xref: /haiku/src/apps/drivesetup/MainWindow.cpp (revision 5c38863b713405b10d72dc79afc7a8589bb6a11c)
1 /*
2  * Copyright 2002-2009 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Erik Jaesler <ejakowatz@users.sourceforge.net>
7  *		Ithamar R. Adema <ithamar@unet.nl>
8  *		Stephan Aßmus <superstippi@gmx.de>
9  */
10 
11 #include "MainWindow.h"
12 #include "DiskView.h"
13 #include "InitParamsPanel.h"
14 #include "PartitionList.h"
15 #include "Support.h"
16 #include "tracker_private.h"
17 
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include <Alert.h>
22 #include <Application.h>
23 #include <ColumnListView.h>
24 #include <ColumnTypes.h>
25 #include <DiskDevice.h>
26 #include <DiskDeviceVisitor.h>
27 #include <DiskSystem.h>
28 #include <MenuItem.h>
29 #include <MenuBar.h>
30 #include <Menu.h>
31 #include <Path.h>
32 #include <Partition.h>
33 #include <PartitioningInfo.h>
34 #include <Roster.h>
35 #include <Screen.h>
36 #include <Volume.h>
37 #include <VolumeRoster.h>
38 
39 
40 class ListPopulatorVisitor : public BDiskDeviceVisitor {
41 public:
42 	ListPopulatorVisitor(PartitionListView* list, int32& diskCount,
43 			SpaceIDMap& spaceIDMap)
44 		:
45 		fPartitionList(list),
46 		fDiskCount(diskCount),
47 		fSpaceIDMap(spaceIDMap)
48 	{
49 		fDiskCount = 0;
50 		fSpaceIDMap.Clear();
51 		// start with an empty list
52 		int32 rows = fPartitionList->CountRows();
53 		for (int32 i = rows - 1; i >= 0; i--) {
54 			BRow* row = fPartitionList->RowAt(i);
55 			fPartitionList->RemoveRow(row);
56 			delete row;
57 		}
58 	}
59 
60 	virtual bool Visit(BDiskDevice* device)
61 	{
62 		fDiskCount++;
63 		// if we don't prepare the device for modifications,
64 		// we cannot get information about available empty
65 		// regions on the device or child partitions
66 		device->PrepareModifications();
67 		_AddPartition(device);
68 		return false; // Don't stop yet!
69 	}
70 
71 	virtual bool Visit(BPartition* partition, int32 level)
72 	{
73 		_AddPartition(partition);
74 		return false; // Don't stop yet!
75 	}
76 
77 private:
78 	void _AddPartition(BPartition* partition) const
79 	{
80 		// add the partition itself
81 		fPartitionList->AddPartition(partition);
82 
83 		// add any available space on it
84 		BPartitioningInfo info;
85 		status_t ret = partition->GetPartitioningInfo(&info);
86 		if (ret >= B_OK) {
87 			partition_id parentID = partition->ID();
88 			off_t offset;
89 			off_t size;
90 			for (int32 i = 0;
91 				info.GetPartitionableSpaceAt(i, &offset, &size) >= B_OK;
92 				i++) {
93 				// TODO: remove again once Disk Device API is fixed
94 				if (!is_valid_partitionable_space(size))
95 					continue;
96 				//
97 				partition_id id = fSpaceIDMap.SpaceIDFor(parentID, offset);
98 				fPartitionList->AddSpace(parentID, id, offset, size);
99 			}
100 		}
101 	}
102 
103 	PartitionListView*	fPartitionList;
104 	int32&				fDiskCount;
105 	SpaceIDMap&			fSpaceIDMap;
106 	BDiskDevice*		fLastPreparedDevice;
107 };
108 
109 
110 class MountAllVisitor : public BDiskDeviceVisitor {
111 public:
112 	MountAllVisitor()
113 	{
114 	}
115 
116 	virtual bool Visit(BDiskDevice* device)
117 	{
118 		return false; // Don't stop yet!
119 	}
120 
121 	virtual bool Visit(BPartition* partition, int32 level)
122 	{
123 		partition->Mount();
124 		return false; // Don't stop yet!
125 	}
126 
127 private:
128 	PartitionListView* fPartitionList;
129 };
130 
131 
132 enum {
133 	MSG_MOUNT_ALL				= 'mnta',
134 	MSG_MOUNT					= 'mnts',
135 	MSG_UNMOUNT					= 'unmt',
136 	MSG_FORMAT					= 'frmt',
137 	MSG_CREATE					= 'crtp',
138 	MSG_INITIALIZE				= 'init',
139 	MSG_DELETE					= 'delt',
140 	MSG_EJECT					= 'ejct',
141 	MSG_SURFACE_TEST			= 'sfct',
142 	MSG_RESCAN					= 'rscn',
143 
144 	MSG_PARTITION_ROW_SELECTED	= 'prsl',
145 };
146 
147 
148 // #pragma mark -
149 
150 
151 MainWindow::MainWindow(BRect frame)
152 	: BWindow(frame, "DriveSetup", B_DOCUMENT_WINDOW,
153 		B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE),
154 	fCurrentDisk(NULL),
155 	fCurrentPartitionID(-1),
156 	fSpaceIDMap()
157 {
158 	BMenuBar* menuBar = new BMenuBar(Bounds(), "root menu");
159 
160 	// create all the menu items
161 	fFormatMI = new BMenuItem("Format (not implemented)",
162 		new BMessage(MSG_FORMAT));
163 	fEjectMI = new BMenuItem("Eject", new BMessage(MSG_EJECT), 'E');
164 	fSurfaceTestMI = new BMenuItem("Surface Test (not implemented)",
165 		new BMessage(MSG_SURFACE_TEST));
166 	fRescanMI = new BMenuItem("Rescan", new BMessage(MSG_RESCAN));
167 
168 	fDeleteMI = new BMenuItem("Delete (not implemented)",
169 		new BMessage(MSG_DELETE));
170 	fDeleteMI->SetEnabled(false);
171 
172 	fMountMI = new BMenuItem("Mount", new BMessage(MSG_MOUNT), 'M');
173 	fUnmountMI = new BMenuItem("Unmount", new BMessage(MSG_UNMOUNT), 'U');
174 	fMountAllMI = new BMenuItem("Mount All",
175 		new BMessage(MSG_MOUNT_ALL), 'M', B_SHIFT_KEY);
176 
177 	// Disk menu
178 	fDiskMenu = new BMenu("Disk");
179 	fDiskMenu->AddItem(fFormatMI);
180 	fDiskMenu->AddItem(fEjectMI);
181 	fDiskMenu->AddItem(fSurfaceTestMI);
182 
183 	fDiskMenu->AddSeparatorItem();
184 
185 	fDiskMenu->AddItem(fRescanMI);
186 	menuBar->AddItem(fDiskMenu);
187 
188 	// Parition menu
189 	fPartitionMenu = new BMenu("Partition");
190 	fCreateMenu = new BMenu("Create (not implemented)");
191 	fPartitionMenu->AddItem(fCreateMenu);
192 
193 	fInitMenu = new BMenu("Initialize");
194 	fPartitionMenu->AddItem(fInitMenu);
195 
196 	fPartitionMenu->AddItem(fDeleteMI);
197 
198 	fPartitionMenu->AddSeparatorItem();
199 
200 	fPartitionMenu->AddItem(fMountMI);
201 	fPartitionMenu->AddItem(fUnmountMI);
202 
203 	fPartitionMenu->AddSeparatorItem();
204 
205 	fPartitionMenu->AddItem(fMountAllMI);
206 	menuBar->AddItem(fPartitionMenu);
207 
208 	AddChild(menuBar);
209 
210 	// add DiskView
211 	BRect r(Bounds());
212 	r.top = menuBar->Frame().bottom + 1;
213 	r.bottom = floorf(r.top + r.Height() * 0.33);
214 	fDiskView = new DiskView(r, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
215 		fSpaceIDMap);
216 	AddChild(fDiskView);
217 
218 	// add PartitionListView
219 	r.top = r.bottom + 2;
220 	r.bottom = Bounds().bottom;
221 	r.InsetBy(-1, -1);
222 	fListView = new PartitionListView(r, B_FOLLOW_ALL);
223 	AddChild(fListView);
224 
225 	// configure PartitionListView
226 	fListView->SetSelectionMessage(new BMessage(MSG_PARTITION_ROW_SELECTED));
227 	fListView->SetTarget(this);
228 
229 	BDiskDeviceRoster().StartWatching(this);
230 
231 	// populate the Initialiaze menu with the available file systems
232 	_ScanFileSystems();
233 
234 	// visit all disks in the system and show their contents
235 	_ScanDrives();
236 
237 	if (!be_roster->IsRunning(kDeskbarSignature))
238 		SetFlags(Flags() | B_NOT_MINIMIZABLE);
239 }
240 
241 
242 MainWindow::~MainWindow()
243 {
244 	BDiskDeviceRoster().StopWatching(this);
245 	delete fCurrentDisk;
246 }
247 
248 
249 void
250 MainWindow::MessageReceived(BMessage* message)
251 {
252 	switch (message->what) {
253 		case MSG_MOUNT_ALL:
254 			_MountAll();
255 			break;
256 		case MSG_MOUNT:
257 			_Mount(fCurrentDisk, fCurrentPartitionID);
258 			break;
259 		case MSG_UNMOUNT:
260 			_Unmount(fCurrentDisk, fCurrentPartitionID);
261 			break;
262 
263 		case MSG_FORMAT:
264 			printf("MSG_FORMAT\n");
265 			break;
266 
267 		case MSG_CREATE:
268 			printf("MSG_CREATE\n");
269 			break;
270 
271 		case MSG_INITIALIZE: {
272 			BString diskSystemName;
273 			if (message->FindString("format", &diskSystemName) != B_OK)
274 				break;
275 			_Initialize(fCurrentDisk, fCurrentPartitionID, diskSystemName);
276 			break;
277 		}
278 
279 		case MSG_DELETE:
280 			printf("MSG_DELETE\n");
281 			break;
282 
283 		case MSG_EJECT:
284 			// TODO: completely untested, especially interesting
285 			// if partition list behaves when partitions disappear
286 			if (fCurrentDisk) {
287 				// TODO: only if no partitions are mounted anymore?
288 				fCurrentDisk->Eject(true);
289 				_ScanDrives();
290 			}
291 			break;
292 		case MSG_SURFACE_TEST:
293 			printf("MSG_SURFACE_TEST\n");
294 			break;
295 
296 		// TODO: this could probably be done better!
297 		case B_DEVICE_UPDATE:
298 		case MSG_RESCAN:
299 			_ScanDrives();
300 			break;
301 
302 		case MSG_PARTITION_ROW_SELECTED:
303 			// selection of partitions via list view
304 			_AdaptToSelectedPartition();
305 			break;
306 		case MSG_SELECTED_PARTITION_ID: {
307 			// selection of partitions via disk view
308 			partition_id id;
309 			if (message->FindInt32("partition_id", &id) == B_OK) {
310 				if (BRow* row = fListView->FindRow(id)) {
311 					fListView->DeselectAll();
312 					fListView->AddToSelection(row);
313 					_AdaptToSelectedPartition();
314 				}
315 			}
316 			break;
317 		}
318 
319 		default:
320 			BWindow::MessageReceived(message);
321 			break;
322 	}
323 }
324 
325 
326 bool
327 MainWindow::QuitRequested()
328 {
329 	// TODO: ask about any unsaved changes
330 	be_app->PostMessage(B_QUIT_REQUESTED);
331 	Hide();
332 	return false;
333 }
334 
335 
336 // #pragma mark -
337 
338 
339 status_t
340 MainWindow::StoreSettings(BMessage* archive) const
341 {
342 	if (archive->ReplaceRect("window frame", Frame()) < B_OK)
343 		archive->AddRect("window frame", Frame());
344 
345 	BMessage columnSettings;
346 	fListView->SaveState(&columnSettings);
347 	if (archive->ReplaceMessage("column settings", &columnSettings) < B_OK)
348 		archive->AddMessage("column settings", &columnSettings);
349 
350 	return B_OK;
351 }
352 
353 
354 status_t
355 MainWindow::RestoreSettings(BMessage* archive)
356 {
357 	BRect frame;
358 	if (archive->FindRect("window frame", &frame) == B_OK) {
359 		BScreen screen(this);
360 		if (frame.Intersects(screen.Frame())) {
361 			MoveTo(frame.LeftTop());
362 			ResizeTo(frame.Width(), frame.Height());
363 		}
364 	}
365 
366 	BMessage columnSettings;
367 	if (archive->FindMessage("column settings", &columnSettings) == B_OK)
368 		fListView->LoadState(&columnSettings);
369 
370 	return B_OK;
371 }
372 
373 
374 // #pragma mark -
375 
376 
377 void
378 MainWindow::_ScanDrives()
379 {
380 	fSpaceIDMap.Clear();
381 	int32 diskCount = 0;
382 	ListPopulatorVisitor driveVisitor(fListView, diskCount, fSpaceIDMap);
383 	fDDRoster.VisitEachPartition(&driveVisitor);
384 	fDiskView->SetDiskCount(diskCount);
385 
386 	// restore selection
387 	PartitionListRow* previousSelection
388 		= fListView->FindRow(fCurrentPartitionID);
389 	if (previousSelection) {
390 		fListView->AddToSelection(previousSelection);
391 		_EnabledDisableMenuItems(fCurrentDisk, fCurrentPartitionID,
392 			previousSelection->ParentID());
393 		fDiskView->ForceUpdate();
394 	} else {
395 		_EnabledDisableMenuItems(NULL, -1, -1);
396 	}
397 }
398 
399 
400 void
401 MainWindow::_ScanFileSystems()
402 {
403 	while (BMenuItem* item = fInitMenu->RemoveItem(0L))
404 		delete item;
405 
406 	BDiskSystem diskSystem;
407 	fDDRoster.RewindDiskSystems();
408 	while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) {
409 		if (diskSystem.IsFileSystem() && diskSystem.SupportsInitializing()) {
410 			BMessage* message = new BMessage(MSG_INITIALIZE);
411 			message->AddString("format", diskSystem.PrettyName());
412 			BString label = diskSystem.PrettyName();
413 			label << B_UTF8_ELLIPSIS;
414 			fInitMenu->AddItem(new BMenuItem(label.String(), message));
415 		}
416 	}
417 }
418 
419 
420 // #pragma mark -
421 
422 
423 void
424 MainWindow::_AdaptToSelectedPartition()
425 {
426 	partition_id diskID = -1;
427 	partition_id partitionID = -1;
428 	partition_id parentID = -1;
429 
430 	BRow* _selectedRow = fListView->CurrentSelection();
431 	if (_selectedRow) {
432 		// go up to top level row
433 		BRow* _topLevelRow = _selectedRow;
434 		BRow* parent = NULL;
435 		while (fListView->FindParent(_topLevelRow, &parent, NULL))
436 			_topLevelRow = parent;
437 
438 		PartitionListRow* topLevelRow
439 			= dynamic_cast<PartitionListRow*>(_topLevelRow);
440 		PartitionListRow* selectedRow
441 			= dynamic_cast<PartitionListRow*>(_selectedRow);
442 
443 		if (topLevelRow)
444 			diskID = topLevelRow->ID();
445 		if (selectedRow) {
446 			partitionID = selectedRow->ID();
447 			parentID = selectedRow->ParentID();
448 		}
449 	}
450 
451 	_SetToDiskAndPartition(diskID, partitionID, parentID);
452 }
453 
454 
455 void
456 MainWindow::_SetToDiskAndPartition(partition_id disk, partition_id partition,
457 	partition_id parent)
458 {
459 	BDiskDevice* oldDisk = NULL;
460 	if (!fCurrentDisk || fCurrentDisk->ID() != disk) {
461 		oldDisk = fCurrentDisk;
462 		fCurrentDisk = NULL;
463 		if (disk >= 0) {
464 			BDiskDevice* newDisk = new BDiskDevice();
465 			status_t ret = newDisk->SetTo(disk);
466 			if (ret < B_OK) {
467 				printf("error switching disks: %s\n", strerror(ret));
468 				delete newDisk;
469 			} else
470 				fCurrentDisk = newDisk;
471 		}
472 	}
473 
474 	fCurrentPartitionID = partition;
475 
476 	fDiskView->SetDisk(fCurrentDisk, fCurrentPartitionID);
477 	_EnabledDisableMenuItems(fCurrentDisk, fCurrentPartitionID, parent);
478 
479 	delete oldDisk;
480 }
481 
482 
483 void
484 MainWindow::_EnabledDisableMenuItems(BDiskDevice* disk,
485 	partition_id selectedPartition, partition_id parentID)
486 {
487 	// clean out Create menu
488 	while (BMenuItem* item = fCreateMenu->RemoveItem(0L))
489 		delete item;
490 
491 	if (!disk) {
492 		fFormatMI->SetEnabled(false);
493 		fEjectMI->SetEnabled(false);
494 		fSurfaceTestMI->SetEnabled(false);
495 
496 		fPartitionMenu->SetEnabled(false);
497 	} else {
498 //		fFormatMI->SetEnabled(true);
499 		fFormatMI->SetEnabled(false);
500 		fEjectMI->SetEnabled(disk->IsRemovableMedia());
501 //		fSurfaceTestMI->SetEnabled(true);
502 		fSurfaceTestMI->SetEnabled(false);
503 
504 		// Create menu and items
505 		fPartitionMenu->SetEnabled(true);
506 
507 		BPartition* parentPartition = NULL;
508 		if (selectedPartition <= -2)
509 			parentPartition = disk->FindDescendant(parentID);
510 
511 		if (parentPartition) {
512 			bool prepared = disk->PrepareModifications() == B_OK;
513 			fCreateMenu->SetEnabled(true);
514 			BString supportedChildType;
515 			int32 cookie = 0;
516 			status_t ret;
517 			while ((ret = parentPartition->GetNextSupportedChildType(&cookie,
518 				&supportedChildType)) == B_OK) {
519 				BMessage* message = new BMessage(MSG_CREATE);
520 				message->AddInt32("parent id", parentID);
521 				message->AddInt32("space id", selectedPartition);
522 				message->AddString("type", supportedChildType);
523 				BMenuItem* item = new BMenuItem(supportedChildType.String(),
524 					message);
525 				fCreateMenu->AddItem(item);
526 			}
527 			if (fCreateMenu->CountItems() == 0)
528 				fprintf(stderr, "Failed to get supported child types: %s\n",
529 					strerror(ret));
530 			if (prepared)
531 				disk->CancelModifications();
532 		} else {
533 			fCreateMenu->SetEnabled(false);
534 		}
535 
536 		// Mount items
537 		BPartition* partition = disk->FindDescendant(selectedPartition);
538 		if (partition) {
539 			fInitMenu->SetEnabled(!partition->IsMounted());
540 //			fDeleteMI->SetEnabled(!partition->IsMounted());
541 			fDeleteMI->SetEnabled(false);
542 			fMountMI->SetEnabled(!partition->IsMounted());
543 
544 			bool unMountable = false;
545 			if (partition->IsMounted()) {
546 				// see if this partition is the boot volume
547 				BVolume volume;
548 				BVolume bootVolume;
549 				if (BVolumeRoster().GetBootVolume(&bootVolume) == B_OK
550 					&& partition->GetVolume(&volume) == B_OK) {
551 					unMountable = volume != bootVolume;
552 				} else
553 					unMountable = true;
554 			}
555 			fUnmountMI->SetEnabled(unMountable);
556 		} else {
557 			fInitMenu->SetEnabled(false);
558 			fDeleteMI->SetEnabled(false);
559 			fMountMI->SetEnabled(false);
560 			fUnmountMI->SetEnabled(false);
561 		}
562 		fMountAllMI->SetEnabled(true);
563 	}
564 }
565 
566 
567 void
568 MainWindow::_DisplayPartitionError(BString _message,
569 	const BPartition* partition, status_t error) const
570 {
571 	char message[1024];
572 
573 	if (partition && _message.FindFirst("%s") >= 0) {
574 		BString name;
575 		name << " \"" << partition->ContentName() << "\"";
576 		sprintf(message, _message.String(), name.String());
577 	} else {
578 		_message.ReplaceAll("%s", "");
579 		sprintf(message, _message.String());
580 	}
581 
582 	if (error < B_OK) {
583 		BString helper = message;
584 		sprintf(message, "%s\n\nError: %s", helper.String(), strerror(error));
585 	}
586 
587 	BAlert* alert = new BAlert("error", message, "Ok", NULL, NULL,
588 		B_WIDTH_FROM_WIDEST, error < B_OK ? B_STOP_ALERT : B_INFO_ALERT);
589 	alert->Go(NULL);
590 }
591 
592 
593 // #pragma mark -
594 
595 
596 void
597 MainWindow::_Mount(BDiskDevice* disk, partition_id selectedPartition)
598 {
599 	if (!disk || selectedPartition < 0) {
600 		_DisplayPartitionError("You need to select a partition "
601 			"entry from the list.");
602 		return;
603 	}
604 
605 	BPartition* partition = disk->FindDescendant(selectedPartition);
606 	if (!partition) {
607 		_DisplayPartitionError("Unable to find the selected partition by id.");
608 		return;
609 	}
610 
611 	if (!partition->IsMounted()) {
612 		status_t ret = partition->Mount();
613 		if (ret < B_OK) {
614 			_DisplayPartitionError("Could not mount partition %s.",
615 				partition, ret);
616 		} else {
617 			// successful mount, adapt to the changes
618 			_ScanDrives();
619 		}
620 	} else {
621 		_DisplayPartitionError("The partition %s is already mounted.",
622 			partition);
623 	}
624 }
625 
626 
627 void
628 MainWindow::_Unmount(BDiskDevice* disk, partition_id selectedPartition)
629 {
630 	if (!disk || selectedPartition < 0) {
631 		_DisplayPartitionError("You need to select a partition "
632 			"entry from the list.");
633 		return;
634 	}
635 
636 	BPartition* partition = disk->FindDescendant(selectedPartition);
637 	if (!partition) {
638 		_DisplayPartitionError("Unable to find the selected partition by id.");
639 		return;
640 	}
641 
642 	if (partition->IsMounted()) {
643 		BPath path;
644 		partition->GetMountPoint(&path);
645 		status_t ret = partition->Unmount();
646 		if (ret < B_OK) {
647 			_DisplayPartitionError("Could not unmount partition %s.",
648 				partition, ret);
649 		} else {
650 			if (dev_for_path(path.Path()) == dev_for_path("/"))
651 				rmdir(path.Path());
652 			// successful unmount, adapt to the changes
653 			_ScanDrives();
654 		}
655 	} else {
656 		_DisplayPartitionError("The partition %s is already unmounted.",
657 			partition);
658 	}
659 }
660 
661 
662 void
663 MainWindow::_MountAll()
664 {
665 	MountAllVisitor visitor;
666 	fDDRoster.VisitEachPartition(&visitor);
667 }
668 
669 
670 // #pragma mark -
671 
672 
673 class ModificationPreparer {
674 public:
675 	ModificationPreparer(BDiskDevice* disk)
676 		:
677 		fDisk(disk),
678 		fModificationStatus(fDisk->PrepareModifications())
679 	{
680 	}
681 	~ModificationPreparer()
682 	{
683 		if (fModificationStatus == B_OK)
684 			fDisk->CancelModifications();
685 	}
686 	status_t ModificationStatus() const
687 	{
688 		return fModificationStatus;
689 	}
690 	status_t CommitModifications()
691 	{
692 		status_t ret = fDisk->CommitModifications();
693 		if (ret == B_OK)
694 			fModificationStatus = B_ERROR;
695 		return ret;
696 	}
697 
698 private:
699 	BDiskDevice*	fDisk;
700 	status_t		fModificationStatus;
701 };
702 
703 
704 void
705 MainWindow::_Initialize(BDiskDevice* disk, partition_id selectedPartition,
706 	const BString& diskSystemName)
707 {
708 	if (!disk || selectedPartition < 0) {
709 		_DisplayPartitionError("You need to select a partition "
710 			"entry from the list.");
711 		return;
712 	}
713 
714 	if (disk->IsReadOnly()) {
715 		_DisplayPartitionError("The selected disk is read-only.");
716 		return;
717 	}
718 
719 	BPartition* partition = disk->FindDescendant(selectedPartition);
720 	if (!partition) {
721 		_DisplayPartitionError("Unable to find the selected partition by id.");
722 		return;
723 	}
724 
725 	if (partition->IsMounted()) {
726 		_DisplayPartitionError("The partition %s is currently mounted.");
727 		// TODO: option to unmount and continue on success to unmount
728 		return;
729 	}
730 
731 	BString message("Are you sure you want to initialize the partition ");
732 	message << "\"" << partition->ContentName();
733 	message << "\"? After entering the initialization parameters, ";
734 	message << "you can abort this operation right before writing ";
735 	message << "changes back to the disk.";
736 	BAlert* alert = new BAlert("first notice", message.String(),
737 		"Continue", "Cancel", NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT);
738 	int32 choice = alert->Go();
739 
740 	if (choice == 1)
741 		return;
742 
743 	BDiskSystem diskSystem;
744 	fDDRoster.RewindDiskSystems();
745 	bool found = false;
746 	while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) {
747 		if (diskSystem.IsFileSystem() && diskSystem.SupportsInitializing()) {
748 			if (diskSystemName == diskSystem.PrettyName()) {
749 				found = true;
750 				break;
751 			}
752 		}
753 	}
754 
755 	if (!found) {
756 		BString message("Disk system \"");
757 		message << diskSystemName << "\" not found!";
758 		_DisplayPartitionError(message);
759 		return;
760 	}
761 
762 
763 	// allow BFS only, since our parameter string
764 	// construction only handles BFS at the moment
765 	if (diskSystemName != "Be File System") {
766 		_DisplayPartitionError("Don't know how to construct parameters "
767 			"for this file system.");
768 		return;
769 	}
770 
771 	ModificationPreparer modificationPreparer(disk);
772 	status_t ret = modificationPreparer.ModificationStatus();
773 	if (ret != B_OK) {
774 		_DisplayPartitionError("There was an error preparing the "
775 			"disk for modifications.", NULL, ret);
776 		return;
777 	}
778 
779 	// TODO: use partition initialization editor
780 	// (partition->GetInitializationParameterEditor())
781 
782 	BString name = partition->ContentName();
783 	if (name.Length() == 0)
784 		name = "Haiku";
785 	BString parameters;
786 	InitParamsPanel* panel = new InitParamsPanel(this);
787 	if (panel->Go(name, parameters) == GO_CANCELED)
788 		return;
789 
790 	bool supportsName = diskSystem.SupportsContentName();
791 	BString validatedName(name);
792 	ret = partition->ValidateInitialize(diskSystem.PrettyName(),
793 		supportsName ? &validatedName : NULL, parameters.String());
794 	if (ret != B_OK) {
795 		_DisplayPartitionError("Validation of the given initialization "
796 			"parameters failed.", partition, ret);
797 		return;
798 	}
799 
800 	BString previousName = partition->ContentName();
801 
802 	ret = partition->Initialize(diskSystem.PrettyName(),
803 		supportsName ? name.String() : NULL, parameters.String());
804 	if (ret != B_OK) {
805 		_DisplayPartitionError("Initialization of the partition %s "
806 			"failed. (Nothing has been written to disk.)", partition, ret);
807 		return;
808 	}
809 
810 	// everything looks fine, we are ready to actually write the changes
811 	// to disk
812 
813 	message = "Are you sure you want to write the changes back to "
814 		"disk now?\n\n";
815 	message << "All data on the partition \"" << previousName;
816 	message << "\" will be irrevertably lost if you do so!";
817 	alert = new BAlert("final notice", message.String(),
818 		"Write Changes", "Cancel", NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT);
819 	choice = alert->Go();
820 
821 	if (choice == 1)
822 		return;
823 
824 	// commit
825 	ret = modificationPreparer.CommitModifications();
826 
827 	// The partition pointer is toast now! Use the partition id to
828 	// retrieve it again.
829 	partition = disk->FindDescendant(selectedPartition);
830 
831 	if (ret == B_OK) {
832 		_DisplayPartitionError("The partition %s has been successfully "
833 			"initialized.\n", partition);
834 	} else {
835 		_DisplayPartitionError("Failed to initialize the partition "
836 			"%s!\n", partition, ret);
837 	}
838 
839 	_ScanDrives();
840 }
841 
842