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