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