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