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