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