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