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