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