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