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