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