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