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 parentPartition = disk->FindDescendant(parentID); 539 540 if (parentPartition && parentPartition->ContainsPartitioningSystem()) 541 fCreateMI->SetEnabled(true); 542 543 bool prepared = disk->PrepareModifications() == B_OK; 544 fInitMenu->SetEnabled(prepared); 545 fDeleteMI->SetEnabled(prepared); 546 547 BPartition* partition = disk->FindDescendant(selectedPartition); 548 if (partition == NULL) 549 partition = disk; 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->CanInitialize(diskSystem.Name())); 573 item->SetEnabled(partition->CanInitialize(diskSystem.PrettyName())); 574 fInitMenu->AddItem(item); 575 } 576 577 // Mount items 578 if (partition) { 579 BDiskSystem partitionDiskSystem; 580 partition->GetDiskSystem(&partitionDiskSystem); 581 fInitMenu->SetEnabled(!partition->IsMounted() 582 && !partition->IsReadOnly() 583 && partition->Device()->HasMedia() 584 // Check if the current disk system allows initialzation. 585 && partition->CanInitialize(partitionDiskSystem.PrettyName())); 586 587 fDeleteMI->SetEnabled(!partition->IsMounted() 588 && !partition->IsDevice()); 589 590 fMountMI->SetEnabled(!partition->IsMounted()); 591 592 bool unMountable = false; 593 if (partition->IsMounted()) { 594 // see if this partition is the boot volume 595 BVolume volume; 596 BVolume bootVolume; 597 if (BVolumeRoster().GetBootVolume(&bootVolume) == B_OK 598 && partition->GetVolume(&volume) == B_OK) { 599 unMountable = volume != bootVolume; 600 } else 601 unMountable = true; 602 } 603 fUnmountMI->SetEnabled(unMountable); 604 } else { 605 fDeleteMI->SetEnabled(false); 606 fMountMI->SetEnabled(false); 607 } 608 609 if (prepared) 610 disk->CancelModifications(); 611 612 fMountAllMI->SetEnabled(true); 613 } 614 if (selectedPartition < 0) { 615 fDeleteMI->SetEnabled(false); 616 fMountMI->SetEnabled(false); 617 } 618 } 619 620 621 void 622 MainWindow::_DisplayPartitionError(BString _message, 623 const BPartition* partition, status_t error) const 624 { 625 char message[1024]; 626 627 if (partition && _message.FindFirst("%s") >= 0) { 628 BString name; 629 name << "\"" << partition->ContentName() << "\""; 630 snprintf(message, sizeof(message), _message.String(), name.String()); 631 } else { 632 _message.ReplaceAll("%s", ""); 633 snprintf(message, sizeof(message), _message.String()); 634 } 635 636 if (error < B_OK) { 637 BString helper = message; 638 const char* errorString = 639 B_TRANSLATE_COMMENT("Error: ", "in any error alert"); 640 snprintf(message, sizeof(message), "%s\n\n%s%s", helper.String(), 641 errorString, strerror(error)); 642 } 643 644 BAlert* alert = new BAlert("error", message, B_TRANSLATE("OK"), NULL, NULL, 645 B_WIDTH_FROM_WIDEST, error < B_OK ? B_STOP_ALERT : B_INFO_ALERT); 646 alert->Go(NULL); 647 } 648 649 650 // #pragma mark - 651 652 653 void 654 MainWindow::_Mount(BDiskDevice* disk, partition_id selectedPartition) 655 { 656 if (!disk || selectedPartition < 0) { 657 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 658 "entry from the list.")); 659 return; 660 } 661 662 BPartition* partition = disk->FindDescendant(selectedPartition); 663 if (!partition) { 664 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 665 "partition by ID.")); 666 return; 667 } 668 669 if (!partition->IsMounted()) { 670 status_t ret = partition->Mount(); 671 if (ret < B_OK) { 672 _DisplayPartitionError( 673 B_TRANSLATE("Could not mount partition %s."), partition, ret); 674 } else { 675 // successful mount, adapt to the changes 676 _ScanDrives(); 677 } 678 } else { 679 _DisplayPartitionError( 680 B_TRANSLATE("The partition %s is already mounted."), partition); 681 } 682 } 683 684 685 void 686 MainWindow::_Unmount(BDiskDevice* disk, partition_id selectedPartition) 687 { 688 if (!disk || selectedPartition < 0) { 689 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 690 "entry from the list.")); 691 return; 692 } 693 694 BPartition* partition = disk->FindDescendant(selectedPartition); 695 if (!partition) { 696 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 697 "partition by ID.")); 698 return; 699 } 700 701 if (partition->IsMounted()) { 702 BPath path; 703 partition->GetMountPoint(&path); 704 status_t ret = partition->Unmount(); 705 if (ret < B_OK) { 706 _DisplayPartitionError( 707 B_TRANSLATE("Could not unmount partition %s."), 708 partition, ret); 709 } else { 710 if (dev_for_path(path.Path()) == dev_for_path("/")) 711 rmdir(path.Path()); 712 // successful unmount, adapt to the changes 713 _ScanDrives(); 714 } 715 } else { 716 _DisplayPartitionError( 717 B_TRANSLATE("The partition %s is already unmounted."), 718 partition); 719 } 720 } 721 722 723 void 724 MainWindow::_MountAll() 725 { 726 MountAllVisitor visitor; 727 fDDRoster.VisitEachPartition(&visitor); 728 } 729 730 731 // #pragma mark - 732 733 734 class ModificationPreparer { 735 public: 736 ModificationPreparer(BDiskDevice* disk) 737 : 738 fDisk(disk), 739 fModificationStatus(fDisk->PrepareModifications()) 740 { 741 } 742 ~ModificationPreparer() 743 { 744 if (fModificationStatus == B_OK) 745 fDisk->CancelModifications(); 746 } 747 status_t ModificationStatus() const 748 { 749 return fModificationStatus; 750 } 751 status_t CommitModifications() 752 { 753 status_t ret = fDisk->CommitModifications(); 754 if (ret == B_OK) 755 fModificationStatus = B_ERROR; 756 757 return ret; 758 } 759 760 private: 761 BDiskDevice* fDisk; 762 status_t fModificationStatus; 763 }; 764 765 766 void 767 MainWindow::_Initialize(BDiskDevice* disk, partition_id selectedPartition, 768 const BString& diskSystemName) 769 { 770 if (!disk || selectedPartition < 0) { 771 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 772 "entry from the list.")); 773 return; 774 } 775 776 if (disk->IsReadOnly()) { 777 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 778 return; 779 } 780 781 BPartition* partition = disk->FindDescendant(selectedPartition); 782 if (!partition) { 783 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 784 "partition by ID.")); 785 return; 786 } 787 788 if (partition->IsMounted()) { 789 _DisplayPartitionError( 790 B_TRANSLATE("The partition %s is currently mounted.")); 791 // TODO: option to unmount and continue on success to unmount 792 return; 793 } 794 795 char message[512]; 796 if (partition->ContentName() && strlen(partition->ContentName()) > 0) { 797 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you want " 798 "to initialize the partition \"%s\"? You will be asked again " 799 "before changes are written to the disk."), 800 partition->ContentName()); 801 } else { 802 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you want " 803 "to initialize the partition? You will be asked again " 804 "before changes are written to the disk.")); 805 } 806 BAlert* alert = new BAlert("first notice", message, 807 B_TRANSLATE("Continue"), B_TRANSLATE("Cancel"), NULL, 808 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 809 int32 choice = alert->Go(); 810 811 if (choice == 1) 812 return; 813 814 BDiskSystem diskSystem; 815 fDDRoster.RewindDiskSystems(); 816 bool found = false; 817 while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) { 818 if (diskSystem.SupportsInitializing()) { 819 if (diskSystemName == diskSystem.PrettyName()) { 820 found = true; 821 break; 822 } 823 } 824 } 825 826 if (!found) { 827 snprintf(message, sizeof(message), B_TRANSLATE("Disk system \"%s\"\" " 828 "not found!")); 829 _DisplayPartitionError(message); 830 return; 831 } 832 833 ModificationPreparer modificationPreparer(disk); 834 status_t ret = modificationPreparer.ModificationStatus(); 835 if (ret != B_OK) { 836 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 837 "disk for modifications."), NULL, ret); 838 return; 839 } 840 841 BString name; 842 BString parameters; 843 if (diskSystemName == "Be File System") { 844 InitParamsPanel* panel = new InitParamsPanel(this, diskSystemName, 845 partition); 846 if (panel->Go(name, parameters) == GO_CANCELED) 847 return; 848 } else if (diskSystemName == "Intel Partition Map") { 849 // TODO: parameters? 850 } else if (diskSystemName == "Intel Extended Partition") { 851 // TODO: parameters? 852 } 853 854 bool supportsName = diskSystem.SupportsContentName(); 855 BString validatedName(name); 856 ret = partition->ValidateInitialize(diskSystem.PrettyName(), 857 supportsName ? &validatedName : NULL, parameters.String()); 858 if (ret != B_OK) { 859 _DisplayPartitionError(B_TRANSLATE("Validation of the given " 860 "initialization parameters failed."), partition, ret); 861 return; 862 } 863 864 BString previousName = partition->ContentName(); 865 866 ret = partition->Initialize(diskSystem.PrettyName(), 867 supportsName ? validatedName.String() : NULL, parameters.String()); 868 if (ret != B_OK) { 869 _DisplayPartitionError(B_TRANSLATE("Initialization of the partition " 870 "%s failed. (Nothing has been written to disk.)"), partition, ret); 871 return; 872 } 873 874 // everything looks fine, we are ready to actually write the changes 875 // to disk 876 877 // Warn the user one more time... 878 if (previousName.Length() > 0) { 879 if (partition->IsDevice()) { 880 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 881 "want to write the changes back to disk now?\n\n" 882 "All data on the disk %s will be irretrievably lost if you " 883 "do so!"), previousName.String()); 884 } else { 885 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 886 "want to write the changes back to disk now?\n\n" 887 "All data on the partition %s will be irretrievably lost if you " 888 "do so!"), previousName.String()); 889 } 890 } else { 891 if (partition->IsDevice()) { 892 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 893 "want to write the changes back to disk now?\n\n" 894 "All data on the selected disk will be irretrievably lost if " 895 "you do so!")); 896 } else { 897 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 898 "want to write the changes back to disk now?\n\n" 899 "All data on the selected partition will be irretrievably lost " 900 "if you do so!")); 901 } 902 } 903 alert = new BAlert("final notice", message, 904 B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, 905 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 906 choice = alert->Go(); 907 908 if (choice == 1) 909 return; 910 911 // commit 912 ret = modificationPreparer.CommitModifications(); 913 914 // The partition pointer is toast now! Use the partition ID to 915 // retrieve it again. 916 partition = disk->FindDescendant(selectedPartition); 917 918 if (ret == B_OK) { 919 _DisplayPartitionError(B_TRANSLATE("The partition %s has been " 920 "successfully initialized.\n"), partition); 921 } else { 922 _DisplayPartitionError(B_TRANSLATE("Failed to initialize the " 923 "partition %s!\n"), partition, ret); 924 } 925 926 _ScanDrives(); 927 } 928 929 930 void 931 MainWindow::_Create(BDiskDevice* disk, partition_id selectedPartition) 932 { 933 if (!disk || selectedPartition > -2) { 934 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 935 "is not empty.")); 936 return; 937 } 938 939 if (disk->IsReadOnly()) { 940 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 941 return; 942 } 943 944 PartitionListRow* currentSelection = dynamic_cast<PartitionListRow*>( 945 fListView->CurrentSelection()); 946 if (!currentSelection) { 947 _DisplayPartitionError(B_TRANSLATE("There was an error acquiring the " 948 "partition row.")); 949 return; 950 } 951 952 BPartition* parent = disk->FindDescendant(currentSelection->ParentID()); 953 if (!parent) { 954 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 955 "does not have a parent partition.")); 956 return; 957 } 958 959 if (!parent->ContainsPartitioningSystem()) { 960 _DisplayPartitionError(B_TRANSLATE("The selected partition does not " 961 "contain a partitioning system.")); 962 return; 963 } 964 965 ModificationPreparer modificationPreparer(disk); 966 status_t ret = modificationPreparer.ModificationStatus(); 967 if (ret != B_OK) { 968 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 969 "disk for modifications."), NULL, ret); 970 return; 971 } 972 973 // get partitioning info 974 BPartitioningInfo partitioningInfo; 975 status_t error = parent->GetPartitioningInfo(&partitioningInfo); 976 if (error != B_OK) { 977 _DisplayPartitionError(B_TRANSLATE("Could not aquire partitioning " 978 "information.")); 979 return; 980 } 981 982 int32 spacesCount = partitioningInfo.CountPartitionableSpaces(); 983 if (spacesCount == 0) { 984 _DisplayPartitionError(B_TRANSLATE("There's no space on the partition " 985 "where a child partition could be created.")); 986 return; 987 } 988 989 BString name, type, parameters; 990 off_t offset = currentSelection->Offset(); 991 off_t size = currentSelection->Size(); 992 993 CreateParamsPanel* panel = new CreateParamsPanel(this, parent, offset, 994 size); 995 if (panel->Go(offset, size, name, type, parameters) == GO_CANCELED) 996 return; 997 998 ret = parent->ValidateCreateChild(&offset, &size, type.String(), 999 &name, parameters.String()); 1000 1001 if (ret != B_OK) { 1002 _DisplayPartitionError(B_TRANSLATE("Validation of the given creation " 1003 "parameters failed.")); 1004 return; 1005 } 1006 1007 // Warn the user one more time... 1008 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1009 "want to write the changes back to disk now?\n\n" 1010 "All data on the partition will be irretrievably lost if you do " 1011 "so!"), B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, 1012 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1013 int32 choice = alert->Go(); 1014 1015 if (choice == 1) 1016 return; 1017 1018 ret = parent->CreateChild(offset, size, type.String(), 1019 name.String(), parameters.String()); 1020 1021 if (ret != B_OK) { 1022 _DisplayPartitionError(B_TRANSLATE("Creation of the partition has " 1023 "failed.")); 1024 return; 1025 } 1026 1027 // commit 1028 ret = modificationPreparer.CommitModifications(); 1029 1030 if (ret != B_OK) { 1031 _DisplayPartitionError(B_TRANSLATE("Failed to initialize the " 1032 "partition. No changes have been written to disk.")); 1033 return; 1034 } 1035 1036 // The disk layout has changed, update disk information 1037 bool updated; 1038 ret = disk->Update(&updated); 1039 1040 _ScanDrives(); 1041 fDiskView->ForceUpdate(); 1042 } 1043 1044 void 1045 MainWindow::_Delete(BDiskDevice* disk, partition_id selectedPartition) 1046 { 1047 if (!disk || selectedPartition < 0) { 1048 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 1049 "entry from the list.")); 1050 return; 1051 } 1052 1053 if (disk->IsReadOnly()) { 1054 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 1055 return; 1056 } 1057 1058 BPartition* partition = disk->FindDescendant(selectedPartition); 1059 if (!partition) { 1060 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 1061 "partition by ID.")); 1062 return; 1063 } 1064 1065 BPartition* parent = partition->Parent(); 1066 if (!parent) { 1067 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 1068 "does not have a parent partition.")); 1069 return; 1070 } 1071 1072 ModificationPreparer modificationPreparer(disk); 1073 status_t ret = modificationPreparer.ModificationStatus(); 1074 if (ret != B_OK) { 1075 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1076 "disk for modifications."), NULL, ret); 1077 return; 1078 } 1079 1080 if (!parent->CanDeleteChild(partition->Index())) { 1081 _DisplayPartitionError( 1082 B_TRANSLATE("Cannot delete the selected partition.")); 1083 return; 1084 } 1085 1086 // Warn the user one more time... 1087 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1088 "want to delete the selected partition?\n\n" 1089 "All data on the partition will be irretrievably lost if you " 1090 "do so!"), B_TRANSLATE("Delete partition"), B_TRANSLATE("Cancel"), NULL, 1091 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1092 int32 choice = alert->Go(); 1093 1094 if (choice == 1) 1095 return; 1096 1097 ret = parent->DeleteChild(partition->Index()); 1098 if (ret != B_OK) { 1099 _DisplayPartitionError( 1100 B_TRANSLATE("Could not delete the selected partition.")); 1101 return; 1102 } 1103 1104 ret = modificationPreparer.CommitModifications(); 1105 1106 if (ret != B_OK) { 1107 _DisplayPartitionError(B_TRANSLATE("Failed to delete the partition. " 1108 "No changes have been written to disk.")); 1109 return; 1110 } 1111 1112 _ScanDrives(); 1113 fDiskView->ForceUpdate(); 1114 } 1115