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 writable = !partition->IsReadOnly() 744 && partition->Device()->HasMedia(); 745 bool notMountedAndWritable = !partition->IsMounted() && writable; 746 747 fFormatMenu->SetEnabled(writable && fFormatMenu->CountItems() > 0); 748 749 fDiskInitMenu->SetEnabled(notMountedAndWritable 750 && partition->IsDevice() 751 && fDiskInitMenu->CountItems() > 0); 752 753 fChangeMenuItem->SetEnabled(notMountedAndWritable); 754 755 fDeleteMenuItem->SetEnabled(notMountedAndWritable 756 && !partition->IsDevice()); 757 758 fMountMenuItem->SetEnabled(!partition->IsMounted()); 759 760 fFormatContextMenuItem->SetEnabled(notMountedAndWritable 761 && fFormatContextMenuItem->CountItems() > 0); 762 fChangeContextMenuItem->SetEnabled(notMountedAndWritable); 763 fDeleteContextMenuItem->SetEnabled(notMountedAndWritable 764 && !partition->IsDevice()); 765 fMountContextMenuItem->SetEnabled(notMountedAndWritable); 766 767 bool unMountable = false; 768 if (partition->IsMounted()) { 769 // see if this partition is the boot volume 770 BVolume volume; 771 BVolume bootVolume; 772 if (BVolumeRoster().GetBootVolume(&bootVolume) == B_OK 773 && partition->GetVolume(&volume) == B_OK) { 774 unMountable = volume != bootVolume; 775 } else 776 unMountable = true; 777 } 778 fUnmountMenuItem->SetEnabled(unMountable); 779 fUnmountContextMenuItem->SetEnabled(unMountable); 780 } else { 781 fDeleteMenuItem->SetEnabled(false); 782 fChangeMenuItem->SetEnabled(false); 783 fMountMenuItem->SetEnabled(false); 784 fFormatMenu->SetEnabled(false); 785 fDiskInitMenu->SetEnabled(false); 786 787 fDeleteContextMenuItem->SetEnabled(false); 788 fChangeContextMenuItem->SetEnabled(false); 789 fMountContextMenuItem->SetEnabled(false); 790 fFormatContextMenuItem->SetEnabled(false); 791 } 792 793 fOpenDiskProbeMenuItem->SetEnabled(true); 794 fOpenDiskProbeContextMenuItem->SetEnabled(true); 795 796 if (prepared) 797 disk->CancelModifications(); 798 799 fMountAllMenuItem->SetEnabled(true); 800 } 801 if (selectedPartition < 0) { 802 fDeleteMenuItem->SetEnabled(false); 803 fChangeMenuItem->SetEnabled(false); 804 fMountMenuItem->SetEnabled(false); 805 806 fDeleteContextMenuItem->SetEnabled(false); 807 fChangeContextMenuItem->SetEnabled(false); 808 fMountContextMenuItem->SetEnabled(false); 809 } 810 } 811 812 813 void 814 MainWindow::_DisplayPartitionError(BString _message, 815 const BPartition* partition, status_t error) const 816 { 817 char message[1024]; 818 819 if (partition && _message.FindFirst("%s") >= 0) { 820 BString name; 821 name << "\"" << partition->ContentName() << "\""; 822 snprintf(message, sizeof(message), _message.String(), name.String()); 823 } else { 824 _message.ReplaceAll("%s", ""); 825 strlcpy(message, _message.String(), sizeof(message)); 826 } 827 828 if (error < B_OK) { 829 BString helper = message; 830 const char* errorString 831 = B_TRANSLATE_COMMENT("Error: ", "in any error alert"); 832 snprintf(message, sizeof(message), "%s\n\n%s%s", helper.String(), 833 errorString, strerror(error)); 834 } 835 836 BAlert* alert = new BAlert("error", message, B_TRANSLATE("OK"), NULL, NULL, 837 B_WIDTH_FROM_WIDEST, error < B_OK ? B_STOP_ALERT : B_INFO_ALERT); 838 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 839 alert->Go(NULL); 840 } 841 842 843 // #pragma mark - 844 845 846 void 847 MainWindow::_Mount(BDiskDevice* disk, partition_id selectedPartition) 848 { 849 if (!disk || selectedPartition < 0) { 850 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 851 "entry from the list.")); 852 return; 853 } 854 855 BPartition* partition = disk->FindDescendant(selectedPartition); 856 if (!partition) { 857 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 858 "partition by ID.")); 859 return; 860 } 861 862 if (!partition->IsMounted()) { 863 status_t status = partition->Mount(); 864 if (status != B_OK) { 865 _DisplayPartitionError(B_TRANSLATE("Could not mount partition %s."), 866 partition, status); 867 } else { 868 // successful mount, adapt to the changes 869 _ScanDrives(); 870 } 871 } else { 872 _DisplayPartitionError( 873 B_TRANSLATE("The partition %s is already mounted."), partition); 874 } 875 } 876 877 878 void 879 MainWindow::_Unmount(BDiskDevice* disk, partition_id selectedPartition) 880 { 881 if (!disk || selectedPartition < 0) { 882 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 883 "entry from the list.")); 884 return; 885 } 886 887 BPartition* partition = disk->FindDescendant(selectedPartition); 888 if (!partition) { 889 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 890 "partition by ID.")); 891 return; 892 } 893 894 if (partition->IsMounted()) { 895 BPath path; 896 partition->GetMountPoint(&path); 897 status_t status = partition->Unmount(); 898 if (status != B_OK) { 899 BString message = B_TRANSLATE("Could not unmount partition"); 900 message << " \"" << partition->ContentName() << "\":\n\t" 901 << strerror(status) << "\n\n" 902 << B_TRANSLATE("Should unmounting be forced?\n\n" 903 "Note: If an application is currently writing to the volume, " 904 "unmounting it now might result in loss of data.\n"); 905 906 BAlert* alert = new BAlert(B_TRANSLATE("Force unmount"), message, 907 B_TRANSLATE("Cancel"), B_TRANSLATE("Force unmount"), NULL, 908 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 909 alert->SetShortcut(0, B_ESCAPE); 910 911 if (alert->Go() == 1) 912 status = partition->Unmount(B_FORCE_UNMOUNT); 913 else 914 return; 915 } 916 917 if (status != B_OK) { 918 _DisplayPartitionError( 919 B_TRANSLATE("Could not unmount partition %s."), 920 partition, status); 921 } else { 922 if (dev_for_path(path.Path()) == dev_for_path("/")) 923 rmdir(path.Path()); 924 // successful unmount, adapt to the changes 925 _ScanDrives(); 926 } 927 } else { 928 _DisplayPartitionError( 929 B_TRANSLATE("The partition %s is already unmounted."), 930 partition); 931 } 932 } 933 934 935 void 936 MainWindow::_MountAll() 937 { 938 MountAllVisitor visitor; 939 fDiskDeviceRoster.VisitEachPartition(&visitor); 940 } 941 942 943 // #pragma mark - 944 945 946 void 947 MainWindow::_Initialize(BDiskDevice* disk, partition_id selectedPartition, 948 const BString& diskSystemName) 949 { 950 if (!disk || selectedPartition < 0) { 951 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 952 "entry from the list.")); 953 return; 954 } 955 956 if (disk->IsReadOnly()) { 957 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 958 return; 959 } 960 961 BPartition* partition = disk->FindDescendant(selectedPartition); 962 if (!partition) { 963 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 964 "partition by ID.")); 965 return; 966 } 967 968 if (partition->IsMounted()) { 969 if (partition->Unmount() != B_OK) { 970 // Probably it's the system partition 971 _DisplayPartitionError( 972 B_TRANSLATE("The partition cannot be unmounted.")); 973 974 return; 975 } 976 } 977 978 BDiskSystem diskSystem; 979 fDiskDeviceRoster.RewindDiskSystems(); 980 bool found = false; 981 while (fDiskDeviceRoster.GetNextDiskSystem(&diskSystem) == B_OK) { 982 if (diskSystem.SupportsInitializing()) { 983 if (diskSystemName == diskSystem.PrettyName()) { 984 found = true; 985 break; 986 } 987 } 988 } 989 990 if (!found) { 991 _DisplayPartitionError(B_TRANSLATE("Disk system \"%s\" not found!")); 992 return; 993 } 994 995 BString message; 996 997 if (diskSystem.IsFileSystem()) { 998 BString intelExtendedPartition = "Intel Extended Partition"; 999 if (disk->ID() == selectedPartition) { 1000 message = B_TRANSLATE("Are you sure you " 1001 "want to format a raw disk? (Most people initialize the disk " 1002 "with a partitioning system first) You will be asked " 1003 "again before changes are written to the disk."); 1004 } else if (partition->ContentName() 1005 && strlen(partition->ContentName()) > 0) { 1006 message = B_TRANSLATE("Are you sure you " 1007 "want to format the partition \"%s\"? You will be asked " 1008 "again before changes are written to the disk."); 1009 message.ReplaceFirst("%s", partition->ContentName()); 1010 } else if (partition->Type() == intelExtendedPartition) { 1011 message = B_TRANSLATE("Are you sure you " 1012 "want to format the Intel Extended Partition? Any " 1013 "subpartitions it contains will be overwritten if you " 1014 "continue. You will be asked again before changes are " 1015 "written to the disk."); 1016 } else { 1017 message = B_TRANSLATE("Are you sure you " 1018 "want to format the partition? You will be asked again " 1019 "before changes are written to the disk."); 1020 } 1021 } else { 1022 message = B_TRANSLATE("Are you sure you " 1023 "want to initialize the selected disk? All data will be lost. " 1024 "You will be asked again before changes are written to the " 1025 "disk.\n"); 1026 } 1027 BAlert* alert = new BAlert("first notice", message.String(), 1028 B_TRANSLATE("Continue"), B_TRANSLATE("Cancel"), NULL, 1029 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1030 alert->SetShortcut(1, B_ESCAPE); 1031 int32 choice = alert->Go(); 1032 1033 if (choice == 1) 1034 return; 1035 1036 ModificationPreparer modificationPreparer(disk); 1037 status_t status = modificationPreparer.ModificationStatus(); 1038 if (status != B_OK) { 1039 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1040 "disk for modifications."), NULL, status); 1041 return; 1042 } 1043 1044 BString name; 1045 BString parameters; 1046 InitParametersPanel* panel = new InitParametersPanel(this, diskSystemName, 1047 partition); 1048 if (panel->Go(name, parameters) != B_OK) 1049 return; 1050 1051 bool supportsName = diskSystem.SupportsContentName(); 1052 BString validatedName(name); 1053 status = partition->ValidateInitialize(diskSystem.PrettyName(), 1054 supportsName ? &validatedName : NULL, parameters.String()); 1055 if (status != B_OK) { 1056 _DisplayPartitionError(B_TRANSLATE("Validation of the given " 1057 "initialization parameters failed."), partition, status); 1058 return; 1059 } 1060 1061 BString previousName = partition->ContentName(); 1062 1063 status = partition->Initialize(diskSystem.PrettyName(), 1064 supportsName ? validatedName.String() : NULL, parameters.String()); 1065 if (status != B_OK) { 1066 _DisplayPartitionError(B_TRANSLATE("Initialization of the partition " 1067 "%s failed. (Nothing has been written to disk.)"), partition, 1068 status); 1069 return; 1070 } 1071 1072 // Also set the partition name in the partition table if supported 1073 if (partition->CanSetName() 1074 && partition->ValidateSetName(&validatedName) == B_OK) { 1075 partition->SetName(validatedName.String()); 1076 } 1077 1078 // everything looks fine, we are ready to actually write the changes 1079 // to disk 1080 1081 // Warn the user one more time... 1082 if (previousName.Length() > 0) { 1083 if (partition->IsDevice()) { 1084 message = B_TRANSLATE("Are you sure you " 1085 "want to write the changes back to disk now?\n\n" 1086 "All data on the disk %s will be irretrievably lost if you " 1087 "do so!"); 1088 message.ReplaceFirst("%s", previousName.String()); 1089 } else { 1090 message = B_TRANSLATE("Are you sure you " 1091 "want to write the changes back to disk now?\n\n" 1092 "All data on the partition %s will be irretrievably lost if you " 1093 "do so!"); 1094 message.ReplaceFirst("%s", previousName.String()); 1095 } 1096 } else { 1097 if (partition->IsDevice()) { 1098 message = B_TRANSLATE("Are you sure you " 1099 "want to write the changes back to disk now?\n\n" 1100 "All data on the selected disk will be irretrievably lost if " 1101 "you do so!"); 1102 } else { 1103 message = B_TRANSLATE("Are you sure you " 1104 "want to write the changes back to disk now?\n\n" 1105 "All data on the selected partition will be irretrievably lost " 1106 "if you do so!"); 1107 } 1108 } 1109 alert = new BAlert("final notice", message.String(), 1110 B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, 1111 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1112 alert->SetShortcut(1, B_ESCAPE); 1113 choice = alert->Go(); 1114 1115 if (choice == 1) 1116 return; 1117 1118 // commit 1119 status = modificationPreparer.CommitModifications(); 1120 1121 // The partition pointer is toast now! Use the partition ID to 1122 // retrieve it again. 1123 partition = disk->FindDescendant(selectedPartition); 1124 1125 if (status == B_OK) { 1126 if (diskSystem.IsFileSystem()) { 1127 _DisplayPartitionError(B_TRANSLATE("The partition %s has been " 1128 "successfully formatted.\n"), partition); 1129 } else { 1130 _DisplayPartitionError(B_TRANSLATE("The disk has been " 1131 "successfully initialized.\n"), partition); 1132 } 1133 } else { 1134 if (diskSystem.IsFileSystem()) { 1135 _DisplayPartitionError(B_TRANSLATE("Failed to format the " 1136 "partition %s!\n"), partition, status); 1137 } else { 1138 _DisplayPartitionError(B_TRANSLATE("Failed to initialize the " 1139 "disk %s!\n"), partition, status); 1140 } 1141 } 1142 1143 _ScanDrives(); 1144 } 1145 1146 1147 void 1148 MainWindow::_Create(BDiskDevice* disk, partition_id selectedPartition) 1149 { 1150 if (!disk || selectedPartition > -2) { 1151 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 1152 "is not empty.")); 1153 return; 1154 } 1155 1156 if (disk->IsReadOnly()) { 1157 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 1158 return; 1159 } 1160 1161 PartitionListRow* currentSelection = dynamic_cast<PartitionListRow*>( 1162 fListView->CurrentSelection()); 1163 if (!currentSelection) { 1164 _DisplayPartitionError(B_TRANSLATE("There was an error acquiring the " 1165 "partition row.")); 1166 return; 1167 } 1168 1169 BPartition* parent = disk->FindDescendant(currentSelection->ParentID()); 1170 if (!parent) { 1171 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 1172 "does not have a parent partition.")); 1173 return; 1174 } 1175 1176 if (!parent->ContainsPartitioningSystem()) { 1177 _DisplayPartitionError(B_TRANSLATE("The selected partition does not " 1178 "contain a partitioning system.")); 1179 return; 1180 } 1181 1182 ModificationPreparer modificationPreparer(disk); 1183 status_t status = modificationPreparer.ModificationStatus(); 1184 if (status != B_OK) { 1185 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1186 "disk for modifications."), NULL, status); 1187 return; 1188 } 1189 1190 // get partitioning info 1191 BPartitioningInfo partitioningInfo; 1192 status_t error = parent->GetPartitioningInfo(&partitioningInfo); 1193 if (error != B_OK) { 1194 _DisplayPartitionError(B_TRANSLATE("Could not acquire partitioning " 1195 "information.")); 1196 return; 1197 } 1198 1199 int32 spacesCount = partitioningInfo.CountPartitionableSpaces(); 1200 if (spacesCount == 0) { 1201 _DisplayPartitionError(B_TRANSLATE("There's no space on the partition " 1202 "where a child partition could be created.")); 1203 return; 1204 } 1205 1206 BString name, type, parameters; 1207 off_t offset = currentSelection->Offset(); 1208 off_t size = currentSelection->Size(); 1209 1210 CreateParametersPanel* panel = new CreateParametersPanel(this, parent, 1211 offset, size); 1212 status = panel->Go(offset, size, name, type, parameters); 1213 if (status != B_OK) { 1214 if (status != B_CANCELED) { 1215 _DisplayPartitionError(B_TRANSLATE("The panel could not return " 1216 "successfully."), NULL, status); 1217 } 1218 return; 1219 } 1220 1221 status = parent->ValidateCreateChild(&offset, &size, type.String(), 1222 &name, parameters.String()); 1223 1224 if (status != B_OK) { 1225 _DisplayPartitionError(B_TRANSLATE("Validation of the given creation " 1226 "parameters failed."), NULL, status); 1227 return; 1228 } 1229 1230 // Warn the user one more time... 1231 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1232 "want to write the changes back to disk now?\n\n" 1233 "All data on the partition will be irretrievably lost if you do " 1234 "so!"), B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, 1235 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1236 alert->SetShortcut(1, B_ESCAPE); 1237 int32 choice = alert->Go(); 1238 1239 if (choice == 1) 1240 return; 1241 1242 status = parent->CreateChild(offset, size, type.String(), name.String(), 1243 parameters.String()); 1244 1245 if (status != B_OK) { 1246 _DisplayPartitionError(B_TRANSLATE("Creation of the partition has " 1247 "failed."), NULL, status); 1248 return; 1249 } 1250 1251 // commit 1252 status = modificationPreparer.CommitModifications(); 1253 1254 if (status != B_OK) { 1255 _DisplayPartitionError(B_TRANSLATE("Failed to format the " 1256 "partition. No changes have been written to disk."), NULL, status); 1257 return; 1258 } 1259 1260 // The disk layout has changed, update disk information 1261 bool updated; 1262 status = disk->Update(&updated); 1263 1264 _ScanDrives(); 1265 fDiskView->ForceUpdate(); 1266 } 1267 1268 1269 void 1270 MainWindow::_Delete(BDiskDevice* disk, partition_id selectedPartition) 1271 { 1272 if (!disk || selectedPartition < 0) { 1273 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 1274 "entry from the list.")); 1275 return; 1276 } 1277 1278 if (disk->IsReadOnly()) { 1279 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 1280 return; 1281 } 1282 1283 BPartition* partition = disk->FindDescendant(selectedPartition); 1284 if (!partition) { 1285 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 1286 "partition by ID.")); 1287 return; 1288 } 1289 1290 BPartition* parent = partition->Parent(); 1291 if (!parent) { 1292 _DisplayPartitionError(B_TRANSLATE("The currently selected partition " 1293 "does not have a parent partition.")); 1294 return; 1295 } 1296 1297 ModificationPreparer modificationPreparer(disk); 1298 status_t status = modificationPreparer.ModificationStatus(); 1299 if (status != B_OK) { 1300 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1301 "disk for modifications."), NULL, status); 1302 return; 1303 } 1304 1305 if (!parent->CanDeleteChild(partition->Index())) { 1306 _DisplayPartitionError( 1307 B_TRANSLATE("Cannot delete the selected partition.")); 1308 return; 1309 } 1310 1311 // Warn the user one more time... 1312 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1313 "want to delete the selected partition?\n\n" 1314 "All data on the partition will be irretrievably lost if you " 1315 "do so!"), B_TRANSLATE("Delete partition"), B_TRANSLATE("Cancel"), NULL, 1316 B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1317 alert->SetShortcut(1, B_ESCAPE); 1318 int32 choice = alert->Go(); 1319 1320 if (choice == 1) 1321 return; 1322 1323 status = parent->DeleteChild(partition->Index()); 1324 if (status != B_OK) { 1325 _DisplayPartitionError(B_TRANSLATE("Could not delete the selected " 1326 "partition."), NULL, status); 1327 return; 1328 } 1329 1330 status = modificationPreparer.CommitModifications(); 1331 1332 if (status != B_OK) { 1333 _DisplayPartitionError(B_TRANSLATE("Failed to delete the partition. " 1334 "No changes have been written to disk."), NULL, status); 1335 return; 1336 } 1337 1338 _ScanDrives(); 1339 fDiskView->ForceUpdate(); 1340 } 1341 1342 1343 void 1344 MainWindow::_ChangeParameters(BDiskDevice* disk, partition_id selectedPartition) 1345 { 1346 if (disk == NULL || selectedPartition < 0) { 1347 _DisplayPartitionError(B_TRANSLATE("You need to select a partition " 1348 "entry from the list.")); 1349 return; 1350 } 1351 1352 if (disk->IsReadOnly()) { 1353 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); 1354 return; 1355 } 1356 1357 BPartition* partition = disk->FindDescendant(selectedPartition); 1358 if (partition == NULL) { 1359 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " 1360 "partition by ID.")); 1361 return; 1362 } 1363 1364 ModificationPreparer modificationPreparer(disk); 1365 status_t status = modificationPreparer.ModificationStatus(); 1366 if (status != B_OK) { 1367 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " 1368 "disk for modifications."), NULL, status); 1369 return; 1370 } 1371 1372 ChangeParametersPanel* panel = new ChangeParametersPanel(this, partition); 1373 1374 BString name, type, parameters; 1375 status = panel->Go(name, type, parameters); 1376 if (status != B_OK) { 1377 if (status != B_CANCELED) { 1378 _DisplayPartitionError(B_TRANSLATE("The panel experienced a " 1379 "problem!"), NULL, status); 1380 } 1381 // TODO: disk systems without an editor and support for name/type 1382 // changing will return B_CANCELED here -- we need to check this 1383 // before, and disable the menu entry instead 1384 return; 1385 } 1386 1387 if (partition->CanSetType()) 1388 status = partition->ValidateSetType(type.String()); 1389 if (status == B_OK && partition->CanSetName()) 1390 status = partition->ValidateSetName(&name); 1391 if (status != B_OK) { 1392 _DisplayPartitionError(B_TRANSLATE("Validation of the given parameters " 1393 "failed.")); 1394 return; 1395 } 1396 1397 // Warn the user one more time... 1398 BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " 1399 "want to change parameters of the selected partition?\n\n" 1400 "The partition may no longer be recognized by other operating systems " 1401 "anymore!"), B_TRANSLATE("Change parameters"), B_TRANSLATE("Cancel"), 1402 NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 1403 alert->SetShortcut(1, B_ESCAPE); 1404 int32 choice = alert->Go(); 1405 1406 if (choice == 1) 1407 return; 1408 1409 if (partition->CanSetType()) 1410 status = partition->SetType(type.String()); 1411 if (status == B_OK && partition->CanSetName()) 1412 status = partition->SetName(name.String()); 1413 if (status == B_OK && partition->CanEditParameters()) 1414 status = partition->SetParameters(parameters.String()); 1415 1416 if (status != B_OK) { 1417 _DisplayPartitionError( 1418 B_TRANSLATE("Could not change the parameters of the selected " 1419 "partition."), NULL, status); 1420 return; 1421 } 1422 1423 status = modificationPreparer.CommitModifications(); 1424 1425 if (status != B_OK) { 1426 _DisplayPartitionError(B_TRANSLATE("Failed to change the parameters " 1427 "of the partition. No changes have been written to disk."), NULL, 1428 status); 1429 return; 1430 } 1431 1432 _ScanDrives(); 1433 fDiskView->ForceUpdate(); 1434 } 1435 1436 1437 float 1438 MainWindow::_ColumnListViewHeight(BColumnListView* list, BRow* currentRow) 1439 { 1440 float height = 0; 1441 int32 rows = list->CountRows(currentRow); 1442 for (int32 i = 0; i < rows; i++) { 1443 BRow* row = list->RowAt(i, currentRow); 1444 height += row->Height() + 1; 1445 if (row->IsExpanded() && list->CountRows(row) > 0) 1446 height += _ColumnListViewHeight(list, row); 1447 } 1448 return height; 1449 } 1450 1451 1452 void 1453 MainWindow::_UpdateWindowZoomLimits() 1454 { 1455 float maxHeight = 0; 1456 int32 numColumns = fListView->CountColumns(); 1457 BRow* parentRow = fListView->RowAt(0, NULL); 1458 BColumn* column = NULL; 1459 1460 maxHeight += _ColumnListViewHeight(fListView, NULL); 1461 1462 float maxWidth = fListView->LatchWidth(); 1463 for (int32 i = 0; i < numColumns; i++) { 1464 column = fListView->ColumnAt(i); 1465 maxWidth += column->Width(); 1466 } 1467 1468 maxHeight += B_H_SCROLL_BAR_HEIGHT; 1469 maxHeight += 1.5 * parentRow->Height(); // the label row 1470 maxHeight += fDiskView->Bounds().Height(); 1471 maxHeight += fMenuBar->Bounds().Height(); 1472 maxWidth += 1.5 * B_V_SCROLL_BAR_WIDTH; // scroll bar & borders 1473 1474 SetZoomLimits(maxWidth, maxHeight); 1475 } 1476 1477