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