1 /* 2 * Copyright 2002-2010 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Erik Jaesler <ejakowatz@users.sourceforge.net> 7 * Ithamar R. Adema <ithamar@unet.nl> 8 * Ingo Weinhold <ingo_weinhold@gmx.de> 9 * Stephan Aßmus <superstippi@gmx.de> 10 */ 11 12 #include "MainWindow.h" 13 14 #include <stdio.h> 15 #include <string.h> 16 17 #include <Alert.h> 18 #include <Application.h> 19 #include <Catalog.h> 20 #include <ColumnListView.h> 21 #include <ColumnTypes.h> 22 #include <Debug.h> 23 #include <DiskDevice.h> 24 #include <DiskDeviceVisitor.h> 25 #include <DiskDeviceTypes.h> 26 #include <DiskSystem.h> 27 #include <Locale.h> 28 #include <MenuItem.h> 29 #include <MenuBar.h> 30 #include <Menu.h> 31 #include <Path.h> 32 #include <Partition.h> 33 #include <PartitioningInfo.h> 34 #include <Roster.h> 35 #include <Screen.h> 36 #include <Volume.h> 37 #include <VolumeRoster.h> 38 39 #include "CreateParamsPanel.h" 40 #include "DiskView.h" 41 #include "InitParamsPanel.h" 42 #include "PartitionList.h" 43 #include "Support.h" 44 #include "tracker_private.h" 45 46 47 #undef B_TRANSLATE_CONTEXT 48 #define B_TRANSLATE_CONTEXT "MainWindow" 49 50 51 class ListPopulatorVisitor : public BDiskDeviceVisitor { 52 public: 53 ListPopulatorVisitor(PartitionListView* list, int32& diskCount, 54 SpaceIDMap& spaceIDMap) 55 : 56 fPartitionList(list), 57 fDiskCount(diskCount), 58 fSpaceIDMap(spaceIDMap) 59 { 60 fDiskCount = 0; 61 fSpaceIDMap.Clear(); 62 // start with an empty list 63 int32 rows = fPartitionList->CountRows(); 64 for (int32 i = rows - 1; i >= 0; i--) { 65 BRow* row = fPartitionList->RowAt(i); 66 fPartitionList->RemoveRow(row); 67 delete row; 68 } 69 } 70 71 virtual bool Visit(BDiskDevice* device) 72 { 73 fDiskCount++; 74 // if we don't prepare the device for modifications, 75 // we cannot get information about available empty 76 // regions on the device or child partitions 77 device->PrepareModifications(); 78 _AddPartition(device); 79 return false; // Don't stop yet! 80 } 81 82 virtual bool Visit(BPartition* partition, int32 level) 83 { 84 _AddPartition(partition); 85 return false; // Don't stop yet! 86 } 87 88 private: 89 void _AddPartition(BPartition* partition) const 90 { 91 // add the partition itself 92 fPartitionList->AddPartition(partition); 93 94 // add any available space on it 95 BPartitioningInfo info; 96 status_t ret = partition->GetPartitioningInfo(&info); 97 if (ret >= B_OK) { 98 partition_id parentID = partition->ID(); 99 off_t offset; 100 off_t size; 101 for (int32 i = 0; 102 info.GetPartitionableSpaceAt(i, &offset, &size) >= B_OK; 103 i++) { 104 // TODO: remove again once Disk Device API is fixed 105 if (!is_valid_partitionable_space(size)) 106 continue; 107 // 108 partition_id id = fSpaceIDMap.SpaceIDFor(parentID, offset); 109 fPartitionList->AddSpace(parentID, id, offset, size); 110 } 111 } 112 } 113 114 PartitionListView* fPartitionList; 115 int32& fDiskCount; 116 SpaceIDMap& fSpaceIDMap; 117 BDiskDevice* fLastPreparedDevice; 118 }; 119 120 121 class MountAllVisitor : public BDiskDeviceVisitor { 122 public: 123 MountAllVisitor() 124 { 125 } 126 127 virtual bool Visit(BDiskDevice* device) 128 { 129 return false; // Don't stop yet! 130 } 131 132 virtual bool Visit(BPartition* partition, int32 level) 133 { 134 partition->Mount(); 135 return false; // Don't stop yet! 136 } 137 138 private: 139 PartitionListView* fPartitionList; 140 }; 141 142 143 enum { 144 MSG_MOUNT_ALL = 'mnta', 145 MSG_MOUNT = 'mnts', 146 MSG_UNMOUNT = 'unmt', 147 MSG_FORMAT = 'frmt', 148 MSG_CREATE = 'crtp', 149 MSG_INITIALIZE = 'init', 150 MSG_DELETE = 'delt', 151 MSG_EJECT = 'ejct', 152 MSG_SURFACE_TEST = 'sfct', 153 MSG_RESCAN = 'rscn', 154 155 MSG_PARTITION_ROW_SELECTED = 'prsl', 156 }; 157 158 159 // #pragma mark - 160 161 162 MainWindow::MainWindow(BRect frame) 163 : BWindow(frame, B_TRANSLATE("DriveSetup"), B_DOCUMENT_WINDOW, 164 B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE), 165 fCurrentDisk(NULL), 166 fCurrentPartitionID(-1), 167 fSpaceIDMap() 168 { 169 BMenuBar* menuBar = new BMenuBar(Bounds(), "root menu"); 170 171 // create all the menu items 172 fFormatMI = new BMenuItem(B_TRANSLATE("Format (not implemented)"), 173 new BMessage(MSG_FORMAT)); 174 fEjectMI = new BMenuItem(B_TRANSLATE("Eject"), 175 new BMessage(MSG_EJECT), 'E'); 176 fSurfaceTestMI = new BMenuItem( 177 B_TRANSLATE("Surface test (not implemented)"), 178 new BMessage(MSG_SURFACE_TEST)); 179 fRescanMI = new BMenuItem(B_TRANSLATE("Rescan"), new BMessage(MSG_RESCAN)); 180 181 fCreateMI = new BMenuItem(B_TRANSLATE("Create" B_UTF8_ELLIPSIS), 182 new BMessage(MSG_CREATE), 'C'); 183 fDeleteMI = new BMenuItem(B_TRANSLATE("Delete"), 184 new BMessage(MSG_DELETE), 'D'); 185 186 fMountMI = new BMenuItem(B_TRANSLATE("Mount"), 187 new BMessage(MSG_MOUNT), 'M'); 188 fUnmountMI = new BMenuItem(B_TRANSLATE("Unmount"), 189 new BMessage(MSG_UNMOUNT), 'U'); 190 fMountAllMI = new BMenuItem(B_TRANSLATE("Mount all"), 191 new BMessage(MSG_MOUNT_ALL), 'M', B_SHIFT_KEY); 192 193 // Disk menu 194 fDiskMenu = new BMenu(B_TRANSLATE("Disk")); 195 fDiskMenu->AddItem(fFormatMI); 196 fDiskMenu->AddItem(fEjectMI); 197 fDiskMenu->AddItem(fSurfaceTestMI); 198 199 fDiskMenu->AddSeparatorItem(); 200 201 fDiskMenu->AddItem(fRescanMI); 202 menuBar->AddItem(fDiskMenu); 203 204 // Parition menu 205 fPartitionMenu = new BMenu(B_TRANSLATE("Partition")); 206 fPartitionMenu->AddItem(fCreateMI); 207 208 fInitMenu = new BMenu(B_TRANSLATE("Initialize")); 209 fPartitionMenu->AddItem(fInitMenu); 210 211 fPartitionMenu->AddItem(fDeleteMI); 212 213 fPartitionMenu->AddSeparatorItem(); 214 215 fPartitionMenu->AddItem(fMountMI); 216 fPartitionMenu->AddItem(fUnmountMI); 217 218 fPartitionMenu->AddSeparatorItem(); 219 220 fPartitionMenu->AddItem(fMountAllMI); 221 menuBar->AddItem(fPartitionMenu); 222 223 AddChild(menuBar); 224 225 // add DiskView 226 BRect r(Bounds()); 227 r.top = menuBar->Frame().bottom + 1; 228 r.bottom = floorf(r.top + r.Height() * 0.33); 229 fDiskView = new DiskView(r, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 230 fSpaceIDMap); 231 AddChild(fDiskView); 232 233 // add PartitionListView 234 r.top = r.bottom + 2; 235 r.bottom = Bounds().bottom; 236 r.InsetBy(-1, -1); 237 fListView = new PartitionListView(r, B_FOLLOW_ALL); 238 AddChild(fListView); 239 240 // configure PartitionListView 241 fListView->SetSelectionMode(B_SINGLE_SELECTION_LIST); 242 fListView->SetSelectionMessage(new BMessage(MSG_PARTITION_ROW_SELECTED)); 243 fListView->SetTarget(this); 244 fListView->MakeFocus(true); 245 246 status_t ret = fDDRoster.StartWatching(BMessenger(this)); 247 if (ret != B_OK) { 248 fprintf(stderr, "Failed to start watching for device changes: %s\n", 249 strerror(ret)); 250 } 251 252 // visit all disks in the system and show their contents 253 _ScanDrives(); 254 255 if (!be_roster->IsRunning(kDeskbarSignature)) 256 SetFlags(Flags() | B_NOT_MINIMIZABLE); 257 } 258 259 260 MainWindow::~MainWindow() 261 { 262 BDiskDeviceRoster().StopWatching(this); 263 delete fCurrentDisk; 264 } 265 266 267 void 268 MainWindow::MessageReceived(BMessage* message) 269 { 270 switch (message->what) { 271 case MSG_MOUNT_ALL: 272 _MountAll(); 273 break; 274 case MSG_MOUNT: 275 _Mount(fCurrentDisk, fCurrentPartitionID); 276 break; 277 case MSG_UNMOUNT: 278 _Unmount(fCurrentDisk, fCurrentPartitionID); 279 break; 280 281 case MSG_FORMAT: 282 printf("MSG_FORMAT\n"); 283 break; 284 285 case MSG_CREATE: { 286 _Create(fCurrentDisk, fCurrentPartitionID); 287 break; 288 } 289 290 case MSG_INITIALIZE: { 291 BString diskSystemName; 292 if (message->FindString("disk system", &diskSystemName) != B_OK) 293 break; 294 _Initialize(fCurrentDisk, fCurrentPartitionID, diskSystemName); 295 break; 296 } 297 298 case MSG_DELETE: 299 _Delete(fCurrentDisk, fCurrentPartitionID); 300 break; 301 302 case MSG_EJECT: 303 // TODO: completely untested, especially interesting 304 // if partition list behaves when partitions disappear 305 if (fCurrentDisk) { 306 // TODO: only if no partitions are mounted anymore? 307 fCurrentDisk->Eject(true); 308 _ScanDrives(); 309 } 310 break; 311 case MSG_SURFACE_TEST: 312 printf("MSG_SURFACE_TEST\n"); 313 break; 314 315 // TODO: this could probably be done better! 316 case B_DEVICE_UPDATE: 317 printf("B_DEVICE_UPDATE\n"); 318 case MSG_RESCAN: 319 _ScanDrives(); 320 break; 321 322 case MSG_PARTITION_ROW_SELECTED: 323 // selection of partitions via list view 324 _AdaptToSelectedPartition(); 325 break; 326 case MSG_SELECTED_PARTITION_ID: { 327 // selection of partitions via disk view 328 partition_id id; 329 if (message->FindInt32("partition_id", &id) == B_OK) { 330 if (BRow* row = fListView->FindRow(id)) { 331 fListView->DeselectAll(); 332 fListView->AddToSelection(row); 333 _AdaptToSelectedPartition(); 334 } 335 } 336 break; 337 } 338 339 default: 340 BWindow::MessageReceived(message); 341 break; 342 } 343 } 344 345 346 bool 347 MainWindow::QuitRequested() 348 { 349 // TODO: ask about any unsaved changes 350 be_app->PostMessage(B_QUIT_REQUESTED); 351 Hide(); 352 return false; 353 } 354 355 356 // #pragma mark - 357 358 359 status_t 360 MainWindow::StoreSettings(BMessage* archive) const 361 { 362 if (archive->ReplaceRect("window frame", Frame()) < B_OK) 363 archive->AddRect("window frame", Frame()); 364 365 BMessage columnSettings; 366 fListView->SaveState(&columnSettings); 367 if (archive->ReplaceMessage("column settings", &columnSettings) < B_OK) 368 archive->AddMessage("column settings", &columnSettings); 369 370 return B_OK; 371 } 372 373 374 status_t 375 MainWindow::RestoreSettings(BMessage* archive) 376 { 377 BRect frame; 378 if (archive->FindRect("window frame", &frame) == B_OK) { 379 BScreen screen(this); 380 if (frame.Intersects(screen.Frame())) { 381 MoveTo(frame.LeftTop()); 382 ResizeTo(frame.Width(), frame.Height()); 383 } 384 } 385 386 BMessage columnSettings; 387 if (archive->FindMessage("column settings", &columnSettings) == B_OK) 388 fListView->LoadState(&columnSettings); 389 390 return B_OK; 391 } 392 393 394 void 395 MainWindow::ApplyDefaultSettings() 396 { 397 if (!Lock()) 398 return; 399 400 fListView->ResizeAllColumnsToPreferred(); 401 402 // Adjust window size for convenience 403 float enlargeBy = fListView->PreferredSize().width 404 - fListView->Bounds().Width(); 405 if (enlargeBy > 0.0f) { 406 BScreen screen(this); 407 float windowWidth = Frame().Width() + enlargeBy; 408 if (windowWidth > screen.Frame().Width() - 20.0f) 409 windowWidth = screen.Frame().Width() - 20.0f; 410 411 ResizeTo(windowWidth, Frame().Height()); 412 } 413 414 CenterOnScreen(); 415 416 Unlock(); 417 } 418 419 420 // #pragma mark - 421 422 423 void 424 MainWindow::_ScanDrives() 425 { 426 fSpaceIDMap.Clear(); 427 int32 diskCount = 0; 428 ListPopulatorVisitor driveVisitor(fListView, diskCount, fSpaceIDMap); 429 fDDRoster.VisitEachPartition(&driveVisitor); 430 fDiskView->SetDiskCount(diskCount); 431 432 // restore selection 433 PartitionListRow* previousSelection 434 = fListView->FindRow(fCurrentPartitionID); 435 if (previousSelection) { 436 fListView->AddToSelection(previousSelection); 437 _UpdateMenus(fCurrentDisk, fCurrentPartitionID, 438 previousSelection->ParentID()); 439 fDiskView->ForceUpdate(); 440 } else { 441 _UpdateMenus(NULL, -1, -1); 442 } 443 } 444 445 446 // #pragma mark - 447 448 449 void 450 MainWindow::_AdaptToSelectedPartition() 451 { 452 partition_id diskID = -1; 453 partition_id partitionID = -1; 454 partition_id parentID = -1; 455 456 BRow* _selectedRow = fListView->CurrentSelection(); 457 if (_selectedRow) { 458 // go up to top level row 459 BRow* _topLevelRow = _selectedRow; 460 BRow* parent = NULL; 461 while (fListView->FindParent(_topLevelRow, &parent, NULL)) 462 _topLevelRow = parent; 463 464 PartitionListRow* topLevelRow 465 = dynamic_cast<PartitionListRow*>(_topLevelRow); 466 PartitionListRow* selectedRow 467 = dynamic_cast<PartitionListRow*>(_selectedRow); 468 469 if (topLevelRow) 470 diskID = topLevelRow->ID(); 471 if (selectedRow) { 472 partitionID = selectedRow->ID(); 473 parentID = selectedRow->ParentID(); 474 } 475 } 476 477 _SetToDiskAndPartition(diskID, partitionID, parentID); 478 } 479 480 481 void 482 MainWindow::_SetToDiskAndPartition(partition_id disk, partition_id partition, 483 partition_id parent) 484 { 485 //printf("MainWindow::_SetToDiskAndPartition(disk: %ld, partition: %ld, " 486 // "parent: %ld)\n", disk, partition, parent); 487 488 BDiskDevice* oldDisk = NULL; 489 if (!fCurrentDisk || fCurrentDisk->ID() != disk) { 490 oldDisk = fCurrentDisk; 491 fCurrentDisk = NULL; 492 if (disk >= 0) { 493 BDiskDevice* newDisk = new BDiskDevice(); 494 status_t ret = newDisk->SetTo(disk); 495 if (ret < B_OK) { 496 printf("error switching disks: %s\n", strerror(ret)); 497 delete newDisk; 498 } else 499 fCurrentDisk = newDisk; 500 } 501 } 502 503 fCurrentPartitionID = partition; 504 505 fDiskView->SetDisk(fCurrentDisk, fCurrentPartitionID); 506 _UpdateMenus(fCurrentDisk, fCurrentPartitionID, parent); 507 508 delete oldDisk; 509 } 510 511 512 void 513 MainWindow::_UpdateMenus(BDiskDevice* disk, 514 partition_id selectedPartition, partition_id parentID) 515 { 516 while (BMenuItem* item = fInitMenu->RemoveItem(0L)) 517 delete item; 518 519 fCreateMI->SetEnabled(false); 520 fUnmountMI->SetEnabled(false); 521 fInitMenu->SetEnabled(false); 522 523 if (!disk) { 524 fFormatMI->SetEnabled(false); 525 fEjectMI->SetEnabled(false); 526 fSurfaceTestMI->SetEnabled(false); 527 } else { 528 // fFormatMI->SetEnabled(true); 529 fFormatMI->SetEnabled(false); 530 fEjectMI->SetEnabled(disk->IsRemovableMedia()); 531 // fSurfaceTestMI->SetEnabled(true); 532 fSurfaceTestMI->SetEnabled(false); 533 534 // Create menu and items 535 BPartition* parentPartition = NULL; 536 if (selectedPartition <= -2) 537 parentPartition = disk->FindDescendant(parentID); 538 539 if (parentPartition && parentPartition->ContainsPartitioningSystem()) 540 fCreateMI->SetEnabled(true); 541 542 bool prepared = disk->PrepareModifications() == B_OK; 543 fInitMenu->SetEnabled(prepared); 544 fDeleteMI->SetEnabled(prepared); 545 546 BPartition* partition = disk->FindDescendant(selectedPartition); 547 if (partition == NULL) 548 partition = disk; 549 550 BDiskSystem diskSystem; 551 fDDRoster.RewindDiskSystems(); 552 while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) { 553 if (!diskSystem.SupportsInitializing()) 554 continue; 555 556 if (disk->ID() != selectedPartition 557 && disk->ContainsPartitioningSystem() 558 && !diskSystem.IsFileSystem()) { 559 // Do not confuse the user with nested partition maps? 560 continue; 561 } 562 BMessage* message = new BMessage(MSG_INITIALIZE); 563 message->AddInt32("parent id", parentID); 564 message->AddString("disk system", diskSystem.PrettyName()); 565 566 BString label = diskSystem.PrettyName(); 567 label << B_UTF8_ELLIPSIS; 568 BMenuItem* item = new BMenuItem(label.String(), message); 569 570 // TODO: Very unintuitive that we have to use the pretty name here! 571 // item->SetEnabled(partition->CanInitialize(diskSystem.Name())); 572 item->SetEnabled(partition->CanInitialize(diskSystem.PrettyName())); 573 fInitMenu->AddItem(item); 574 } 575 576 // Mount items 577 if (partition) { 578 BDiskSystem partitionDiskSystem; 579 partition->GetDiskSystem(&partitionDiskSystem); 580 fInitMenu->SetEnabled(!partition->IsMounted() 581 && !partition->IsReadOnly() 582 && partition->Device()->HasMedia() 583 // Check if the current disk system allows initialzation. 584 && partition->CanInitialize(partitionDiskSystem.PrettyName())); 585 586 fDeleteMI->SetEnabled(!partition->IsMounted() 587 && !partition->IsDevice()); 588 589 fMountMI->SetEnabled(!partition->IsMounted()); 590 591 bool unMountable = false; 592 if (partition->IsMounted()) { 593 // see if this partition is the boot volume 594 BVolume volume; 595 BVolume bootVolume; 596 if (BVolumeRoster().GetBootVolume(&bootVolume) == B_OK 597 && partition->GetVolume(&volume) == B_OK) { 598 unMountable = volume != bootVolume; 599 } else 600 unMountable = true; 601 } 602 fUnmountMI->SetEnabled(unMountable); 603 } else { 604 fDeleteMI->SetEnabled(false); 605 fMountMI->SetEnabled(false); 606 } 607 608 if (prepared) 609 disk->CancelModifications(); 610 611 fMountAllMI->SetEnabled(true); 612 } 613 if (selectedPartition < 0) { 614 fDeleteMI->SetEnabled(false); 615 fMountMI->SetEnabled(false); 616 } 617 } 618 619 620 void 621 MainWindow::_DisplayPartitionError(BString _message, 622 const BPartition* partition, status_t error) const 623 { 624 char message[1024]; 625 626 if (partition && _message.FindFirst("%s") >= 0) { 627 BString name; 628 name << "\"" << partition->ContentName() << "\""; 629 snprintf(message, sizeof(message), _message.String(), name.String()); 630 } else { 631 _message.ReplaceAll("%s", ""); 632 snprintf(message, sizeof(message), _message.String()); 633 } 634 635 if (error < B_OK) { 636 BString helper = message; 637 const char* errorString = 638 B_TRANSLATE_COMMENT("Error: ", "in any error alert"); 639 snprintf(message, sizeof(message), "%s\n\n%s%s", helper.String(), 640 errorString, strerror(error)); 641 } 642 643 BAlert* alert = new BAlert("error", message, B_TRANSLATE("OK"), NULL, NULL, 644 B_WIDTH_FROM_WIDEST, error < B_OK ? B_STOP_ALERT : B_INFO_ALERT); 645 alert->Go(NULL); 646 } 647 648 649 // #pragma mark - 650 651 652 void 653 MainWindow::_Mount(BDiskDevice* disk, partition_id selectedPartition) 654 { 655 if (!disk || selectedPartition < 0) { 656 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 657 "entry from the list.")); 658 return; 659 } 660 661 BPartition* partition = disk->FindDescendant(selectedPartition); 662 if (!partition) { 663 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 664 "partition by ID.")); 665 return; 666 } 667 668 if (!partition->IsMounted()) { 669 status_t ret = partition->Mount(); 670 if (ret < B_OK) { 671 _DisplayPartitionError( 672 B_TRANSLATE("Could not mount partition %s."), partition, ret); 673 } else { 674 // successful mount, adapt to the changes 675 _ScanDrives(); 676 } 677 } else { 678 _DisplayPartitionError( 679 B_TRANSLATE("The partition %s is already mounted."), partition); 680 } 681 } 682 683 684 void 685 MainWindow::_Unmount(BDiskDevice* disk, partition_id selectedPartition) 686 { 687 if (!disk || selectedPartition < 0) { 688 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 689 "entry from the list.")); 690 return; 691 } 692 693 BPartition* partition = disk->FindDescendant(selectedPartition); 694 if (!partition) { 695 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 696 "partition by ID.")); 697 return; 698 } 699 700 if (partition->IsMounted()) { 701 BPath path; 702 partition->GetMountPoint(&path); 703 status_t ret = partition->Unmount(); 704 if (ret < B_OK) { 705 _DisplayPartitionError( 706 B_TRANSLATE("Could not unmount partition %s."), 707 partition, ret); 708 } else { 709 if (dev_for_path(path.Path()) == dev_for_path("/")) 710 rmdir(path.Path()); 711 // successful unmount, adapt to the changes 712 _ScanDrives(); 713 } 714 } else { 715 _DisplayPartitionError( 716 B_TRANSLATE("The partition %s is already unmounted."), 717 partition); 718 } 719 } 720 721 722 void 723 MainWindow::_MountAll() 724 { 725 MountAllVisitor visitor; 726 fDDRoster.VisitEachPartition(&visitor); 727 } 728 729 730 // #pragma mark - 731 732 733 class ModificationPreparer { 734 public: 735 ModificationPreparer(BDiskDevice* disk) 736 : 737 fDisk(disk), 738 fModificationStatus(fDisk->PrepareModifications()) 739 { 740 } 741 ~ModificationPreparer() 742 { 743 if (fModificationStatus == B_OK) 744 fDisk->CancelModifications(); 745 } 746 status_t ModificationStatus() const 747 { 748 return fModificationStatus; 749 } 750 status_t CommitModifications() 751 { 752 status_t ret = fDisk->CommitModifications(); 753 if (ret == B_OK) 754 fModificationStatus = B_ERROR; 755 756 return ret; 757 } 758 759 private: 760 BDiskDevice* fDisk; 761 status_t fModificationStatus; 762 }; 763 764 765 void 766 MainWindow::_Initialize(BDiskDevice* disk, partition_id selectedPartition, 767 const BString& diskSystemName) 768 { 769 if (!disk || selectedPartition < 0) { 770 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 771 "entry from the list.")); 772 return; 773 } 774 775 if (disk->IsReadOnly()) { 776 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 777 return; 778 } 779 780 BPartition* partition = disk->FindDescendant(selectedPartition); 781 if (!partition) { 782 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 783 "partition by ID.")); 784 return; 785 } 786 787 if (partition->IsMounted()) { 788 _DisplayPartitionError( 789 B_TRANSLATE("The partition %s is currently mounted.")); 790 // TODO: option to unmount and continue on success to unmount 791 return; 792 } 793 794 char message[512]; 795 if (partition->ContentName() && strlen(partition->ContentName()) > 0) { 796 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you want " 797 "to initialize the partition \"%s\"? You will be asked again " 798 "before changes are written to the disk."), 799 partition->ContentName()); 800 } else { 801 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you want " 802 "to initialize the partition? You will be asked again " 803 "before changes are written to the disk.")); 804 } 805 BAlert* alert = new BAlert("first notice", message, 806 B_TRANSLATE("Continue"), B_TRANSLATE("Cancel"), NULL, 807 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 808 int32 choice = alert->Go(); 809 810 if (choice == 1) 811 return; 812 813 BDiskSystem diskSystem; 814 fDDRoster.RewindDiskSystems(); 815 bool found = false; 816 while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) { 817 if (diskSystem.SupportsInitializing()) { 818 if (diskSystemName == diskSystem.PrettyName()) { 819 found = true; 820 break; 821 } 822 } 823 } 824 825 if (!found) { 826 snprintf(message, sizeof(message), B_TRANSLATE("Disk system \"%s\"\" " 827 "not found!")); 828 _DisplayPartitionError(message); 829 return; 830 } 831 832 ModificationPreparer modificationPreparer(disk); 833 status_t ret = modificationPreparer.ModificationStatus(); 834 if (ret != B_OK) { 835 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 836 "disk for modifications."), NULL, ret); 837 return; 838 } 839 840 BString name; 841 BString parameters; 842 if (diskSystemName == "Be File System") { 843 InitParamsPanel* panel = new InitParamsPanel(this, diskSystemName, 844 partition); 845 if (panel->Go(name, parameters) == GO_CANCELED) 846 return; 847 } else if (diskSystemName == "Intel Partition Map") { 848 // TODO: parameters? 849 } else if (diskSystemName == "Intel Extended Partition") { 850 // TODO: parameters? 851 } 852 853 bool supportsName = diskSystem.SupportsContentName(); 854 BString validatedName(name); 855 ret = partition->ValidateInitialize(diskSystem.PrettyName(), 856 supportsName ? &validatedName : NULL, parameters.String()); 857 if (ret != B_OK) { 858 _DisplayPartitionError(B_TRANSLATE("Validation of the given " 859 "initialization parameters failed."), partition, ret); 860 return; 861 } 862 863 BString previousName = partition->ContentName(); 864 865 ret = partition->Initialize(diskSystem.PrettyName(), 866 supportsName ? validatedName.String() : NULL, parameters.String()); 867 if (ret != B_OK) { 868 _DisplayPartitionError(B_TRANSLATE("Initialization of the partition " 869 "%s failed. (Nothing has been written to disk.)"), partition, ret); 870 return; 871 } 872 873 // everything looks fine, we are ready to actually write the changes 874 // to disk 875 876 // Warn the user one more time... 877 if (previousName.Length() > 0) { 878 if (partition->IsDevice()) { 879 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 880 "want to write the changes back to disk now?\n\n" 881 "All data on the disk %s will be irretrievably lost if you " 882 "do so!"), previousName.String()); 883 } else { 884 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 885 "want to write the changes back to disk now?\n\n" 886 "All data on the partition %s will be irretrievably lost if you " 887 "do so!"), previousName.String()); 888 } 889 } else { 890 if (partition->IsDevice()) { 891 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 892 "want to write the changes back to disk now?\n\n" 893 "All data on the selected disk will be irretrievably lost if " 894 "you do so!")); 895 } else { 896 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 897 "want to write the changes back to disk now?\n\n" 898 "All data on the selected partition will be irretrievably lost " 899 "if you do so!")); 900 } 901 } 902 alert = new BAlert("final notice", message, 903 B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, 904 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 905 choice = alert->Go(); 906 907 if (choice == 1) 908 return; 909 910 // commit 911 ret = modificationPreparer.CommitModifications(); 912 913 // The partition pointer is toast now! Use the partition ID to 914 // retrieve it again. 915 partition = disk->FindDescendant(selectedPartition); 916 917 if (ret == B_OK) { 918 _DisplayPartitionError(B_TRANSLATE("The partition %s has been " 919 "successfully initialized.\n"), partition); 920 } else { 921 _DisplayPartitionError(B_TRANSLATE("Failed to initialize the " 922 "partition %s!\n"), partition, ret); 923 } 924 925 _ScanDrives(); 926 } 927 928 929 void 930 MainWindow::_Create(BDiskDevice* disk, partition_id selectedPartition) 931 { 932 if (!disk || selectedPartition > -2) { 933 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 934 "is not empty.")); 935 return; 936 } 937 938 if (disk->IsReadOnly()) { 939 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 940 return; 941 } 942 943 PartitionListRow* currentSelection = dynamic_cast<PartitionListRow*>( 944 fListView->CurrentSelection()); 945 if (!currentSelection) { 946 _DisplayPartitionError(B_TRANSLATE("There was an error acquiring the " 947 "partition row.")); 948 return; 949 } 950 951 BPartition* parent = disk->FindDescendant(currentSelection->ParentID()); 952 if (!parent) { 953 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 954 "does not have a parent partition.")); 955 return; 956 } 957 958 if (!parent->ContainsPartitioningSystem()) { 959 _DisplayPartitionError(B_TRANSLATE("The selected partition does not " 960 "contain a partitioning system.")); 961 return; 962 } 963 964 ModificationPreparer modificationPreparer(disk); 965 status_t ret = modificationPreparer.ModificationStatus(); 966 if (ret != B_OK) { 967 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 968 "disk for modifications."), NULL, ret); 969 return; 970 } 971 972 // get partitioning info 973 BPartitioningInfo partitioningInfo; 974 status_t error = parent->GetPartitioningInfo(&partitioningInfo); 975 if (error != B_OK) { 976 _DisplayPartitionError(B_TRANSLATE("Could not aquire partitioning " 977 "information.")); 978 return; 979 } 980 981 int32 spacesCount = partitioningInfo.CountPartitionableSpaces(); 982 if (spacesCount == 0) { 983 _DisplayPartitionError(B_TRANSLATE("There's no space on the partition " 984 "where a child partition could be created.")); 985 return; 986 } 987 988 BString name, type, parameters; 989 off_t offset = currentSelection->Offset(); 990 off_t size = currentSelection->Size(); 991 992 CreateParamsPanel* panel = new CreateParamsPanel(this, parent, offset, 993 size); 994 if (panel->Go(offset, size, name, type, parameters) == GO_CANCELED) 995 return; 996 997 ret = parent->ValidateCreateChild(&offset, &size, type.String(), 998 &name, parameters.String()); 999 1000 if (ret != B_OK) { 1001 _DisplayPartitionError(B_TRANSLATE("Validation of the given creation " 1002 "parameters failed.")); 1003 return; 1004 } 1005 1006 // Warn the user one more time... 1007 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1008 "want to write the changes back to disk now?\n\n" 1009 "All data on the partition will be irretrievably lost if you do " 1010 "so!"), B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, 1011 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1012 int32 choice = alert->Go(); 1013 1014 if (choice == 1) 1015 return; 1016 1017 ret = parent->CreateChild(offset, size, type.String(), 1018 name.String(), parameters.String()); 1019 1020 if (ret != B_OK) { 1021 _DisplayPartitionError(B_TRANSLATE("Creation of the partition has " 1022 "failed.")); 1023 return; 1024 } 1025 1026 // commit 1027 ret = modificationPreparer.CommitModifications(); 1028 1029 if (ret != B_OK) { 1030 _DisplayPartitionError(B_TRANSLATE("Failed to initialize the " 1031 "partition. No changes have been written to disk.")); 1032 return; 1033 } 1034 1035 // The disk layout has changed, update disk information 1036 bool updated; 1037 ret = disk->Update(&updated); 1038 1039 _ScanDrives(); 1040 fDiskView->ForceUpdate(); 1041 } 1042 1043 void 1044 MainWindow::_Delete(BDiskDevice* disk, partition_id selectedPartition) 1045 { 1046 if (!disk || selectedPartition < 0) { 1047 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 1048 "entry from the list.")); 1049 return; 1050 } 1051 1052 if (disk->IsReadOnly()) { 1053 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 1054 return; 1055 } 1056 1057 BPartition* partition = disk->FindDescendant(selectedPartition); 1058 if (!partition) { 1059 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 1060 "partition by ID.")); 1061 return; 1062 } 1063 1064 BPartition* parent = partition->Parent(); 1065 if (!parent) { 1066 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 1067 "does not have a parent partition.")); 1068 return; 1069 } 1070 1071 ModificationPreparer modificationPreparer(disk); 1072 status_t ret = modificationPreparer.ModificationStatus(); 1073 if (ret != B_OK) { 1074 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1075 "disk for modifications."), NULL, ret); 1076 return; 1077 } 1078 1079 if (!parent->CanDeleteChild(partition->Index())) { 1080 _DisplayPartitionError( 1081 B_TRANSLATE("Cannot delete the selected partition.")); 1082 return; 1083 } 1084 1085 // Warn the user one more time... 1086 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1087 "want to delete the selected partition?\n\n" 1088 "All data on the partition will be irretrievably lost if you " 1089 "do so!"), B_TRANSLATE("Delete partition"), B_TRANSLATE("Cancel"), NULL, 1090 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1091 int32 choice = alert->Go(); 1092 1093 if (choice == 1) 1094 return; 1095 1096 ret = parent->DeleteChild(partition->Index()); 1097 if (ret != B_OK) { 1098 _DisplayPartitionError( 1099 B_TRANSLATE("Could not delete the selected partition.")); 1100 return; 1101 } 1102 1103 ret = modificationPreparer.CommitModifications(); 1104 1105 if (ret != B_OK) { 1106 _DisplayPartitionError(B_TRANSLATE("Failed to delete the partition. " 1107 "No changes have been written to disk.")); 1108 return; 1109 } 1110 1111 _ScanDrives(); 1112 fDiskView->ForceUpdate(); 1113 } 1114