xref: /haiku/src/apps/drivesetup/MainWindow.cpp (revision adb0d19d561947362090081e81d90dde59142026)
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 
17 #include <stdio.h>
18 #include <string.h>
19 
20 #include <Alert.h>
21 #include <Application.h>
22 
23 #include <DiskDeviceVisitor.h>
24 #include <DiskSystem.h>
25 #include <DiskDevice.h>
26 #include <Partition.h>
27 #include <PartitioningInfo.h>
28 #include <Path.h>
29 
30 #include <ColumnListView.h>
31 #include <ColumnTypes.h>
32 #include <MenuItem.h>
33 #include <MenuBar.h>
34 #include <Menu.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 
238 
239 MainWindow::~MainWindow()
240 {
241 	BDiskDeviceRoster().StopWatching(this);
242 	delete fCurrentDisk;
243 }
244 
245 
246 void
247 MainWindow::MessageReceived(BMessage* message)
248 {
249 	switch (message->what) {
250 		case MSG_MOUNT_ALL:
251 			_MountAll();
252 			break;
253 		case MSG_MOUNT:
254 			_Mount(fCurrentDisk, fCurrentPartitionID);
255 			break;
256 		case MSG_UNMOUNT:
257 			_Unmount(fCurrentDisk, fCurrentPartitionID);
258 			break;
259 
260 		case MSG_FORMAT:
261 			printf("MSG_FORMAT\n");
262 			break;
263 
264 		case MSG_CREATE:
265 			printf("MSG_CREATE\n");
266 			break;
267 
268 		case MSG_INITIALIZE: {
269 			BString diskSystemName;
270 			if (message->FindString("format", &diskSystemName) != B_OK)
271 				break;
272 			_Initialize(fCurrentDisk, fCurrentPartitionID, diskSystemName);
273 			break;
274 		}
275 
276 		case MSG_DELETE:
277 			printf("MSG_DELETE\n");
278 			break;
279 
280 		case MSG_EJECT:
281 			// TODO: completely untested, especially interesting
282 			// if partition list behaves when partitions disappear
283 			if (fCurrentDisk) {
284 				// TODO: only if no partitions are mounted anymore?
285 				fCurrentDisk->Eject(true);
286 				_ScanDrives();
287 			}
288 			break;
289 		case MSG_SURFACE_TEST:
290 			printf("MSG_SURFACE_TEST\n");
291 			break;
292 
293 		// TODO: this could probably be done better!
294 		case B_DEVICE_UPDATE:
295 		case MSG_RESCAN:
296 			_ScanDrives();
297 			break;
298 
299 		case MSG_PARTITION_ROW_SELECTED:
300 			// selection of partitions via list view
301 			_AdaptToSelectedPartition();
302 			break;
303 		case MSG_SELECTED_PARTITION_ID: {
304 			// selection of partitions via disk view
305 			partition_id id;
306 			if (message->FindInt32("partition_id", &id) == B_OK) {
307 				if (BRow* row = fListView->FindRow(id)) {
308 					fListView->DeselectAll();
309 					fListView->AddToSelection(row);
310 					_AdaptToSelectedPartition();
311 				}
312 			}
313 			break;
314 		}
315 
316 		default:
317 			BWindow::MessageReceived(message);
318 			break;
319 	}
320 }
321 
322 
323 bool
324 MainWindow::QuitRequested()
325 {
326 	// TODO: ask about any unsaved changes
327 	be_app->PostMessage(B_QUIT_REQUESTED);
328 	Hide();
329 	return false;
330 }
331 
332 
333 // #pragma mark -
334 
335 
336 status_t
337 MainWindow::StoreSettings(BMessage* archive) const
338 {
339 	if (archive->ReplaceRect("window frame", Frame()) < B_OK)
340 		archive->AddRect("window frame", Frame());
341 
342 	BMessage columnSettings;
343 	fListView->SaveState(&columnSettings);
344 	if (archive->ReplaceMessage("column settings", &columnSettings) < B_OK)
345 		archive->AddMessage("column settings", &columnSettings);
346 
347 	return B_OK;
348 }
349 
350 
351 status_t
352 MainWindow::RestoreSettings(BMessage* archive)
353 {
354 	BRect frame;
355 	if (archive->FindRect("window frame", &frame) == B_OK) {
356 		BScreen screen(this);
357 		if (frame.Intersects(screen.Frame())) {
358 			MoveTo(frame.LeftTop());
359 			ResizeTo(frame.Width(), frame.Height());
360 		}
361 	}
362 
363 	BMessage columnSettings;
364 	if (archive->FindMessage("column settings", &columnSettings) == B_OK)
365 		fListView->LoadState(&columnSettings);
366 
367 	return B_OK;
368 }
369 
370 
371 // #pragma mark -
372 
373 
374 void
375 MainWindow::_ScanDrives()
376 {
377 	fSpaceIDMap.Clear();
378 	int32 diskCount = 0;
379 	ListPopulatorVisitor driveVisitor(fListView, diskCount, fSpaceIDMap);
380 	fDDRoster.VisitEachPartition(&driveVisitor);
381 	fDiskView->SetDiskCount(diskCount);
382 
383 	// restore selection
384 	PartitionListRow* previousSelection
385 		= fListView->FindRow(fCurrentPartitionID);
386 	if (previousSelection) {
387 		fListView->AddToSelection(previousSelection);
388 		_EnabledDisableMenuItems(fCurrentDisk, fCurrentPartitionID,
389 			previousSelection->ParentID());
390 		fDiskView->ForceUpdate();
391 	} else {
392 		_EnabledDisableMenuItems(NULL, -1, -1);
393 	}
394 }
395 
396 
397 void
398 MainWindow::_ScanFileSystems()
399 {
400 	while (BMenuItem* item = fInitMenu->RemoveItem(0L))
401 		delete item;
402 
403 	BDiskSystem diskSystem;
404 	fDDRoster.RewindDiskSystems();
405 	while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) {
406 		if (diskSystem.IsFileSystem() && diskSystem.SupportsInitializing()) {
407 			BMessage* message = new BMessage(MSG_INITIALIZE);
408 			message->AddString("format", diskSystem.PrettyName());
409 			BString label = diskSystem.PrettyName();
410 			label << B_UTF8_ELLIPSIS;
411 			fInitMenu->AddItem(new BMenuItem(label.String(), message));
412 		}
413 	}
414 }
415 
416 
417 // #pragma mark -
418 
419 
420 void
421 MainWindow::_AdaptToSelectedPartition()
422 {
423 	partition_id diskID = -1;
424 	partition_id partitionID = -1;
425 	partition_id parentID = -1;
426 
427 	BRow* _selectedRow = fListView->CurrentSelection();
428 	if (_selectedRow) {
429 		// go up to top level row
430 		BRow* _topLevelRow = _selectedRow;
431 		BRow* parent = NULL;
432 		while (fListView->FindParent(_topLevelRow, &parent, NULL))
433 			_topLevelRow = parent;
434 
435 		PartitionListRow* topLevelRow
436 			= dynamic_cast<PartitionListRow*>(_topLevelRow);
437 		PartitionListRow* selectedRow
438 			= dynamic_cast<PartitionListRow*>(_selectedRow);
439 
440 		if (topLevelRow)
441 			diskID = topLevelRow->ID();
442 		if (selectedRow) {
443 			partitionID = selectedRow->ID();
444 			parentID = selectedRow->ParentID();
445 		}
446 	}
447 
448 	_SetToDiskAndPartition(diskID, partitionID, parentID);
449 }
450 
451 
452 void
453 MainWindow::_SetToDiskAndPartition(partition_id disk, partition_id partition,
454 	partition_id parent)
455 {
456 	BDiskDevice* oldDisk = NULL;
457 	if (!fCurrentDisk || fCurrentDisk->ID() != disk) {
458 		oldDisk = fCurrentDisk;
459 		fCurrentDisk = NULL;
460 		if (disk >= 0) {
461 			BDiskDevice* newDisk = new BDiskDevice();
462 			status_t ret = newDisk->SetTo(disk);
463 			if (ret < B_OK) {
464 				printf("error switching disks: %s\n", strerror(ret));
465 				delete newDisk;
466 			} else
467 				fCurrentDisk = newDisk;
468 		}
469 	}
470 
471 	fCurrentPartitionID = partition;
472 
473 	fDiskView->SetDisk(fCurrentDisk, fCurrentPartitionID);
474 	_EnabledDisableMenuItems(fCurrentDisk, fCurrentPartitionID, parent);
475 
476 	delete oldDisk;
477 }
478 
479 
480 void
481 MainWindow::_EnabledDisableMenuItems(BDiskDevice* disk,
482 	partition_id selectedPartition, partition_id parentID)
483 {
484 	// clean out Create menu
485 	while (BMenuItem* item = fCreateMenu->RemoveItem(0L))
486 		delete item;
487 
488 	if (!disk) {
489 		fFormatMI->SetEnabled(false);
490 		fEjectMI->SetEnabled(false);
491 		fSurfaceTestMI->SetEnabled(false);
492 
493 		fPartitionMenu->SetEnabled(false);
494 	} else {
495 //		fFormatMI->SetEnabled(true);
496 		fFormatMI->SetEnabled(false);
497 		fEjectMI->SetEnabled(disk->IsRemovableMedia());
498 //		fSurfaceTestMI->SetEnabled(true);
499 		fSurfaceTestMI->SetEnabled(false);
500 
501 		// Create menu and items
502 		fPartitionMenu->SetEnabled(true);
503 
504 		BPartition* parentPartition = NULL;
505 		if (selectedPartition <= -2)
506 			parentPartition = disk->FindDescendant(parentID);
507 
508 		if (parentPartition) {
509 			bool prepared = disk->PrepareModifications() == B_OK;
510 			fCreateMenu->SetEnabled(true);
511 			BString supportedChildType;
512 			int32 cookie = 0;
513 			status_t ret;
514 			while ((ret = parentPartition->GetNextSupportedChildType(&cookie,
515 				&supportedChildType)) == B_OK) {
516 				BMessage* message = new BMessage(MSG_CREATE);
517 				message->AddInt32("parent id", parentID);
518 				message->AddInt32("space id", selectedPartition);
519 				message->AddString("type", supportedChildType);
520 				BMenuItem* item = new BMenuItem(supportedChildType.String(),
521 					message);
522 				fCreateMenu->AddItem(item);
523 			}
524 			if (fCreateMenu->CountItems() == 0)
525 				fprintf(stderr, "Failed to get supported child types: %s\n",
526 					strerror(ret));
527 			if (prepared)
528 				disk->CancelModifications();
529 		} else {
530 			fCreateMenu->SetEnabled(false);
531 		}
532 
533 		// Mount items
534 		BPartition* partition = disk->FindDescendant(selectedPartition);
535 		if (partition) {
536 			fInitMenu->SetEnabled(!partition->IsMounted());
537 //			fDeleteMI->SetEnabled(!partition->IsMounted());
538 			fDeleteMI->SetEnabled(false);
539 			fMountMI->SetEnabled(!partition->IsMounted());
540 
541 			bool unMountable = false;
542 			if (partition->IsMounted()) {
543 				// see if this partition is the boot volume
544 				BVolume volume;
545 				BVolume bootVolume;
546 				if (BVolumeRoster().GetBootVolume(&bootVolume) == B_OK
547 					&& partition->GetVolume(&volume) == B_OK) {
548 					unMountable = volume != bootVolume;
549 				} else
550 					unMountable = true;
551 			}
552 			fUnmountMI->SetEnabled(unMountable);
553 		} else {
554 			fInitMenu->SetEnabled(false);
555 			fDeleteMI->SetEnabled(false);
556 			fMountMI->SetEnabled(false);
557 			fUnmountMI->SetEnabled(false);
558 		}
559 		fMountAllMI->SetEnabled(true);
560 	}
561 }
562 
563 
564 void
565 MainWindow::_DisplayPartitionError(BString _message,
566 	const BPartition* partition, status_t error) const
567 {
568 	char message[1024];
569 
570 	if (partition && _message.FindFirst("%s") >= 0) {
571 		BString name;
572 		name << " \"" << partition->ContentName() << "\"";
573 		sprintf(message, _message.String(), name.String());
574 	} else {
575 		_message.ReplaceAll("%s", "");
576 		sprintf(message, _message.String());
577 	}
578 
579 	if (error < B_OK) {
580 		BString helper = message;
581 		sprintf(message, "%s\n\nError: %s", helper.String(), strerror(error));
582 	}
583 
584 	BAlert* alert = new BAlert("error", message, "Ok", NULL, NULL,
585 		B_WIDTH_FROM_WIDEST, error < B_OK ? B_STOP_ALERT : B_INFO_ALERT);
586 	alert->Go(NULL);
587 }
588 
589 
590 // #pragma mark -
591 
592 
593 void
594 MainWindow::_Mount(BDiskDevice* disk, partition_id selectedPartition)
595 {
596 	if (!disk || selectedPartition < 0) {
597 		_DisplayPartitionError("You need to select a partition "
598 			"entry from the list.");
599 		return;
600 	}
601 
602 	BPartition* partition = disk->FindDescendant(selectedPartition);
603 	if (!partition) {
604 		_DisplayPartitionError("Unable to find the selected partition by id.");
605 		return;
606 	}
607 
608 	if (!partition->IsMounted()) {
609 		status_t ret = partition->Mount();
610 		if (ret < B_OK) {
611 			_DisplayPartitionError("Could not mount partition %s.",
612 				partition, ret);
613 		} else {
614 			// successful mount, adapt to the changes
615 			_ScanDrives();
616 		}
617 	} else {
618 		_DisplayPartitionError("The partition %s is already mounted.",
619 			partition);
620 	}
621 }
622 
623 
624 void
625 MainWindow::_Unmount(BDiskDevice* disk, partition_id selectedPartition)
626 {
627 	if (!disk || selectedPartition < 0) {
628 		_DisplayPartitionError("You need to select a partition "
629 			"entry from the list.");
630 		return;
631 	}
632 
633 	BPartition* partition = disk->FindDescendant(selectedPartition);
634 	if (!partition) {
635 		_DisplayPartitionError("Unable to find the selected partition by id.");
636 		return;
637 	}
638 
639 	if (partition->IsMounted()) {
640 		BPath path;
641 		partition->GetMountPoint(&path);
642 		status_t ret = partition->Unmount();
643 		if (ret < B_OK) {
644 			_DisplayPartitionError("Could not unmount partition %s.",
645 				partition, ret);
646 		} else {
647 			if (dev_for_path(path.Path()) == dev_for_path("/"))
648 				rmdir(path.Path());
649 			// successful unmount, adapt to the changes
650 			_ScanDrives();
651 		}
652 	} else {
653 		_DisplayPartitionError("The partition %s is already unmounted.",
654 			partition);
655 	}
656 }
657 
658 
659 void
660 MainWindow::_MountAll()
661 {
662 	MountAllVisitor visitor;
663 	fDDRoster.VisitEachPartition(&visitor);
664 }
665 
666 
667 // #pragma mark -
668 
669 
670 class ModificationPreparer {
671 public:
672 	ModificationPreparer(BDiskDevice* disk)
673 		:
674 		fDisk(disk),
675 		fModificationStatus(fDisk->PrepareModifications())
676 	{
677 	}
678 	~ModificationPreparer()
679 	{
680 		if (fModificationStatus == B_OK)
681 			fDisk->CancelModifications();
682 	}
683 	status_t ModificationStatus() const
684 	{
685 		return fModificationStatus;
686 	}
687 	status_t CommitModifications()
688 	{
689 		status_t ret = fDisk->CommitModifications();
690 		if (ret == B_OK)
691 			fModificationStatus = B_ERROR;
692 		return ret;
693 	}
694 
695 private:
696 	BDiskDevice*	fDisk;
697 	status_t		fModificationStatus;
698 };
699 
700 
701 void
702 MainWindow::_Initialize(BDiskDevice* disk, partition_id selectedPartition,
703 	const BString& diskSystemName)
704 {
705 	if (!disk || selectedPartition < 0) {
706 		_DisplayPartitionError("You need to select a partition "
707 			"entry from the list.");
708 		return;
709 	}
710 
711 	if (disk->IsReadOnly()) {
712 		_DisplayPartitionError("The selected disk is read-only.");
713 		return;
714 	}
715 
716 	BPartition* partition = disk->FindDescendant(selectedPartition);
717 	if (!partition) {
718 		_DisplayPartitionError("Unable to find the selected partition by id.");
719 		return;
720 	}
721 
722 	if (partition->IsMounted()) {
723 		_DisplayPartitionError("The partition %s is currently mounted.");
724 		// TODO: option to unmount and continue on success to unmount
725 		return;
726 	}
727 
728 	BString message("Are you sure you want to initialize the partition ");
729 	message << "\"" << partition->ContentName();
730 	message << "\"? After entering the initialization parameters, ";
731 	message << "you can abort this operation right before writing ";
732 	message << "changes back to the disk.";
733 	BAlert* alert = new BAlert("first notice", message.String(),
734 		"Continue", "Cancel", NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT);
735 	int32 choice = alert->Go();
736 
737 	if (choice == 1)
738 		return;
739 
740 	BDiskSystem diskSystem;
741 	fDDRoster.RewindDiskSystems();
742 	bool found = false;
743 	while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) {
744 		if (diskSystem.IsFileSystem() && diskSystem.SupportsInitializing()) {
745 			if (diskSystemName == diskSystem.PrettyName()) {
746 				found = true;
747 				break;
748 			}
749 		}
750 	}
751 
752 	if (!found) {
753 		BString message("Disk system \"");
754 		message << diskSystemName << "\" not found!";
755 		_DisplayPartitionError(message);
756 		return;
757 	}
758 
759 
760 	// allow BFS only, since our parameter string
761 	// construction only handles BFS at the moment
762 	if (diskSystemName != "Be File System") {
763 		_DisplayPartitionError("Don't know how to construct parameters "
764 			"for this file system.");
765 		return;
766 	}
767 
768 	ModificationPreparer modificationPreparer(disk);
769 	status_t ret = modificationPreparer.ModificationStatus();
770 	if (ret != B_OK) {
771 		_DisplayPartitionError("There was an error preparing the "
772 			"disk for modifications.", NULL, ret);
773 		return;
774 	}
775 
776 	// TODO: use partition initialization editor
777 	// (partition->GetInitializationParameterEditor())
778 
779 	BString name = partition->ContentName();
780 	if (name.Length() == 0)
781 		name = "Haiku";
782 	BString parameters;
783 	InitParamsPanel* panel = new InitParamsPanel(this);
784 	if (panel->Go(name, parameters) == GO_CANCELED)
785 		return;
786 
787 	bool supportsName = diskSystem.SupportsContentName();
788 	BString validatedName(name);
789 	ret = partition->ValidateInitialize(diskSystem.PrettyName(),
790 		supportsName ? &validatedName : NULL, parameters.String());
791 	if (ret != B_OK) {
792 		_DisplayPartitionError("Validation of the given initialization "
793 			"parameters failed.", partition, ret);
794 		return;
795 	}
796 
797 	BString previousName = partition->ContentName();
798 
799 	ret = partition->Initialize(diskSystem.PrettyName(),
800 		supportsName ? name.String() : NULL, parameters.String());
801 	if (ret != B_OK) {
802 		_DisplayPartitionError("Initialization of the partition %s "
803 			"failed. (Nothing has been written to disk.)", partition, ret);
804 		return;
805 	}
806 
807 	// everything looks fine, we are ready to actually write the changes
808 	// to disk
809 
810 	message = "Are you sure you want to write the changes back to "
811 		"disk now?\n\n";
812 	message << "All data on the partition \"" << previousName;
813 	message << "\" will be irrevertably lost if you do so!";
814 	alert = new BAlert("final notice", message.String(),
815 		"Write Changes", "Cancel", NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT);
816 	choice = alert->Go();
817 
818 	if (choice == 1)
819 		return;
820 
821 	// commit
822 	ret = modificationPreparer.CommitModifications();
823 
824 	// The partition pointer is toast now! Use the partition id to
825 	// retrieve it again.
826 	partition = disk->FindDescendant(selectedPartition);
827 
828 	if (ret == B_OK) {
829 		_DisplayPartitionError("The partition %s has been successfully "
830 			"initialized.\n", partition);
831 	} else {
832 		_DisplayPartitionError("Failed to initialize the partition "
833 			"%s!\n", partition, ret);
834 	}
835 
836 	_ScanDrives();
837 }
838 
839