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 BString intelExtendedPartition = "Intel Extended Partition"; 971 if (disk->ID() == selectedPartition) { 972 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 973 "want to format a raw disk? (Most people initialize the disk " 974 "with a partitioning system first) You will be asked " 975 "again before changes are written to the disk.")); 976 } else if (partition->ContentName() 977 && strlen(partition->ContentName()) > 0) { 978 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 979 "want to format the partition \"%s\"? You will be asked " 980 "again before changes are written to the disk."), 981 partition->ContentName()); 982 } else if (partition->Type() == intelExtendedPartition) { 983 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 984 "want to format the Intel Extended Partition? Any " 985 "subpartitions it contains will be overwritten if you " 986 "continue. You will be asked again before changes are " 987 "written to the disk.")); 988 } else { 989 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 990 "want to format the partition? You will be asked again " 991 "before changes are written to the disk.")); 992 } 993 } else { 994 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 995 "want to initialize the selected disk? All data will be lost. " 996 "You will be asked again before changes are written to the " 997 "disk.\n")); 998 } 999 BAlert* alert = new BAlert("first notice", message, 1000 B_TRANSLATE("Continue"), B_TRANSLATE("Cancel"), NULL, 1001 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1002 alert->SetShortcut(1, B_ESCAPE); 1003 int32 choice = alert->Go(); 1004 1005 if (choice == 1) 1006 return; 1007 1008 ModificationPreparer modificationPreparer(disk); 1009 status_t status = modificationPreparer.ModificationStatus(); 1010 if (status != B_OK) { 1011 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1012 "disk for modifications."), NULL, status); 1013 return; 1014 } 1015 1016 BString name; 1017 BString parameters; 1018 InitParametersPanel* panel = new InitParametersPanel(this, diskSystemName, 1019 partition); 1020 if (panel->Go(name, parameters) != B_OK) 1021 return; 1022 1023 bool supportsName = diskSystem.SupportsContentName(); 1024 BString validatedName(name); 1025 status = partition->ValidateInitialize(diskSystem.PrettyName(), 1026 supportsName ? &validatedName : NULL, parameters.String()); 1027 if (status != B_OK) { 1028 _DisplayPartitionError(B_TRANSLATE("Validation of the given " 1029 "initialization parameters failed."), partition, status); 1030 return; 1031 } 1032 1033 BString previousName = partition->ContentName(); 1034 1035 status = partition->Initialize(diskSystem.PrettyName(), 1036 supportsName ? validatedName.String() : NULL, parameters.String()); 1037 if (status != B_OK) { 1038 _DisplayPartitionError(B_TRANSLATE("Initialization of the partition " 1039 "%s failed. (Nothing has been written to disk.)"), partition, 1040 status); 1041 return; 1042 } 1043 1044 // Also set the partition name in the partition table if supported 1045 if (partition->CanSetName() 1046 && partition->ValidateSetName(&validatedName) == B_OK) { 1047 partition->SetName(validatedName.String()); 1048 } 1049 1050 // everything looks fine, we are ready to actually write the changes 1051 // to disk 1052 1053 // Warn the user one more time... 1054 if (previousName.Length() > 0) { 1055 if (partition->IsDevice()) { 1056 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 1057 "want to write the changes back to disk now?\n\n" 1058 "All data on the disk %s will be irretrievably lost if you " 1059 "do so!"), previousName.String()); 1060 } else { 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 partition %s will be irretrievably lost if you " 1064 "do so!"), previousName.String()); 1065 } 1066 } else { 1067 if (partition->IsDevice()) { 1068 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 1069 "want to write the changes back to disk now?\n\n" 1070 "All data on the selected disk will be irretrievably lost if " 1071 "you do so!")); 1072 } else { 1073 snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " 1074 "want to write the changes back to disk now?\n\n" 1075 "All data on the selected partition will be irretrievably lost " 1076 "if you do so!")); 1077 } 1078 } 1079 alert = new BAlert("final notice", message, 1080 B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, 1081 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1082 alert->SetShortcut(1, B_ESCAPE); 1083 choice = alert->Go(); 1084 1085 if (choice == 1) 1086 return; 1087 1088 // commit 1089 status = modificationPreparer.CommitModifications(); 1090 1091 // The partition pointer is toast now! Use the partition ID to 1092 // retrieve it again. 1093 partition = disk->FindDescendant(selectedPartition); 1094 1095 if (status == B_OK) { 1096 if (diskSystem.IsFileSystem()) { 1097 _DisplayPartitionError(B_TRANSLATE("The partition %s has been " 1098 "successfully formatted.\n"), partition); 1099 } else { 1100 _DisplayPartitionError(B_TRANSLATE("The disk has been " 1101 "successfully initialized.\n"), partition); 1102 } 1103 } else { 1104 if (diskSystem.IsFileSystem()) { 1105 _DisplayPartitionError(B_TRANSLATE("Failed to format the " 1106 "partition %s!\n"), partition, status); 1107 } else { 1108 _DisplayPartitionError(B_TRANSLATE("Failed to initialize the " 1109 "disk %s!\n"), partition, status); 1110 } 1111 } 1112 1113 _ScanDrives(); 1114 } 1115 1116 1117 void 1118 MainWindow::_Create(BDiskDevice* disk, partition_id selectedPartition) 1119 { 1120 if (!disk || selectedPartition > -2) { 1121 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 1122 "is not empty.")); 1123 return; 1124 } 1125 1126 if (disk->IsReadOnly()) { 1127 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 1128 return; 1129 } 1130 1131 PartitionListRow* currentSelection = dynamic_cast<PartitionListRow*>( 1132 fListView->CurrentSelection()); 1133 if (!currentSelection) { 1134 _DisplayPartitionError(B_TRANSLATE("There was an error acquiring the " 1135 "partition row.")); 1136 return; 1137 } 1138 1139 BPartition* parent = disk->FindDescendant(currentSelection->ParentID()); 1140 if (!parent) { 1141 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 1142 "does not have a parent partition.")); 1143 return; 1144 } 1145 1146 if (!parent->ContainsPartitioningSystem()) { 1147 _DisplayPartitionError(B_TRANSLATE("The selected partition does not " 1148 "contain a partitioning system.")); 1149 return; 1150 } 1151 1152 ModificationPreparer modificationPreparer(disk); 1153 status_t status = modificationPreparer.ModificationStatus(); 1154 if (status != B_OK) { 1155 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1156 "disk for modifications."), NULL, status); 1157 return; 1158 } 1159 1160 // get partitioning info 1161 BPartitioningInfo partitioningInfo; 1162 status_t error = parent->GetPartitioningInfo(&partitioningInfo); 1163 if (error != B_OK) { 1164 _DisplayPartitionError(B_TRANSLATE("Could not acquire partitioning " 1165 "information.")); 1166 return; 1167 } 1168 1169 int32 spacesCount = partitioningInfo.CountPartitionableSpaces(); 1170 if (spacesCount == 0) { 1171 _DisplayPartitionError(B_TRANSLATE("There's no space on the partition " 1172 "where a child partition could be created.")); 1173 return; 1174 } 1175 1176 BString name, type, parameters; 1177 off_t offset = currentSelection->Offset(); 1178 off_t size = currentSelection->Size(); 1179 1180 CreateParametersPanel* panel = new CreateParametersPanel(this, parent, 1181 offset, size); 1182 status = panel->Go(offset, size, name, type, parameters); 1183 if (status != B_OK) { 1184 if (status != B_CANCELED) { 1185 _DisplayPartitionError(B_TRANSLATE("The panel could not return " 1186 "successfully."), NULL, status); 1187 } 1188 return; 1189 } 1190 1191 status = parent->ValidateCreateChild(&offset, &size, type.String(), 1192 &name, parameters.String()); 1193 1194 if (status != B_OK) { 1195 _DisplayPartitionError(B_TRANSLATE("Validation of the given creation " 1196 "parameters failed."), NULL, status); 1197 return; 1198 } 1199 1200 // Warn the user one more time... 1201 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1202 "want to write the changes back to disk now?\n\n" 1203 "All data on the partition will be irretrievably lost if you do " 1204 "so!"), B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, 1205 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1206 alert->SetShortcut(1, B_ESCAPE); 1207 int32 choice = alert->Go(); 1208 1209 if (choice == 1) 1210 return; 1211 1212 status = parent->CreateChild(offset, size, type.String(), name.String(), 1213 parameters.String()); 1214 1215 if (status != B_OK) { 1216 _DisplayPartitionError(B_TRANSLATE("Creation of the partition has " 1217 "failed."), NULL, status); 1218 return; 1219 } 1220 1221 // commit 1222 status = modificationPreparer.CommitModifications(); 1223 1224 if (status != B_OK) { 1225 _DisplayPartitionError(B_TRANSLATE("Failed to format the " 1226 "partition. No changes have been written to disk."), NULL, status); 1227 return; 1228 } 1229 1230 // The disk layout has changed, update disk information 1231 bool updated; 1232 status = disk->Update(&updated); 1233 1234 _ScanDrives(); 1235 fDiskView->ForceUpdate(); 1236 } 1237 1238 1239 void 1240 MainWindow::_Delete(BDiskDevice* disk, partition_id selectedPartition) 1241 { 1242 if (!disk || selectedPartition < 0) { 1243 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 1244 "entry from the list.")); 1245 return; 1246 } 1247 1248 if (disk->IsReadOnly()) { 1249 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 1250 return; 1251 } 1252 1253 BPartition* partition = disk->FindDescendant(selectedPartition); 1254 if (!partition) { 1255 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 1256 "partition by ID.")); 1257 return; 1258 } 1259 1260 BPartition* parent = partition->Parent(); 1261 if (!parent) { 1262 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 1263 "does not have a parent partition.")); 1264 return; 1265 } 1266 1267 ModificationPreparer modificationPreparer(disk); 1268 status_t status = modificationPreparer.ModificationStatus(); 1269 if (status != B_OK) { 1270 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1271 "disk for modifications."), NULL, status); 1272 return; 1273 } 1274 1275 if (!parent->CanDeleteChild(partition->Index())) { 1276 _DisplayPartitionError( 1277 B_TRANSLATE("Cannot delete the selected partition.")); 1278 return; 1279 } 1280 1281 // Warn the user one more time... 1282 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1283 "want to delete the selected partition?\n\n" 1284 "All data on the partition will be irretrievably lost if you " 1285 "do so!"), B_TRANSLATE("Delete partition"), B_TRANSLATE("Cancel"), NULL, 1286 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1287 alert->SetShortcut(1, B_ESCAPE); 1288 int32 choice = alert->Go(); 1289 1290 if (choice == 1) 1291 return; 1292 1293 status = parent->DeleteChild(partition->Index()); 1294 if (status != B_OK) { 1295 _DisplayPartitionError(B_TRANSLATE("Could not delete the selected " 1296 "partition."), NULL, status); 1297 return; 1298 } 1299 1300 status = modificationPreparer.CommitModifications(); 1301 1302 if (status != B_OK) { 1303 _DisplayPartitionError(B_TRANSLATE("Failed to delete the partition. " 1304 "No changes have been written to disk."), NULL, status); 1305 return; 1306 } 1307 1308 _ScanDrives(); 1309 fDiskView->ForceUpdate(); 1310 } 1311 1312 1313 void 1314 MainWindow::_ChangeParameters(BDiskDevice* disk, partition_id selectedPartition) 1315 { 1316 if (disk == NULL || selectedPartition < 0) { 1317 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 1318 "entry from the list.")); 1319 return; 1320 } 1321 1322 if (disk->IsReadOnly()) { 1323 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 1324 return; 1325 } 1326 1327 BPartition* partition = disk->FindDescendant(selectedPartition); 1328 if (partition == NULL) { 1329 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 1330 "partition by ID.")); 1331 return; 1332 } 1333 1334 ModificationPreparer modificationPreparer(disk); 1335 status_t status = modificationPreparer.ModificationStatus(); 1336 if (status != B_OK) { 1337 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1338 "disk for modifications."), NULL, status); 1339 return; 1340 } 1341 1342 ChangeParametersPanel* panel = new ChangeParametersPanel(this, partition); 1343 1344 BString name, type, parameters; 1345 status = panel->Go(name, type, parameters); 1346 if (status != B_OK) { 1347 if (status != B_CANCELED) { 1348 _DisplayPartitionError(B_TRANSLATE("The panel experienced a " 1349 "problem!"), NULL, status); 1350 } 1351 // TODO: disk systems without an editor and support for name/type 1352 // changing will return B_CANCELED here -- we need to check this 1353 // before, and disable the menu entry instead 1354 return; 1355 } 1356 1357 if (partition->CanSetType()) 1358 status = partition->ValidateSetType(type.String()); 1359 if (status == B_OK && partition->CanSetName()) 1360 status = partition->ValidateSetName(&name); 1361 if (status != B_OK) { 1362 _DisplayPartitionError(B_TRANSLATE("Validation of the given parameters " 1363 "failed.")); 1364 return; 1365 } 1366 1367 // Warn the user one more time... 1368 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1369 "want to change parameters of the selected partition?\n\n" 1370 "The partition may no longer be recognized by other operating systems " 1371 "anymore!"), B_TRANSLATE("Change parameters"), B_TRANSLATE("Cancel"), 1372 NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1373 alert->SetShortcut(1, B_ESCAPE); 1374 int32 choice = alert->Go(); 1375 1376 if (choice == 1) 1377 return; 1378 1379 if (partition->CanSetType()) 1380 status = partition->SetType(type.String()); 1381 if (status == B_OK && partition->CanSetName()) 1382 status = partition->SetName(name.String()); 1383 if (status == B_OK && partition->CanEditParameters()) 1384 status = partition->SetParameters(parameters.String()); 1385 1386 if (status != B_OK) { 1387 _DisplayPartitionError( 1388 B_TRANSLATE("Could not change the parameters of the selected " 1389 "partition."), NULL, status); 1390 return; 1391 } 1392 1393 status = modificationPreparer.CommitModifications(); 1394 1395 if (status != B_OK) { 1396 _DisplayPartitionError(B_TRANSLATE("Failed to change the parameters " 1397 "of the partition. No changes have been written to disk."), NULL, 1398 status); 1399 return; 1400 } 1401 1402 _ScanDrives(); 1403 fDiskView->ForceUpdate(); 1404 } 1405 1406 1407 float 1408 MainWindow::_ColumnListViewHeight(BColumnListView* list, BRow* currentRow) 1409 { 1410 float height = 0; 1411 int32 rows = list->CountRows(currentRow); 1412 for (int32 i = 0; i < rows; i++) { 1413 BRow* row = list->RowAt(i, currentRow); 1414 height += row->Height() + 1; 1415 if (row->IsExpanded() && list->CountRows(row) > 0) 1416 height += _ColumnListViewHeight(list, row); 1417 } 1418 return height; 1419 } 1420 1421 1422 void 1423 MainWindow::_UpdateWindowZoomLimits() 1424 { 1425 float maxHeight = 0; 1426 int32 numColumns = fListView->CountColumns(); 1427 BRow* parentRow = fListView->RowAt(0, NULL); 1428 BColumn* column = NULL; 1429 1430 maxHeight += _ColumnListViewHeight(fListView, NULL); 1431 1432 float maxWidth = fListView->LatchWidth(); 1433 for (int32 i = 0; i < numColumns; i++) { 1434 column = fListView->ColumnAt(i); 1435 maxWidth += column->Width(); 1436 } 1437 1438 maxHeight += B_H_SCROLL_BAR_HEIGHT; 1439 maxHeight += 1.5 * parentRow->Height(); // the label row 1440 maxHeight += fDiskView->Bounds().Height(); 1441 maxHeight += fMenuBar->Bounds().Height(); 1442 maxWidth += 1.5 * B_V_SCROLL_BAR_WIDTH; // scroll bar & borders 1443 1444 SetZoomLimits(maxWidth, maxHeight); 1445 } 1446 1447