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