2 * Copyright 2002-2013 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
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>
14 #include "MainWindow.h"
20 #include <Application.h>
22 #include <ColumnListView.h>
23 #include <ColumnTypes.h>
25 #include <DiskDevice.h>
26 #include <DiskDeviceVisitor.h>
27 #include <DiskDeviceTypes.h>
28 #include <DiskSystem.h>
34 #include <Partition.h>
35 #include <PartitioningInfo.h>
38 #include <ScrollBar.h>
40 #include <VolumeRoster.h>
42 #include <fs_volume.h>
43 #include <tracker_private.h>
45 #include "ChangeParametersPanel.h"
46 #include "ColumnListView.h"
47 #include "CreateParametersPanel.h"
49 #include "InitParametersPanel.h"
50 #include "PartitionList.h"
54 #undef B_TRANSLATION_CONTEXT
55 #define B_TRANSLATION_CONTEXT "MainWindow"
59 MSG_MOUNT_ALL
= 'mnta',
65 MSG_INITIALIZE
= 'init',
68 MSG_SURFACE_TEST
= 'sfct',
71 MSG_PARTITION_ROW_SELECTED
= 'prsl',
75 class ListPopulatorVisitor
: public BDiskDeviceVisitor
{
77 ListPopulatorVisitor(PartitionListView
* list
, int32
& diskCount
,
78 SpaceIDMap
& spaceIDMap
)
81 fDiskCount(diskCount
),
82 fSpaceIDMap(spaceIDMap
)
86 // start with an empty list
87 int32 rows
= fPartitionList
->CountRows();
88 for (int32 i
= rows
- 1; i
>= 0; i
--) {
89 BRow
* row
= fPartitionList
->RowAt(i
);
90 fPartitionList
->RemoveRow(row
);
95 virtual bool Visit(BDiskDevice
* device
)
98 // if we don't prepare the device for modifications,
99 // we cannot get information about available empty
100 // regions on the device or child partitions
101 device
->PrepareModifications();
102 _AddPartition(device
);
103 return false; // Don't stop yet!
106 virtual bool Visit(BPartition
* partition
, int32 level
)
108 _AddPartition(partition
);
109 return false; // Don't stop yet!
113 void _AddPartition(BPartition
* partition
) const
115 // add the partition itself
116 fPartitionList
->AddPartition(partition
);
118 // add any available space on it
119 BPartitioningInfo info
;
120 status_t status
= partition
->GetPartitioningInfo(&info
);
121 if (status
>= B_OK
) {
122 partition_id parentID
= partition
->ID();
126 info
.GetPartitionableSpaceAt(i
, &offset
, &size
) >= B_OK
;
128 // TODO: remove again once Disk Device API is fixed
129 if (!is_valid_partitionable_space(size
))
132 partition_id id
= fSpaceIDMap
.SpaceIDFor(parentID
, offset
);
133 fPartitionList
->AddSpace(parentID
, id
, offset
, size
);
138 PartitionListView
* fPartitionList
;
140 SpaceIDMap
& fSpaceIDMap
;
141 BDiskDevice
* fLastPreparedDevice
;
145 class MountAllVisitor
: public BDiskDeviceVisitor
{
151 virtual bool Visit(BDiskDevice
* device
)
153 if (device
->ContainsFileSystem())
156 return false; // Don't stop yet!
159 virtual bool Visit(BPartition
* partition
, int32 level
)
162 return false; // Don't stop yet!
166 PartitionListView
* fPartitionList
;
170 class ModificationPreparer
{
172 ModificationPreparer(BDiskDevice
* disk
)
175 fModificationStatus(fDisk
->PrepareModifications())
178 ~ModificationPreparer()
180 if (fModificationStatus
== B_OK
)
181 fDisk
->CancelModifications();
183 status_t
ModificationStatus() const
185 return fModificationStatus
;
187 status_t
CommitModifications()
189 status_t status
= fDisk
->CommitModifications();
191 fModificationStatus
= B_ERROR
;
198 status_t fModificationStatus
;
205 MainWindow::MainWindow()
207 BWindow(BRect(50, 50, 600, 500), B_TRANSLATE_SYSTEM_NAME("DriveSetup"),
208 B_DOCUMENT_WINDOW
, B_ASYNCHRONOUS_CONTROLS
),
210 fCurrentPartitionID(-1),
213 fMenuBar
= new BMenuBar(Bounds(), "root menu");
215 // create all the menu items
216 fWipeMenuItem
= new BMenuItem(B_TRANSLATE("Wipe (not implemented)"),
217 new BMessage(MSG_FORMAT
));
218 fEjectMenuItem
= new BMenuItem(B_TRANSLATE("Eject"),
219 new BMessage(MSG_EJECT
), 'E');
220 fSurfaceTestMenuItem
= new BMenuItem(
221 B_TRANSLATE("Surface test (not implemented)"),
222 new BMessage(MSG_SURFACE_TEST
));
223 fRescanMenuItem
= new BMenuItem(B_TRANSLATE("Rescan"),
224 new BMessage(MSG_RESCAN
));
226 fCreateMenuItem
= new BMenuItem(B_TRANSLATE("Create" B_UTF8_ELLIPSIS
),
227 new BMessage(MSG_CREATE
), 'C');
228 fChangeMenuItem
= new BMenuItem(
229 B_TRANSLATE("Change parameters" B_UTF8_ELLIPSIS
),
230 new BMessage(MSG_CHANGE
));
231 fDeleteMenuItem
= new BMenuItem(B_TRANSLATE("Delete"),
232 new BMessage(MSG_DELETE
), 'D');
234 fMountMenuItem
= new BMenuItem(B_TRANSLATE("Mount"),
235 new BMessage(MSG_MOUNT
), 'M');
236 fUnmountMenuItem
= new BMenuItem(B_TRANSLATE("Unmount"),
237 new BMessage(MSG_UNMOUNT
), 'U');
238 fMountAllMenuItem
= new BMenuItem(B_TRANSLATE("Mount all"),
239 new BMessage(MSG_MOUNT_ALL
), 'M', B_SHIFT_KEY
);
242 fDiskMenu
= new BMenu(B_TRANSLATE("Disk"));
244 // fDiskMenu->AddItem(fWipeMenuItem);
245 fDiskInitMenu
= new BMenu(B_TRANSLATE("Initialize"));
246 fDiskMenu
->AddItem(fDiskInitMenu
);
248 fDiskMenu
->AddSeparatorItem();
250 fDiskMenu
->AddItem(fEjectMenuItem
);
251 // fDiskMenu->AddItem(fSurfaceTestMenuItem);
252 fDiskMenu
->AddItem(fRescanMenuItem
);
254 fMenuBar
->AddItem(fDiskMenu
);
257 fPartitionMenu
= new BMenu(B_TRANSLATE("Partition"));
258 fPartitionMenu
->AddItem(fCreateMenuItem
);
260 fFormatMenu
= new BMenu(B_TRANSLATE("Format"));
261 fPartitionMenu
->AddItem(fFormatMenu
);
263 fPartitionMenu
->AddItem(fChangeMenuItem
);
264 fPartitionMenu
->AddItem(fDeleteMenuItem
);
266 fPartitionMenu
->AddSeparatorItem();
268 fPartitionMenu
->AddItem(fMountMenuItem
);
269 fPartitionMenu
->AddItem(fUnmountMenuItem
);
271 fPartitionMenu
->AddSeparatorItem();
273 fPartitionMenu
->AddItem(fMountAllMenuItem
);
274 fMenuBar
->AddItem(fPartitionMenu
);
278 // Partition / Drives context menu
279 fContextMenu
= new BPopUpMenu("Partition", false, false);
280 fCreateContextMenuItem
= new BMenuItem(B_TRANSLATE("Create" B_UTF8_ELLIPSIS
),
281 new BMessage(MSG_CREATE
), 'C');
282 fChangeContextMenuItem
= new BMenuItem(
283 B_TRANSLATE("Change parameters" B_UTF8_ELLIPSIS
),
284 new BMessage(MSG_CHANGE
));
285 fDeleteContextMenuItem
= new BMenuItem(B_TRANSLATE("Delete"),
286 new BMessage(MSG_DELETE
), 'D');
287 fMountContextMenuItem
= new BMenuItem(B_TRANSLATE("Mount"),
288 new BMessage(MSG_MOUNT
), 'M');
289 fUnmountContextMenuItem
= new BMenuItem(B_TRANSLATE("Unmount"),
290 new BMessage(MSG_UNMOUNT
), 'U');
291 fFormatContextMenuItem
= new BMenu(B_TRANSLATE("Format"));
293 fContextMenu
->AddItem(fCreateContextMenuItem
);
294 fContextMenu
->AddItem(fFormatContextMenuItem
);
295 fContextMenu
->AddItem(fChangeContextMenuItem
);
296 fContextMenu
->AddItem(fDeleteContextMenuItem
);
297 fContextMenu
->AddSeparatorItem();
298 fContextMenu
->AddItem(fMountContextMenuItem
);
299 fContextMenu
->AddItem(fUnmountContextMenuItem
);
300 fContextMenu
->SetTargetForItems(this);
304 r
.top
= fMenuBar
->Frame().bottom
+ 1;
305 r
.bottom
= floorf(r
.top
+ r
.Height() * 0.33);
306 fDiskView
= new DiskView(r
, B_FOLLOW_LEFT_RIGHT
| B_FOLLOW_TOP
,
310 // add PartitionListView
311 r
.top
= r
.bottom
+ 2;
312 r
.bottom
= Bounds().bottom
;
314 fListView
= new PartitionListView(r
, B_FOLLOW_ALL
);
317 // configure PartitionListView
318 fListView
->SetSelectionMode(B_SINGLE_SELECTION_LIST
);
319 fListView
->SetSelectionMessage(new BMessage(MSG_PARTITION_ROW_SELECTED
));
320 fListView
->SetTarget(this);
321 fListView
->MakeFocus(true);
323 status_t status
= fDiskDeviceRoster
.StartWatching(BMessenger(this));
324 if (status
!= B_OK
) {
325 fprintf(stderr
, "Failed to start watching for device changes: %s\n",
329 // visit all disks in the system and show their contents
332 if (!be_roster
->IsRunning(kDeskbarSignature
))
333 SetFlags(Flags() | B_NOT_MINIMIZABLE
);
337 MainWindow::~MainWindow()
339 BDiskDeviceRoster().StopWatching(this);
346 MainWindow::MessageReceived(BMessage
* message
)
348 switch (message
->what
) {
353 _Mount(fCurrentDisk
, fCurrentPartitionID
);
356 _Unmount(fCurrentDisk
, fCurrentPartitionID
);
360 printf("MSG_FORMAT\n");
364 _Create(fCurrentDisk
, fCurrentPartitionID
);
367 case MSG_INITIALIZE
: {
368 BString diskSystemName
;
369 if (message
->FindString("disk system", &diskSystemName
) != B_OK
)
371 _Initialize(fCurrentDisk
, fCurrentPartitionID
, diskSystemName
);
376 _ChangeParameters(fCurrentDisk
, fCurrentPartitionID
);
380 _Delete(fCurrentDisk
, fCurrentPartitionID
);
384 // TODO: completely untested, especially interesting
385 // if partition list behaves when partitions disappear
387 // TODO: only if no partitions are mounted anymore?
388 fCurrentDisk
->Eject(true);
392 case MSG_SURFACE_TEST
:
393 printf("MSG_SURFACE_TEST\n");
396 // TODO: this could probably be done better!
397 case B_DEVICE_UPDATE
:
398 printf("B_DEVICE_UPDATE\n");
403 case MSG_PARTITION_ROW_SELECTED
: {
404 // selection of partitions via list view
405 _AdaptToSelectedPartition();
409 fListView
->GetMouse(&where
, &buttons
);
410 where
.x
+= 2; // to prevent occasional select
411 if (buttons
& B_SECONDARY_MOUSE_BUTTON
)
412 fContextMenu
->Go(fListView
->ConvertToScreen(where
),
416 case MSG_SELECTED_PARTITION_ID
: {
417 // selection of partitions via disk view
419 if (message
->FindInt32("partition_id", &id
) == B_OK
) {
420 if (BRow
* row
= fListView
->FindRow(id
)) {
421 fListView
->DeselectAll();
422 fListView
->AddToSelection(row
);
423 _AdaptToSelectedPartition();
428 fListView
->GetMouse(&where
, &buttons
);
429 where
.x
+= 2; // to prevent occasional select
430 if (buttons
& B_SECONDARY_MOUSE_BUTTON
)
431 fContextMenu
->Go(fListView
->ConvertToScreen(where
),
436 case MSG_UPDATE_ZOOM_LIMITS
:
437 _UpdateWindowZoomLimits();
441 BWindow::MessageReceived(message
);
448 MainWindow::QuitRequested()
450 // TODO: ask about any unsaved changes
451 be_app
->PostMessage(B_QUIT_REQUESTED
);
461 MainWindow::StoreSettings(BMessage
* archive
) const
463 if (archive
->ReplaceRect("window frame", Frame()) < B_OK
)
464 archive
->AddRect("window frame", Frame());
466 BMessage columnSettings
;
467 fListView
->SaveState(&columnSettings
);
468 if (archive
->ReplaceMessage("column settings", &columnSettings
) < B_OK
)
469 archive
->AddMessage("column settings", &columnSettings
);
476 MainWindow::RestoreSettings(BMessage
* archive
)
479 if (archive
->FindRect("window frame", &frame
) == B_OK
) {
480 BScreen
screen(this);
481 if (frame
.Intersects(screen
.Frame())) {
482 MoveTo(frame
.LeftTop());
483 ResizeTo(frame
.Width(), frame
.Height());
487 BMessage columnSettings
;
488 if (archive
->FindMessage("column settings", &columnSettings
) == B_OK
)
489 fListView
->LoadState(&columnSettings
);
496 MainWindow::ApplyDefaultSettings()
501 fListView
->ResizeAllColumnsToPreferred();
503 // Adjust window size for convenience
504 BScreen
screen(this);
505 float windowWidth
= Frame().Width();
506 float windowHeight
= Frame().Height();
508 float enlargeWidthBy
= fListView
->PreferredSize().width
509 - fListView
->Bounds().Width();
510 float enlargeHeightBy
= fListView
->PreferredSize().height
511 - fListView
->Bounds().Height();
513 if (enlargeWidthBy
> 0.0f
)
514 windowWidth
+= enlargeWidthBy
;
515 if (enlargeHeightBy
> 0.0f
)
516 windowHeight
+= enlargeHeightBy
;
518 if (windowWidth
> screen
.Frame().Width() - 20.0f
)
519 windowWidth
= screen
.Frame().Width() - 20.0f
;
520 if (windowHeight
> screen
.Frame().Height() - 20.0f
)
521 windowHeight
= screen
.Frame().Height() - 20.0f
;
523 ResizeTo(windowWidth
, windowHeight
);
534 MainWindow::_ScanDrives()
538 ListPopulatorVisitor
driveVisitor(fListView
, diskCount
, fSpaceIDMap
);
539 fDiskDeviceRoster
.VisitEachPartition(&driveVisitor
);
540 fDiskView
->SetDiskCount(diskCount
);
543 PartitionListRow
* previousSelection
544 = fListView
->FindRow(fCurrentPartitionID
);
545 if (previousSelection
) {
546 fListView
->AddToSelection(previousSelection
);
547 _UpdateMenus(fCurrentDisk
, fCurrentPartitionID
,
548 previousSelection
->ParentID());
549 fDiskView
->ForceUpdate();
551 _UpdateMenus(NULL
, -1, -1);
554 PostMessage(MSG_UPDATE_ZOOM_LIMITS
);
562 MainWindow::_AdaptToSelectedPartition()
564 partition_id diskID
= -1;
565 partition_id partitionID
= -1;
566 partition_id parentID
= -1;
568 BRow
* _selectedRow
= fListView
->CurrentSelection();
570 // go up to top level row
571 BRow
* _topLevelRow
= _selectedRow
;
573 while (fListView
->FindParent(_topLevelRow
, &parent
, NULL
))
574 _topLevelRow
= parent
;
576 PartitionListRow
* topLevelRow
577 = dynamic_cast<PartitionListRow
*>(_topLevelRow
);
578 PartitionListRow
* selectedRow
579 = dynamic_cast<PartitionListRow
*>(_selectedRow
);
582 diskID
= topLevelRow
->ID();
584 partitionID
= selectedRow
->ID();
585 parentID
= selectedRow
->ParentID();
589 _SetToDiskAndPartition(diskID
, partitionID
, parentID
);
594 MainWindow::_SetToDiskAndPartition(partition_id disk
, partition_id partition
,
597 //printf("MainWindow::_SetToDiskAndPartition(disk: %ld, partition: %ld, "
598 // "parent: %ld)\n", disk, partition, parent);
600 BDiskDevice
* oldDisk
= NULL
;
601 if (!fCurrentDisk
|| fCurrentDisk
->ID() != disk
) {
602 oldDisk
= fCurrentDisk
;
605 BDiskDevice
* newDisk
= new BDiskDevice();
606 status_t status
= newDisk
->SetTo(disk
);
607 if (status
!= B_OK
) {
608 printf("error switching disks: %s\n", strerror(status
));
611 fCurrentDisk
= newDisk
;
615 fCurrentPartitionID
= partition
;
617 fDiskView
->SetDisk(fCurrentDisk
, fCurrentPartitionID
);
618 _UpdateMenus(fCurrentDisk
, fCurrentPartitionID
, parent
);
625 MainWindow::_UpdateMenus(BDiskDevice
* disk
,
626 partition_id selectedPartition
, partition_id parentID
)
628 while (BMenuItem
* item
= fFormatMenu
->RemoveItem((int32
)0))
630 while (BMenuItem
* item
= fDiskInitMenu
->RemoveItem((int32
)0))
632 while (BMenuItem
* item
= fFormatContextMenuItem
->RemoveItem((int32
)0))
635 fCreateMenuItem
->SetEnabled(false);
636 fUnmountMenuItem
->SetEnabled(false);
637 fDiskInitMenu
->SetEnabled(false);
638 fFormatMenu
->SetEnabled(false);
640 fCreateContextMenuItem
->SetEnabled(false);
641 fUnmountContextMenuItem
->SetEnabled(false);
642 fFormatContextMenuItem
->SetEnabled(false);
645 fWipeMenuItem
->SetEnabled(false);
646 fEjectMenuItem
->SetEnabled(false);
647 fSurfaceTestMenuItem
->SetEnabled(false);
649 // fWipeMenuItem->SetEnabled(true);
650 fWipeMenuItem
->SetEnabled(false);
651 fEjectMenuItem
->SetEnabled(disk
->IsRemovableMedia());
652 // fSurfaceTestMenuItem->SetEnabled(true);
653 fSurfaceTestMenuItem
->SetEnabled(false);
655 // Create menu and items
656 BPartition
* parentPartition
= NULL
;
657 if (selectedPartition
<= -2) {
658 // a partitionable space item is selected
659 parentPartition
= disk
->FindDescendant(parentID
);
662 if (parentPartition
&& parentPartition
->ContainsPartitioningSystem()) {
663 fCreateMenuItem
->SetEnabled(true);
664 fCreateContextMenuItem
->SetEnabled(true);
666 bool prepared
= disk
->PrepareModifications() == B_OK
;
668 fFormatMenu
->SetEnabled(prepared
);
669 fDeleteMenuItem
->SetEnabled(prepared
);
670 fChangeMenuItem
->SetEnabled(prepared
);
672 fChangeContextMenuItem
->SetEnabled(prepared
);
673 fDeleteContextMenuItem
->SetEnabled(prepared
);
674 fFormatContextMenuItem
->SetEnabled(prepared
);
676 BPartition
* partition
= disk
->FindDescendant(selectedPartition
);
678 BDiskSystem diskSystem
;
679 fDiskDeviceRoster
.RewindDiskSystems();
680 while (fDiskDeviceRoster
.GetNextDiskSystem(&diskSystem
) == B_OK
) {
681 if (!diskSystem
.SupportsInitializing())
684 BMessage
* message
= new BMessage(MSG_INITIALIZE
);
685 message
->AddInt32("parent id", parentID
);
686 message
->AddString("disk system", diskSystem
.PrettyName());
688 BString label
= diskSystem
.PrettyName();
689 label
<< B_UTF8_ELLIPSIS
;
690 BMenuItem
* item
= new BMenuItem(label
.String(), message
);
692 // TODO: Very unintuitive that we have to use PrettyName (vs Name)
693 item
->SetEnabled(partition
!= NULL
694 && partition
->CanInitialize(diskSystem
.PrettyName()));
696 if (disk
->ID() == selectedPartition
697 && !diskSystem
.IsFileSystem()) {
698 // Disk is selected, and DiskSystem is a partition map
699 fDiskInitMenu
->AddItem(item
);
700 } else if (diskSystem
.IsFileSystem()) {
701 // Otherwise a filesystem
702 fFormatMenu
->AddItem(item
);
705 BMessage
* message
= new BMessage(MSG_INITIALIZE
);
706 message
->AddInt32("parent id", parentID
);
707 message
->AddString("disk system", diskSystem
.PrettyName());
708 BMenuItem
* popUpItem
= new BMenuItem(label
.String(), message
);
709 popUpItem
->SetEnabled(partition
!= NULL
710 && partition
->CanInitialize(diskSystem
.PrettyName()));
711 fFormatContextMenuItem
->AddItem(popUpItem
);
712 fFormatContextMenuItem
->SetTargetForItems(this);
717 if (partition
!= NULL
) {
718 bool notMountedAndWritable
= !partition
->IsMounted()
719 && !partition
->IsReadOnly()
720 && partition
->Device()->HasMedia();
722 fFormatMenu
->SetEnabled(notMountedAndWritable
723 && fFormatMenu
->CountItems() > 0);
725 fDiskInitMenu
->SetEnabled(notMountedAndWritable
726 && partition
->IsDevice()
727 && fDiskInitMenu
->CountItems() > 0);
729 fChangeMenuItem
->SetEnabled(notMountedAndWritable
);
731 fDeleteMenuItem
->SetEnabled(notMountedAndWritable
732 && !partition
->IsDevice());
734 fMountMenuItem
->SetEnabled(!partition
->IsMounted());
736 fFormatContextMenuItem
->SetEnabled(notMountedAndWritable
737 && fFormatContextMenuItem
->CountItems() > 0);
738 fChangeContextMenuItem
->SetEnabled(notMountedAndWritable
);
739 fDeleteContextMenuItem
->SetEnabled(notMountedAndWritable
740 && !partition
->IsDevice());
741 fMountContextMenuItem
->SetEnabled(notMountedAndWritable
);
743 bool unMountable
= false;
744 if (partition
->IsMounted()) {
745 // see if this partition is the boot volume
748 if (BVolumeRoster().GetBootVolume(&bootVolume
) == B_OK
749 && partition
->GetVolume(&volume
) == B_OK
) {
750 unMountable
= volume
!= bootVolume
;
754 fUnmountMenuItem
->SetEnabled(unMountable
);
755 fUnmountContextMenuItem
->SetEnabled(unMountable
);
757 fDeleteMenuItem
->SetEnabled(false);
758 fChangeMenuItem
->SetEnabled(false);
759 fMountMenuItem
->SetEnabled(false);
760 fFormatMenu
->SetEnabled(false);
761 fDiskInitMenu
->SetEnabled(false);
763 fDeleteContextMenuItem
->SetEnabled(false);
764 fChangeContextMenuItem
->SetEnabled(false);
765 fMountContextMenuItem
->SetEnabled(false);
766 fFormatContextMenuItem
->SetEnabled(false);
770 disk
->CancelModifications();
772 fMountAllMenuItem
->SetEnabled(true);
774 if (selectedPartition
< 0) {
775 fDeleteMenuItem
->SetEnabled(false);
776 fChangeMenuItem
->SetEnabled(false);
777 fMountMenuItem
->SetEnabled(false);
779 fDeleteContextMenuItem
->SetEnabled(false);
780 fChangeContextMenuItem
->SetEnabled(false);
781 fMountContextMenuItem
->SetEnabled(false);
787 MainWindow::_DisplayPartitionError(BString _message
,
788 const BPartition
* partition
, status_t error
) const
792 if (partition
&& _message
.FindFirst("%s") >= 0) {
794 name
<< "\"" << partition
->ContentName() << "\"";
795 snprintf(message
, sizeof(message
), _message
.String(), name
.String());
797 _message
.ReplaceAll("%s", "");
798 snprintf(message
, sizeof(message
), _message
.String());
802 BString helper
= message
;
803 const char* errorString
804 = B_TRANSLATE_COMMENT("Error: ", "in any error alert");
805 snprintf(message
, sizeof(message
), "%s\n\n%s%s", helper
.String(),
806 errorString
, strerror(error
));
809 BAlert
* alert
= new BAlert("error", message
, B_TRANSLATE("OK"), NULL
, NULL
,
810 B_WIDTH_FROM_WIDEST
, error
< B_OK
? B_STOP_ALERT
: B_INFO_ALERT
);
811 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
820 MainWindow::_Mount(BDiskDevice
* disk
, partition_id selectedPartition
)
822 if (!disk
|| selectedPartition
< 0) {
823 _DisplayPartitionError(B_TRANSLATE("You need to select a partition "
824 "entry from the list."));
828 BPartition
* partition
= disk
->FindDescendant(selectedPartition
);
830 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected "
831 "partition by ID."));
835 if (!partition
->IsMounted()) {
836 status_t status
= partition
->Mount();
837 if (status
!= B_OK
) {
838 _DisplayPartitionError(B_TRANSLATE("Could not mount partition %s."),
841 // successful mount, adapt to the changes
845 _DisplayPartitionError(
846 B_TRANSLATE("The partition %s is already mounted."), partition
);
852 MainWindow::_Unmount(BDiskDevice
* disk
, partition_id selectedPartition
)
854 if (!disk
|| selectedPartition
< 0) {
855 _DisplayPartitionError(B_TRANSLATE("You need to select a partition "
856 "entry from the list."));
860 BPartition
* partition
= disk
->FindDescendant(selectedPartition
);
862 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected "
863 "partition by ID."));
867 if (partition
->IsMounted()) {
869 partition
->GetMountPoint(&path
);
870 status_t status
= partition
->Unmount();
871 if (status
!= B_OK
) {
872 BString message
= B_TRANSLATE("Could not unmount partition");
873 message
<< " \"" << partition
->ContentName() << "\":\n\t"
874 << strerror(status
) << "\n\n"
875 << B_TRANSLATE("Should unmounting be forced?\n\n"
876 "Note: If an application is currently writing to the volume, "
877 "unmounting it now might result in loss of data.\n");
879 BAlert
* alert
= new BAlert(B_TRANSLATE("Force unmount"), message
,
880 B_TRANSLATE("Cancel"), B_TRANSLATE("Force unmount"), NULL
,
881 B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
882 alert
->SetShortcut(0, B_ESCAPE
);
884 if (alert
->Go() == 1)
885 status
= partition
->Unmount(B_FORCE_UNMOUNT
);
890 if (status
!= B_OK
) {
891 _DisplayPartitionError(
892 B_TRANSLATE("Could not unmount partition %s."),
895 if (dev_for_path(path
.Path()) == dev_for_path("/"))
897 // successful unmount, adapt to the changes
901 _DisplayPartitionError(
902 B_TRANSLATE("The partition %s is already unmounted."),
909 MainWindow::_MountAll()
911 MountAllVisitor visitor
;
912 fDiskDeviceRoster
.VisitEachPartition(&visitor
);
920 MainWindow::_Initialize(BDiskDevice
* disk
, partition_id selectedPartition
,
921 const BString
& diskSystemName
)
923 if (!disk
|| selectedPartition
< 0) {
924 _DisplayPartitionError(B_TRANSLATE("You need to select a partition "
925 "entry from the list."));
929 if (disk
->IsReadOnly()) {
930 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only."));
934 BPartition
* partition
= disk
->FindDescendant(selectedPartition
);
936 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected "
937 "partition by ID."));
941 if (partition
->IsMounted()) {
942 _DisplayPartitionError(
943 B_TRANSLATE("The partition %s is currently mounted."));
944 // TODO: option to unmount and continue on success to unmount
948 BDiskSystem diskSystem
;
949 fDiskDeviceRoster
.RewindDiskSystems();
951 while (fDiskDeviceRoster
.GetNextDiskSystem(&diskSystem
) == B_OK
) {
952 if (diskSystem
.SupportsInitializing()) {
953 if (diskSystemName
== diskSystem
.PrettyName()) {
963 snprintf(message
, sizeof(message
), B_TRANSLATE("Disk system \"%s\" "
965 _DisplayPartitionError(message
);
969 if (diskSystem
.IsFileSystem()) {
970 if (disk
->ID() == selectedPartition
) {
971 snprintf(message
, sizeof(message
), B_TRANSLATE("Are you sure you "
972 "want to format a raw disk? (Most people initialize the disk "
973 "with a partitioning system first) You will be asked "
974 "again before changes are written to the disk."));
975 } else if (partition
->ContentName()
976 && strlen(partition
->ContentName()) > 0) {
977 snprintf(message
, sizeof(message
), B_TRANSLATE("Are you sure you "
978 "want to format the partition \"%s\"? You will be asked "
979 "again before changes are written to the disk."),
980 partition
->ContentName());
982 snprintf(message
, sizeof(message
), B_TRANSLATE("Are you sure you "
983 "want to format the partition? You will be asked again "
984 "before changes are written to the disk."));
987 snprintf(message
, sizeof(message
), B_TRANSLATE("Are you sure you "
988 "want to initialize the selected disk? All data will be lost. "
989 "You will be asked again before changes are written to the "
992 BAlert
* alert
= new BAlert("first notice", message
,
993 B_TRANSLATE("Continue"), B_TRANSLATE("Cancel"), NULL
,
994 B_WIDTH_FROM_WIDEST
, B_WARNING_ALERT
);
995 alert
->SetShortcut(1, B_ESCAPE
);
996 int32 choice
= alert
->Go();
1001 ModificationPreparer
modificationPreparer(disk
);
1002 status_t status
= modificationPreparer
.ModificationStatus();
1003 if (status
!= B_OK
) {
1004 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the "
1005 "disk for modifications."), NULL
, status
);
1011 InitParametersPanel
* panel
= new InitParametersPanel(this, diskSystemName
,
1013 if (panel
->Go(name
, parameters
) != B_OK
)
1016 bool supportsName
= diskSystem
.SupportsContentName();
1017 BString
validatedName(name
);
1018 status
= partition
->ValidateInitialize(diskSystem
.PrettyName(),
1019 supportsName
? &validatedName
: NULL
, parameters
.String());
1020 if (status
!= B_OK
) {
1021 _DisplayPartitionError(B_TRANSLATE("Validation of the given "
1022 "initialization parameters failed."), partition
, status
);
1026 BString previousName
= partition
->ContentName();
1028 status
= partition
->Initialize(diskSystem
.PrettyName(),
1029 supportsName
? validatedName
.String() : NULL
, parameters
.String());
1030 if (status
!= B_OK
) {
1031 _DisplayPartitionError(B_TRANSLATE("Initialization of the partition "
1032 "%s failed. (Nothing has been written to disk.)"), partition
,
1037 // Also set the partition name in the partition table if supported
1038 if (partition
->CanSetName()
1039 && partition
->ValidateSetName(&validatedName
) == B_OK
) {
1040 partition
->SetName(validatedName
.String());
1043 // everything looks fine, we are ready to actually write the changes
1046 // Warn the user one more time...
1047 if (previousName
.Length() > 0) {
1048 if (partition
->IsDevice()) {
1049 snprintf(message
, sizeof(message
), B_TRANSLATE("Are you sure you "
1050 "want to write the changes back to disk now?\n\n"
1051 "All data on the disk %s will be irretrievably lost if you "
1052 "do so!"), previousName
.String());
1054 snprintf(message
, sizeof(message
), B_TRANSLATE("Are you sure you "
1055 "want to write the changes back to disk now?\n\n"
1056 "All data on the partition %s will be irretrievably lost if you "
1057 "do so!"), previousName
.String());
1060 if (partition
->IsDevice()) {
1061 snprintf(message
, sizeof(message
), B_TRANSLATE("Are you sure you "
1062 "want to write the changes back to disk now?\n\n"
1063 "All data on the selected disk will be irretrievably lost if "
1066 snprintf(message
, sizeof(message
), B_TRANSLATE("Are you sure you "
1067 "want to write the changes back to disk now?\n\n"
1068 "All data on the selected partition will be irretrievably lost "
1072 alert
= new BAlert("final notice", message
,
1073 B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL
,
1074 B_WIDTH_FROM_WIDEST
, B_WARNING_ALERT
);
1075 alert
->SetShortcut(1, B_ESCAPE
);
1076 choice
= alert
->Go();
1082 status
= modificationPreparer
.CommitModifications();
1084 // The partition pointer is toast now! Use the partition ID to
1085 // retrieve it again.
1086 partition
= disk
->FindDescendant(selectedPartition
);
1088 if (status
== B_OK
) {
1089 if (diskSystem
.IsFileSystem()) {
1090 _DisplayPartitionError(B_TRANSLATE("The partition %s has been "
1091 "successfully formatted.\n"), partition
);
1093 _DisplayPartitionError(B_TRANSLATE("The disk has been "
1094 "successfully initialized.\n"), partition
);
1097 if (diskSystem
.IsFileSystem()) {
1098 _DisplayPartitionError(B_TRANSLATE("Failed to format the "
1099 "partition %s!\n"), partition
, status
);
1101 _DisplayPartitionError(B_TRANSLATE("Failed to initialize the "
1102 "disk %s!\n"), partition
, status
);
1111 MainWindow::_Create(BDiskDevice
* disk
, partition_id selectedPartition
)
1113 if (!disk
|| selectedPartition
> -2) {
1114 _DisplayPartitionError(B_TRANSLATE("The currently selected partition "
1119 if (disk
->IsReadOnly()) {
1120 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only."));
1124 PartitionListRow
* currentSelection
= dynamic_cast<PartitionListRow
*>(
1125 fListView
->CurrentSelection());
1126 if (!currentSelection
) {
1127 _DisplayPartitionError(B_TRANSLATE("There was an error acquiring the "
1132 BPartition
* parent
= disk
->FindDescendant(currentSelection
->ParentID());
1134 _DisplayPartitionError(B_TRANSLATE("The currently selected partition "
1135 "does not have a parent partition."));
1139 if (!parent
->ContainsPartitioningSystem()) {
1140 _DisplayPartitionError(B_TRANSLATE("The selected partition does not "
1141 "contain a partitioning system."));
1145 ModificationPreparer
modificationPreparer(disk
);
1146 status_t status
= modificationPreparer
.ModificationStatus();
1147 if (status
!= B_OK
) {
1148 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the "
1149 "disk for modifications."), NULL
, status
);
1153 // get partitioning info
1154 BPartitioningInfo partitioningInfo
;
1155 status_t error
= parent
->GetPartitioningInfo(&partitioningInfo
);
1156 if (error
!= B_OK
) {
1157 _DisplayPartitionError(B_TRANSLATE("Could not acquire partitioning "
1162 int32 spacesCount
= partitioningInfo
.CountPartitionableSpaces();
1163 if (spacesCount
== 0) {
1164 _DisplayPartitionError(B_TRANSLATE("There's no space on the partition "
1165 "where a child partition could be created."));
1169 BString name
, type
, parameters
;
1170 off_t offset
= currentSelection
->Offset();
1171 off_t size
= currentSelection
->Size();
1173 CreateParametersPanel
* panel
= new CreateParametersPanel(this, parent
,
1175 status
= panel
->Go(offset
, size
, name
, type
, parameters
);
1176 if (status
!= B_OK
) {
1177 if (status
!= B_CANCELED
) {
1178 _DisplayPartitionError(B_TRANSLATE("The panel could not return "
1179 "successfully."), NULL
, status
);
1184 status
= parent
->ValidateCreateChild(&offset
, &size
, type
.String(),
1185 &name
, parameters
.String());
1187 if (status
!= B_OK
) {
1188 _DisplayPartitionError(B_TRANSLATE("Validation of the given creation "
1189 "parameters failed."), NULL
, status
);
1193 // Warn the user one more time...
1194 BAlert
* alert
= new BAlert("final notice", B_TRANSLATE("Are you sure you "
1195 "want to write the changes back to disk now?\n\n"
1196 "All data on the partition will be irretrievably lost if you do "
1197 "so!"), B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL
,
1198 B_WIDTH_FROM_WIDEST
, B_WARNING_ALERT
);
1199 alert
->SetShortcut(1, B_ESCAPE
);
1200 int32 choice
= alert
->Go();
1205 status
= parent
->CreateChild(offset
, size
, type
.String(), name
.String(),
1206 parameters
.String());
1208 if (status
!= B_OK
) {
1209 _DisplayPartitionError(B_TRANSLATE("Creation of the partition has "
1210 "failed."), NULL
, status
);
1215 status
= modificationPreparer
.CommitModifications();
1217 if (status
!= B_OK
) {
1218 _DisplayPartitionError(B_TRANSLATE("Failed to format the "
1219 "partition. No changes have been written to disk."), NULL
, status
);
1223 // The disk layout has changed, update disk information
1225 status
= disk
->Update(&updated
);
1228 fDiskView
->ForceUpdate();
1233 MainWindow::_Delete(BDiskDevice
* disk
, partition_id selectedPartition
)
1235 if (!disk
|| selectedPartition
< 0) {
1236 _DisplayPartitionError(B_TRANSLATE("You need to select a partition "
1237 "entry from the list."));
1241 if (disk
->IsReadOnly()) {
1242 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only."));
1246 BPartition
* partition
= disk
->FindDescendant(selectedPartition
);
1248 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected "
1249 "partition by ID."));
1253 BPartition
* parent
= partition
->Parent();
1255 _DisplayPartitionError(B_TRANSLATE("The currently selected partition "
1256 "does not have a parent partition."));
1260 ModificationPreparer
modificationPreparer(disk
);
1261 status_t status
= modificationPreparer
.ModificationStatus();
1262 if (status
!= B_OK
) {
1263 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the "
1264 "disk for modifications."), NULL
, status
);
1268 if (!parent
->CanDeleteChild(partition
->Index())) {
1269 _DisplayPartitionError(
1270 B_TRANSLATE("Cannot delete the selected partition."));
1274 // Warn the user one more time...
1275 BAlert
* alert
= new BAlert("final notice", B_TRANSLATE("Are you sure you "
1276 "want to delete the selected partition?\n\n"
1277 "All data on the partition will be irretrievably lost if you "
1278 "do so!"), B_TRANSLATE("Delete partition"), B_TRANSLATE("Cancel"), NULL
,
1279 B_WIDTH_FROM_WIDEST
, B_WARNING_ALERT
);
1280 alert
->SetShortcut(1, B_ESCAPE
);
1281 int32 choice
= alert
->Go();
1286 status
= parent
->DeleteChild(partition
->Index());
1287 if (status
!= B_OK
) {
1288 _DisplayPartitionError(B_TRANSLATE("Could not delete the selected "
1289 "partition."), NULL
, status
);
1293 status
= modificationPreparer
.CommitModifications();
1295 if (status
!= B_OK
) {
1296 _DisplayPartitionError(B_TRANSLATE("Failed to delete the partition. "
1297 "No changes have been written to disk."), NULL
, status
);
1302 fDiskView
->ForceUpdate();
1307 MainWindow::_ChangeParameters(BDiskDevice
* disk
, partition_id selectedPartition
)
1309 if (disk
== NULL
|| selectedPartition
< 0) {
1310 _DisplayPartitionError(B_TRANSLATE("You need to select a partition "
1311 "entry from the list."));
1315 if (disk
->IsReadOnly()) {
1316 _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only."));
1320 BPartition
* partition
= disk
->FindDescendant(selectedPartition
);
1321 if (partition
== NULL
) {
1322 _DisplayPartitionError(B_TRANSLATE("Unable to find the selected "
1323 "partition by ID."));
1327 ModificationPreparer
modificationPreparer(disk
);
1328 status_t status
= modificationPreparer
.ModificationStatus();
1329 if (status
!= B_OK
) {
1330 _DisplayPartitionError(B_TRANSLATE("There was an error preparing the "
1331 "disk for modifications."), NULL
, status
);
1335 ChangeParametersPanel
* panel
= new ChangeParametersPanel(this, partition
);
1337 BString name
, type
, parameters
;
1338 status
= panel
->Go(name
, type
, parameters
);
1339 if (status
!= B_OK
) {
1340 if (status
!= B_CANCELED
) {
1341 _DisplayPartitionError(B_TRANSLATE("The panel experienced a "
1342 "problem!"), NULL
, status
);
1344 // TODO: disk systems without an editor and support for name/type
1345 // changing will return B_CANCELED here -- we need to check this
1346 // before, and disable the menu entry instead
1350 if (partition
->CanSetType())
1351 status
= partition
->ValidateSetType(type
.String());
1352 if (status
== B_OK
&& partition
->CanSetName())
1353 status
= partition
->ValidateSetName(&name
);
1354 if (status
!= B_OK
) {
1355 _DisplayPartitionError(B_TRANSLATE("Validation of the given parameters "
1360 // Warn the user one more time...
1361 BAlert
* alert
= new BAlert("final notice", B_TRANSLATE("Are you sure you "
1362 "want to change parameters of the selected partition?\n\n"
1363 "The partition may no longer be recognized by other operating systems "
1364 "anymore!"), B_TRANSLATE("Change parameters"), B_TRANSLATE("Cancel"),
1365 NULL
, B_WIDTH_FROM_WIDEST
, B_WARNING_ALERT
);
1366 alert
->SetShortcut(1, B_ESCAPE
);
1367 int32 choice
= alert
->Go();
1372 if (partition
->CanSetType())
1373 status
= partition
->SetType(type
.String());
1374 if (status
== B_OK
&& partition
->CanSetName())
1375 status
= partition
->SetName(name
.String());
1376 if (status
== B_OK
&& partition
->CanEditParameters())
1377 status
= partition
->SetParameters(parameters
.String());
1379 if (status
!= B_OK
) {
1380 _DisplayPartitionError(
1381 B_TRANSLATE("Could not change the parameters of the selected "
1382 "partition."), NULL
, status
);
1386 status
= modificationPreparer
.CommitModifications();
1388 if (status
!= B_OK
) {
1389 _DisplayPartitionError(B_TRANSLATE("Failed to change the parameters "
1390 "of the partition. No changes have been written to disk."), NULL
,
1396 fDiskView
->ForceUpdate();
1401 MainWindow::_ColumnListViewHeight(BColumnListView
* list
, BRow
* currentRow
)
1404 int32 rows
= list
->CountRows(currentRow
);
1405 for (int32 i
= 0; i
< rows
; i
++) {
1406 BRow
* row
= list
->RowAt(i
, currentRow
);
1407 height
+= row
->Height() + 1;
1408 if (row
->IsExpanded() && list
->CountRows(row
) > 0)
1409 height
+= _ColumnListViewHeight(list
, row
);
1416 MainWindow::_UpdateWindowZoomLimits()
1418 float maxHeight
= 0;
1419 int32 numColumns
= fListView
->CountColumns();
1420 BRow
* parentRow
= NULL
;
1421 BColumn
* column
= NULL
;
1423 maxHeight
+= _ColumnListViewHeight(fListView
, NULL
);
1425 float maxWidth
= fListView
->LatchWidth();
1426 for (int32 i
= 0; i
< numColumns
; i
++) {
1427 column
= fListView
->ColumnAt(i
);
1428 maxWidth
+= column
->Width();
1431 parentRow
= fListView
->RowAt(0, NULL
);
1432 maxHeight
+= B_H_SCROLL_BAR_HEIGHT
;
1433 maxHeight
+= 1.5 * parentRow
->Height(); // the label row
1434 maxHeight
+= fDiskView
->Bounds().Height();
1435 maxHeight
+= fMenuBar
->Bounds().Height();
1436 maxWidth
+= 1.5 * B_V_SCROLL_BAR_WIDTH
; // scroll bar & borders
1438 SetZoomLimits(maxWidth
, maxHeight
);