btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / installer / InstallerWindow.cpp
blobeb36bf3cce486e4b2ebc348f57b876db20de4390
1 /*
2 * Copyright 2009-2010, Stephan Aßmus <superstippi@gmx.de>
3 * Copyright 2005-2008, Jérôme DUVAL
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
8 #include "InstallerWindow.h"
10 #include <stdio.h>
11 #include <strings.h>
13 #include <Alert.h>
14 #include <Application.h>
15 #include <Autolock.h>
16 #include <Box.h>
17 #include <Button.h>
18 #include <Catalog.h>
19 #include <ControlLook.h>
20 #include <Directory.h>
21 #include <FindDirectory.h>
22 #include <LayoutBuilder.h>
23 #include <LayoutUtils.h>
24 #include <Locale.h>
25 #include <MenuBar.h>
26 #include <MenuField.h>
27 #include <Path.h>
28 #include <PopUpMenu.h>
29 #include <Roster.h>
30 #include <Screen.h>
31 #include <ScrollView.h>
32 #include <SeparatorView.h>
33 #include <SpaceLayoutItem.h>
34 #include <StatusBar.h>
35 #include <String.h>
36 #include <TextView.h>
37 #include <TranslationUtils.h>
38 #include <TranslatorFormats.h>
40 #include "tracker_private.h"
42 #include "DialogPane.h"
43 #include "InstallerDefs.h"
44 #include "PackageViews.h"
45 #include "PartitionMenuItem.h"
46 #include "WorkerThread.h"
49 #undef B_TRANSLATION_CONTEXT
50 #define B_TRANSLATION_CONTEXT "InstallerWindow"
53 static const char* kDriveSetupSignature = "application/x-vnd.Haiku-DriveSetup";
54 static const char* kBootManagerSignature
55 = "application/x-vnd.Haiku-BootManager";
57 const uint32 BEGIN_MESSAGE = 'iBGN';
58 const uint32 SHOW_BOTTOM_MESSAGE = 'iSBT';
59 const uint32 LAUNCH_DRIVE_SETUP = 'iSEP';
60 const uint32 LAUNCH_BOOTMAN = 'iWBM';
61 const uint32 START_SCAN = 'iSSC';
62 const uint32 PACKAGE_CHECKBOX = 'iPCB';
63 const uint32 ENCOURAGE_DRIVESETUP = 'iENC';
66 class LogoView : public BView {
67 public:
68 LogoView(const BRect& frame);
69 LogoView();
70 virtual ~LogoView();
72 virtual void Draw(BRect update);
74 virtual void GetPreferredSize(float* _width,
75 float* _height);
77 private:
78 void _Init();
80 BBitmap* fLogo;
84 LogoView::LogoView(const BRect& frame)
86 BView(frame, "logoview", B_FOLLOW_LEFT | B_FOLLOW_TOP,
87 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
89 _Init();
93 LogoView::LogoView()
95 BView("logoview", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
97 _Init();
101 LogoView::~LogoView(void)
103 delete fLogo;
107 void
108 LogoView::Draw(BRect update)
110 if (fLogo == NULL)
111 return;
113 BRect bounds(Bounds());
114 BPoint placement;
115 placement.x = (bounds.left + bounds.right - fLogo->Bounds().Width()) / 2;
116 placement.y = (bounds.top + bounds.bottom - fLogo->Bounds().Height()) / 2;
118 DrawBitmap(fLogo, placement);
122 void
123 LogoView::GetPreferredSize(float* _width, float* _height)
125 float width = 0.0;
126 float height = 0.0;
127 if (fLogo) {
128 width = fLogo->Bounds().Width();
129 height = fLogo->Bounds().Height();
131 if (_width)
132 *_width = width;
133 if (_height)
134 *_height = height;
138 void
139 LogoView::_Init()
141 fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "logo.png");
145 // #pragma mark -
148 static BLayoutItem*
149 layout_item_for(BView* view)
151 BLayout* layout = view->Parent()->GetLayout();
152 int32 index = layout->IndexOfView(view);
153 return layout->ItemAt(index);
157 InstallerWindow::InstallerWindow()
159 BWindow(BRect(-2000, -2000, -1800, -1800),
160 B_TRANSLATE_SYSTEM_NAME("Installer"), B_TITLED_WINDOW,
161 B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
162 fEncouragedToSetupPartitions(false),
163 fDriveSetupLaunched(false),
164 fBootManagerLaunched(false),
165 fInstallStatus(kReadyForInstall),
166 fWorkerThread(new WorkerThread(this)),
167 fCopyEngineCancelSemaphore(-1)
169 if (!be_roster->IsRunning(kTrackerSignature))
170 SetWorkspaces(B_ALL_WORKSPACES);
172 LogoView* logoView = new LogoView();
174 fStatusView = new BTextView("statusView", be_plain_font, NULL,
175 B_WILL_DRAW);
176 fStatusView->SetViewColor(255, 255, 255, 255);
177 fStatusView->SetInsets(10, 0, 10, 0);
178 fStatusView->MakeEditable(false);
179 fStatusView->MakeSelectable(false);
181 BSize logoSize = logoView->MinSize();
182 logoView->SetExplicitMaxSize(logoSize);
183 fStatusView->SetExplicitMinSize(BSize(logoSize.width * 0.8,
184 B_SIZE_UNSET));
186 // Explicitly create group view to set the background white in case
187 // height resizing is needed for the status view
188 BGroupView* logoGroup = new BGroupView(B_HORIZONTAL, 0);
189 logoGroup->SetViewColor(255, 255, 255);
190 logoGroup->AddChild(logoView);
191 logoGroup->AddChild(fStatusView);
193 fDestMenu = new BPopUpMenu(B_TRANSLATE("scanning" B_UTF8_ELLIPSIS),
194 true, false);
195 fSrcMenu = new BPopUpMenu(B_TRANSLATE("scanning" B_UTF8_ELLIPSIS),
196 true, false);
198 fSrcMenuField = new BMenuField("srcMenuField",
199 B_TRANSLATE("Install from:"), fSrcMenu);
200 fSrcMenuField->SetAlignment(B_ALIGN_RIGHT);
202 fDestMenuField = new BMenuField("destMenuField", B_TRANSLATE("Onto:"),
203 fDestMenu);
204 fDestMenuField->SetAlignment(B_ALIGN_RIGHT);
206 fPackagesSwitch = new PaneSwitch("options_button");
207 fPackagesSwitch->SetLabels(B_TRANSLATE("Hide optional packages"),
208 B_TRANSLATE("Show optional packages"));
209 fPackagesSwitch->SetMessage(new BMessage(SHOW_BOTTOM_MESSAGE));
210 fPackagesSwitch->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED,
211 B_SIZE_UNSET));
212 fPackagesSwitch->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
213 B_ALIGN_TOP));
215 fPackagesView = new PackagesView("packages_view");
216 BScrollView* packagesScrollView = new BScrollView("packagesScroll",
217 fPackagesView, B_WILL_DRAW, false, true);
219 const char* requiredDiskSpaceString
220 = B_TRANSLATE("Additional disk space required: 0.0 KiB");
221 fSizeView = new BStringView("size_view", requiredDiskSpaceString);
222 fSizeView->SetAlignment(B_ALIGN_RIGHT);
223 fSizeView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
224 fSizeView->SetExplicitAlignment(
225 BAlignment(B_ALIGN_RIGHT, B_ALIGN_MIDDLE));
227 fProgressBar = new BStatusBar("progress",
228 B_TRANSLATE("Install progress: "));
229 fProgressBar->SetMaxValue(100.0);
231 fBeginButton = new BButton("begin_button", B_TRANSLATE("Begin"),
232 new BMessage(BEGIN_MESSAGE));
233 fBeginButton->MakeDefault(true);
234 fBeginButton->SetEnabled(false);
236 fLaunchDriveSetupButton = new BButton("setup_button",
237 B_TRANSLATE("Set up partitions" B_UTF8_ELLIPSIS),
238 new BMessage(LAUNCH_DRIVE_SETUP));
240 fLaunchBootManagerItem = new BMenuItem(B_TRANSLATE("Set up boot menu"),
241 new BMessage(LAUNCH_BOOTMAN));
242 fLaunchBootManagerItem->SetEnabled(false);
244 fMakeBootableItem = new BMenuItem(B_TRANSLATE("Write boot sector"),
245 new BMessage(MSG_WRITE_BOOT_SECTOR));
246 fMakeBootableItem->SetEnabled(false);
247 BMenuBar* mainMenu = new BMenuBar("main menu");
248 BMenu* toolsMenu = new BMenu(B_TRANSLATE("Tools"));
249 toolsMenu->AddItem(fLaunchBootManagerItem);
250 toolsMenu->AddItem(fMakeBootableItem);
251 mainMenu->AddItem(toolsMenu);
253 BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
254 .Add(mainMenu)
255 .Add(logoGroup)
256 .Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
257 .AddGroup(B_VERTICAL, B_USE_ITEM_SPACING)
258 .SetInsets(B_USE_WINDOW_SPACING)
259 .AddGrid(new BGridView(B_USE_ITEM_SPACING, B_USE_ITEM_SPACING))
260 .Add(fSrcMenuField->CreateLabelLayoutItem(), 0, 0)
261 .Add(fSrcMenuField->CreateMenuBarLayoutItem(), 1, 0)
262 .Add(fDestMenuField->CreateLabelLayoutItem(), 0, 1)
263 .Add(fDestMenuField->CreateMenuBarLayoutItem(), 1, 1)
265 .Add(BSpaceLayoutItem::CreateVerticalStrut(5), 0, 2, 2)
267 .Add(fPackagesSwitch, 0, 3, 2)
268 .Add(packagesScrollView, 0, 4, 2)
269 .Add(fProgressBar, 0, 5, 2)
270 .Add(fSizeView, 0, 6, 2)
271 .End()
273 .AddGroup(B_HORIZONTAL, B_USE_WINDOW_SPACING)
274 .Add(fLaunchDriveSetupButton)
275 .AddGlue()
276 .Add(fBeginButton);
278 // Make the optional packages and progress bar invisible on start
279 fPackagesLayoutItem = layout_item_for(packagesScrollView);
280 fPkgSwitchLayoutItem = layout_item_for(fPackagesSwitch);
281 fSizeViewLayoutItem = layout_item_for(fSizeView);
282 fProgressLayoutItem = layout_item_for(fProgressBar);
284 fPackagesLayoutItem->SetVisible(false);
285 fSizeViewLayoutItem->SetVisible(false);
286 fProgressLayoutItem->SetVisible(false);
288 // Setup tool tips for the non-obvious features
289 fLaunchDriveSetupButton->SetToolTip(
290 B_TRANSLATE("Launch the DriveSetup utility to partition\n"
291 "available hard drives and other media.\n"
292 "Partitions can be initialized with the\n"
293 "Be File System needed for a Haiku boot\n"
294 "partition."));
295 // fLaunchBootManagerItem->SetToolTip(
296 // B_TRANSLATE("Install or uninstall the Haiku boot menu, which allows "
297 // "to choose an operating system to boot when the computer starts.\n"
298 // "If this computer already has a boot manager such as GRUB installed, "
299 // "it is better to add Haiku to that menu than to overwrite it."));
300 // fMakeBootableItem->SetToolTip(
301 // B_TRANSLATE("Writes the Haiku boot code to the partition start\n"
302 // "sector. This step is automatically performed by\n"
303 // "the installation, but you can manually make a\n"
304 // "partition bootable in case you do not need to\n"
305 // "perform an installation."));
307 // finish creating window
308 if (!be_roster->IsRunning(kDeskbarSignature))
309 SetFlags(Flags() | B_NOT_MINIMIZABLE);
311 CenterOnScreen();
312 Show();
314 // Register to receive notifications when apps launch or quit...
315 be_roster->StartWatching(this);
316 // ... and check the two we are interested in.
317 fDriveSetupLaunched = be_roster->IsRunning(kDriveSetupSignature);
318 fBootManagerLaunched = be_roster->IsRunning(kBootManagerSignature);
320 if (Lock()) {
321 fLaunchDriveSetupButton->SetEnabled(!fDriveSetupLaunched);
322 fLaunchBootManagerItem->SetEnabled(!fBootManagerLaunched);
323 Unlock();
326 PostMessage(START_SCAN);
330 InstallerWindow::~InstallerWindow()
332 _SetCopyEngineCancelSemaphore(-1);
333 be_roster->StopWatching(this);
337 void
338 InstallerWindow::MessageReceived(BMessage *msg)
340 switch (msg->what) {
341 case MSG_RESET:
343 _SetCopyEngineCancelSemaphore(-1);
345 status_t error;
346 if (msg->FindInt32("error", &error) == B_OK) {
347 char errorMessage[2048];
348 snprintf(errorMessage, sizeof(errorMessage),
349 B_TRANSLATE("An error was encountered and the "
350 "installation was not completed:\n\n"
351 "Error: %s"), strerror(error));
352 BAlert* alert = new BAlert("error", errorMessage, B_TRANSLATE("OK"));
353 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
354 alert->Go();
357 _DisableInterface(false);
359 fProgressLayoutItem->SetVisible(false);
360 fPkgSwitchLayoutItem->SetVisible(true);
361 _ShowOptionalPackages();
362 _UpdateControls();
363 break;
365 case START_SCAN:
366 _ScanPartitions();
367 break;
368 case BEGIN_MESSAGE:
369 switch (fInstallStatus) {
370 case kReadyForInstall:
372 // get source and target
373 PartitionMenuItem* targetItem
374 = (PartitionMenuItem*)fDestMenu->FindMarked();
375 PartitionMenuItem* srcItem
376 = (PartitionMenuItem*)fSrcMenu->FindMarked();
377 if (srcItem == NULL || targetItem == NULL)
378 break;
380 _SetCopyEngineCancelSemaphore(create_sem(1,
381 "copy engine cancel"));
383 BList* list = new BList();
384 int32 size = 0;
385 fPackagesView->GetPackagesToInstall(list, &size);
386 fWorkerThread->SetLock(fCopyEngineCancelSemaphore);
387 fWorkerThread->SetPackagesList(list);
388 fWorkerThread->SetSpaceRequired(size);
389 fInstallStatus = kInstalling;
390 fWorkerThread->StartInstall(srcItem->ID(),
391 targetItem->ID());
392 fBeginButton->SetLabel(B_TRANSLATE("Stop"));
393 _DisableInterface(true);
395 fProgressBar->SetTo(0.0, NULL, NULL);
397 fPkgSwitchLayoutItem->SetVisible(false);
398 fPackagesLayoutItem->SetVisible(false);
399 fSizeViewLayoutItem->SetVisible(false);
400 fProgressLayoutItem->SetVisible(true);
401 break;
403 case kInstalling:
405 _QuitCopyEngine(true);
406 break;
408 case kFinished:
409 PostMessage(B_QUIT_REQUESTED);
410 break;
411 case kCancelled:
412 break;
414 break;
415 case SHOW_BOTTOM_MESSAGE:
416 _ShowOptionalPackages();
417 break;
418 case SOURCE_PARTITION:
419 _PublishPackages();
420 _UpdateControls();
421 break;
422 case TARGET_PARTITION:
423 _UpdateControls();
424 break;
425 case LAUNCH_DRIVE_SETUP:
426 _LaunchDriveSetup();
427 break;
428 case LAUNCH_BOOTMAN:
429 _LaunchBootManager();
430 break;
431 case PACKAGE_CHECKBOX:
433 char buffer[15];
434 fPackagesView->GetTotalSizeAsString(buffer, sizeof(buffer));
435 char string[256];
436 snprintf(string, sizeof(string),
437 B_TRANSLATE("Additional disk space required: %s"), buffer);
438 fSizeView->SetText(string);
439 break;
441 case ENCOURAGE_DRIVESETUP:
443 BAlert* alert = new BAlert("use drive setup", B_TRANSLATE("No partitions have "
444 "been found that are suitable for installation. Please set "
445 "up partitions and initialize at least one partition with the "
446 "Be File System."), B_TRANSLATE("OK"));
447 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
448 alert->Go();
449 break;
451 case MSG_STATUS_MESSAGE:
453 // TODO: Was this supposed to prevent status messages still arriving
454 // after the copy engine was shut down?
455 // if (fInstallStatus != kInstalling)
456 // break;
457 float progress;
458 if (msg->FindFloat("progress", &progress) == B_OK) {
459 const char* currentItem;
460 if (msg->FindString("item", &currentItem) != B_OK) {
461 currentItem = B_TRANSLATE_COMMENT("???",
462 "Unknown currently copied item");
464 BString trailingLabel;
465 int32 currentCount;
466 int32 maximumCount;
467 if (msg->FindInt32("current", &currentCount) == B_OK
468 && msg->FindInt32("maximum", &maximumCount) == B_OK) {
469 char buffer[64];
470 snprintf(buffer, sizeof(buffer),
471 B_TRANSLATE_COMMENT("%1ld of %2ld",
472 "number of files copied"),
473 currentCount, maximumCount);
474 trailingLabel << buffer;
475 } else {
476 trailingLabel <<
477 B_TRANSLATE_COMMENT("?? of ??", "Unknown progress");
479 fProgressBar->SetTo(progress, currentItem,
480 trailingLabel.String());
481 } else {
482 const char *status;
483 if (msg->FindString("status", &status) == B_OK) {
484 fLastStatus = fStatusView->Text();
485 _SetStatusMessage(status);
486 } else
487 _SetStatusMessage(fLastStatus.String());
489 break;
491 case MSG_INSTALL_FINISHED:
494 _SetCopyEngineCancelSemaphore(-1);
496 PartitionMenuItem* dstItem
497 = (PartitionMenuItem*)fDestMenu->FindMarked();
499 char status[1024];
500 if (be_roster->IsRunning(kDeskbarSignature)) {
501 fBeginButton->SetLabel(B_TRANSLATE("Quit"));
502 snprintf(status, sizeof(status), B_TRANSLATE("Installation "
503 "completed. Boot sector has been written to '%s'. Press "
504 "Quit to leave the Installer or choose a new target "
505 "volume to perform another installation."),
506 dstItem ? dstItem->Name() : B_TRANSLATE_COMMENT("???",
507 "Unknown partition name"));
508 } else {
509 fBeginButton->SetLabel(B_TRANSLATE("Restart"));
510 snprintf(status, sizeof(status), B_TRANSLATE("Installation "
511 "completed. Boot sector has been written to '%s'. Press "
512 "Restart to restart the computer or choose a new target "
513 "volume to perform another installation."),
514 dstItem ? dstItem->Name() : B_TRANSLATE_COMMENT("???",
515 "Unknown partition name"));
518 _SetStatusMessage(status);
519 fInstallStatus = kFinished;
520 _DisableInterface(false);
521 fProgressLayoutItem->SetVisible(false);
522 fPkgSwitchLayoutItem->SetVisible(true);
523 _ShowOptionalPackages();
524 break;
526 case B_SOME_APP_LAUNCHED:
527 case B_SOME_APP_QUIT:
529 const char *signature;
530 if (msg->FindString("be:signature", &signature) != B_OK)
531 break;
532 bool isDriveSetup = !strcasecmp(signature, kDriveSetupSignature);
533 bool isBootManager = !strcasecmp(signature, kBootManagerSignature);
534 if (isDriveSetup || isBootManager) {
535 bool scanPartitions = false;
536 if (isDriveSetup) {
537 bool launched = msg->what == B_SOME_APP_LAUNCHED;
538 // We need to scan partitions if DriveSetup has quit.
539 scanPartitions = fDriveSetupLaunched && !launched;
540 fDriveSetupLaunched = launched;
542 if (isBootManager)
543 fBootManagerLaunched = msg->what == B_SOME_APP_LAUNCHED;
545 fBeginButton->SetEnabled(
546 !fDriveSetupLaunched && !fBootManagerLaunched);
547 _DisableInterface(fDriveSetupLaunched || fBootManagerLaunched);
548 if (fDriveSetupLaunched && fBootManagerLaunched) {
549 _SetStatusMessage(B_TRANSLATE("Running Boot Manager and "
550 "DriveSetup" B_UTF8_ELLIPSIS
551 "\n\nClose both applications to continue with the "
552 "installation."));
553 } else if (fDriveSetupLaunched) {
554 _SetStatusMessage(B_TRANSLATE("Running DriveSetup"
555 B_UTF8_ELLIPSIS
556 "\n\nClose DriveSetup to continue with the "
557 "installation."));
558 } else if (fBootManagerLaunched) {
559 _SetStatusMessage(B_TRANSLATE("Running Boot Manager"
560 B_UTF8_ELLIPSIS
561 "\n\nClose Boot Manager to continue with the "
562 "installation."));
563 } else {
564 // If neither DriveSetup nor Bootman is running, we need
565 // to scan partitions in case DriveSetup has quit, or
566 // we need to update the guidance message.
567 if (scanPartitions)
568 _ScanPartitions();
569 else
570 _UpdateControls();
573 break;
575 case MSG_WRITE_BOOT_SECTOR:
576 fWorkerThread->WriteBootSector(fDestMenu);
577 break;
579 default:
580 BWindow::MessageReceived(msg);
581 break;
586 bool
587 InstallerWindow::QuitRequested()
589 if ((Flags() & B_NOT_MINIMIZABLE) != 0) {
590 // This means Deskbar is not running, i.e. Installer is the only
591 // thing on the screen and we will reboot the machine once it quits.
593 if (fDriveSetupLaunched && fBootManagerLaunched) {
594 BAlert* alert = new BAlert(B_TRANSLATE("Quit Boot Manager and "
595 "DriveSetup"), B_TRANSLATE("Please close the Boot Manager "
596 "and DriveSetup windows before closing the Installer window."),
597 B_TRANSLATE("OK"));
598 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
599 alert->Go();
600 return false;
602 if (fDriveSetupLaunched) {
603 BAlert* alert = new BAlert(B_TRANSLATE("Quit DriveSetup"),
604 B_TRANSLATE("Please close the DriveSetup window before "
605 "closing the Installer window."), B_TRANSLATE("OK"));
606 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
607 alert->Go();
608 return false;
610 if (fBootManagerLaunched) {
611 BAlert* alert = new BAlert(B_TRANSLATE("Quit Boot Manager"),
612 B_TRANSLATE("Please close the Boot Manager window before "
613 "closing the Installer window."), B_TRANSLATE("OK"));
614 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
615 alert->Go();
616 return false;
618 if (fInstallStatus != kFinished) {
619 BAlert* alert = new BAlert(B_TRANSLATE_SYSTEM_NAME("Installer"),
620 B_TRANSLATE("Are you sure you want to abort the "
621 "installation and restart the system?"),
622 B_TRANSLATE("Cancel"), B_TRANSLATE("Restart system"), NULL,
623 B_WIDTH_AS_USUAL, B_STOP_ALERT);
624 alert->SetShortcut(0, B_ESCAPE);
625 if (alert->Go() == 0)
626 return false;
628 } else if (fInstallStatus == kInstalling) {
629 BAlert* alert = new BAlert(B_TRANSLATE_SYSTEM_NAME("Installer"),
630 B_TRANSLATE("Are you sure you want to abort the installation?"),
631 B_TRANSLATE("Cancel"), B_TRANSLATE("Abort"), NULL,
632 B_WIDTH_AS_USUAL, B_STOP_ALERT);
633 alert->SetShortcut(0, B_ESCAPE);
634 if (alert->Go() == 0)
635 return false;
638 _QuitCopyEngine(false);
639 fWorkerThread->PostMessage(B_QUIT_REQUESTED);
640 be_app->PostMessage(B_QUIT_REQUESTED);
641 return true;
645 // #pragma mark -
648 void
649 InstallerWindow::_ShowOptionalPackages()
651 if (fPackagesLayoutItem && fSizeViewLayoutItem) {
652 fPackagesLayoutItem->SetVisible(fPackagesSwitch->Value());
653 fSizeViewLayoutItem->SetVisible(fPackagesSwitch->Value());
658 void
659 InstallerWindow::_LaunchDriveSetup()
661 if (be_roster->Launch(kDriveSetupSignature) != B_OK) {
662 // Try really hard to launch it. It's very likely that this fails,
663 // when we run from the CD and there is only an incomplete mime
664 // database for example...
665 BPath path;
666 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &path) != B_OK
667 || path.Append("DriveSetup") != B_OK) {
668 path.SetTo("/boot/system/apps/DriveSetup");
670 BEntry entry(path.Path());
671 entry_ref ref;
672 if (entry.GetRef(&ref) != B_OK || be_roster->Launch(&ref) != B_OK) {
673 BAlert* alert = new BAlert("error", B_TRANSLATE("DriveSetup, the "
674 "application to configure disk partitions, could not be "
675 "launched."), B_TRANSLATE("OK"));
676 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
677 alert->Go();
683 void
684 InstallerWindow::_LaunchBootManager()
686 // TODO: Currently BootManager always tries to install to the "first"
687 // harddisk. If/when it later supports being installed to a certain
688 // harddisk, we would have to pass it the disk that contains the target
689 // partition here.
690 if (be_roster->Launch(kBootManagerSignature) != B_OK) {
691 // Try really hard to launch it. It's very likely that this fails,
692 // when we run from the CD and there is only an incomplete mime
693 // database for example...
694 BPath path;
695 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &path) != B_OK
696 || path.Append("BootManager") != B_OK) {
697 path.SetTo("/boot/system/apps/BootManager");
699 BEntry entry(path.Path());
700 entry_ref ref;
701 if (entry.GetRef(&ref) != B_OK || be_roster->Launch(&ref) != B_OK) {
702 BAlert* alert = new BAlert(
703 B_TRANSLATE("Failed to launch Boot Manager"),
704 B_TRANSLATE("Boot Manager, the application to configure the "
705 "Haiku boot menu, could not be launched."),
706 B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
707 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
708 alert->Go();
714 void
715 InstallerWindow::_DisableInterface(bool disable)
717 fLaunchDriveSetupButton->SetEnabled(!disable);
718 fLaunchBootManagerItem->SetEnabled(!disable);
719 fMakeBootableItem->SetEnabled(!disable);
720 fSrcMenuField->SetEnabled(!disable);
721 fDestMenuField->SetEnabled(!disable);
725 void
726 InstallerWindow::_ScanPartitions()
728 _SetStatusMessage(B_TRANSLATE("Scanning for disks" B_UTF8_ELLIPSIS));
730 BMenuItem *item;
731 while ((item = fSrcMenu->RemoveItem((int32)0)))
732 delete item;
733 while ((item = fDestMenu->RemoveItem((int32)0)))
734 delete item;
736 fWorkerThread->ScanDisksPartitions(fSrcMenu, fDestMenu);
738 if (fSrcMenu->ItemAt(0) != NULL)
739 _PublishPackages();
741 _UpdateControls();
745 void
746 InstallerWindow::_UpdateControls()
748 PartitionMenuItem* srcItem = (PartitionMenuItem*)fSrcMenu->FindMarked();
749 BString label;
750 if (srcItem) {
751 label = srcItem->MenuLabel();
752 } else {
753 if (fSrcMenu->CountItems() == 0)
754 label = B_TRANSLATE_COMMENT("<none>", "No partition available");
755 else
756 label = ((PartitionMenuItem*)fSrcMenu->ItemAt(0))->MenuLabel();
758 fSrcMenuField->MenuItem()->SetLabel(label.String());
760 // Disable any unsuitable target items, check if at least one partition
761 // is suitable.
762 bool foundOneSuitableTarget = false;
763 for (int32 i = fDestMenu->CountItems() - 1; i >= 0; i--) {
764 PartitionMenuItem* dstItem
765 = (PartitionMenuItem*)fDestMenu->ItemAt(i);
766 if (srcItem != NULL && dstItem->ID() == srcItem->ID()) {
767 // Prevent the user from having picked the same partition as source
768 // and destination.
769 dstItem->SetEnabled(false);
770 dstItem->SetMarked(false);
771 } else
772 dstItem->SetEnabled(dstItem->IsValidTarget());
774 if (dstItem->IsEnabled())
775 foundOneSuitableTarget = true;
778 PartitionMenuItem* dstItem = (PartitionMenuItem*)fDestMenu->FindMarked();
779 if (dstItem) {
780 label = dstItem->MenuLabel();
781 } else {
782 if (fDestMenu->CountItems() == 0)
783 label = B_TRANSLATE_COMMENT("<none>", "No partition available");
784 else
785 label = B_TRANSLATE("Please choose target");
787 fDestMenuField->MenuItem()->SetLabel(label.String());
789 if (srcItem != NULL && dstItem != NULL) {
790 char message[255];
791 sprintf(message, B_TRANSLATE("Press the Begin button to install from "
792 "'%1s' onto '%2s'."), srcItem->Name(), dstItem->Name());
793 _SetStatusMessage(message);
794 } else if (srcItem != NULL) {
795 _SetStatusMessage(B_TRANSLATE("Choose the disk you want to install "
796 "onto from the pop-up menu. Then click \"Begin\"."));
797 } else if (dstItem != NULL) {
798 _SetStatusMessage(B_TRANSLATE("Choose the source disk from the "
799 "pop-up menu. Then click \"Begin\"."));
800 } else {
801 _SetStatusMessage(B_TRANSLATE("Choose the source and destination disk "
802 "from the pop-up menus. Then click \"Begin\"."));
805 fInstallStatus = kReadyForInstall;
806 fBeginButton->SetLabel(B_TRANSLATE("Begin"));
807 fBeginButton->SetEnabled(srcItem && dstItem);
809 // adjust "Write Boot Sector" and "Set up boot menu" buttons
810 if (dstItem != NULL) {
811 char buffer[256];
812 snprintf(buffer, sizeof(buffer), B_TRANSLATE("Write boot sector to '%s'"),
813 dstItem->Name());
814 label = buffer;
815 } else
816 label = B_TRANSLATE("Write boot sector");
817 fMakeBootableItem->SetEnabled(dstItem != NULL);
818 fMakeBootableItem->SetLabel(label.String());
819 // TODO: Once bootman support writing to specific disks, enable this, since
820 // we would pass it the disk which contains the target partition.
821 // fLaunchBootManagerItem->SetEnabled(dstItem != NULL);
823 if (!fEncouragedToSetupPartitions && !foundOneSuitableTarget) {
824 // Focus the users attention on the DriveSetup button
825 fEncouragedToSetupPartitions = true;
826 PostMessage(ENCOURAGE_DRIVESETUP);
831 void
832 InstallerWindow::_PublishPackages()
834 fPackagesView->Clean();
835 PartitionMenuItem *item = (PartitionMenuItem *)fSrcMenu->FindMarked();
836 if (item == NULL)
837 return;
839 BPath directory;
840 BDiskDeviceRoster roster;
841 BDiskDevice device;
842 BPartition *partition;
843 if (roster.GetPartitionWithID(item->ID(), &device, &partition) == B_OK) {
844 if (partition->GetMountPoint(&directory) != B_OK)
845 return;
846 } else if (roster.GetDeviceWithID(item->ID(), &device) == B_OK) {
847 if (device.GetMountPoint(&directory) != B_OK)
848 return;
849 } else
850 return; // shouldn't happen
852 directory.Append(kPackagesDirectoryPath);
853 BDirectory dir(directory.Path());
854 if (dir.InitCheck() != B_OK)
855 return;
857 BEntry packageEntry;
858 BList packages;
859 while (dir.GetNextEntry(&packageEntry) == B_OK) {
860 Package* package = Package::PackageFromEntry(packageEntry);
861 if (package != NULL)
862 packages.AddItem(package);
864 packages.SortItems(_ComparePackages);
866 fPackagesView->AddPackages(packages, new BMessage(PACKAGE_CHECKBOX));
867 PostMessage(PACKAGE_CHECKBOX);
871 void
872 InstallerWindow::_SetStatusMessage(const char *text)
874 fStatusView->SetText(text);
876 // Make the status view taller if needed
877 BSize size = fStatusView->ExplicitMinSize();
878 float heightNeeded = fStatusView->TextHeight(0, fStatusView->CountLines()) + 15.0;
879 if (heightNeeded > size.height)
880 fStatusView->SetExplicitMinSize(BSize(size.width, heightNeeded));
884 void
885 InstallerWindow::_SetCopyEngineCancelSemaphore(sem_id id, bool alreadyLocked)
887 if (fCopyEngineCancelSemaphore >= 0) {
888 if (!alreadyLocked)
889 acquire_sem(fCopyEngineCancelSemaphore);
890 delete_sem(fCopyEngineCancelSemaphore);
892 fCopyEngineCancelSemaphore = id;
896 void
897 InstallerWindow::_QuitCopyEngine(bool askUser)
899 if (fCopyEngineCancelSemaphore < 0)
900 return;
902 // First of all block the copy engine, so that it doesn't continue
903 // while the alert is showing, which would be irritating.
904 acquire_sem(fCopyEngineCancelSemaphore);
906 bool quit = true;
907 if (askUser) {
908 BAlert* alert = new BAlert("cancel",
909 B_TRANSLATE("Are you sure you want to to stop the installation?"),
910 B_TRANSLATE_COMMENT("Continue", "In alert after pressing Stop"),
911 B_TRANSLATE_COMMENT("Stop", "In alert after pressing Stop"), 0,
912 B_WIDTH_AS_USUAL, B_STOP_ALERT);
913 alert->SetShortcut(1, B_ESCAPE);
914 quit = alert->Go() != 0;
917 if (quit) {
918 // Make it quit by having it's lock fail...
919 _SetCopyEngineCancelSemaphore(-1, true);
920 } else
921 release_sem(fCopyEngineCancelSemaphore);
925 // #pragma mark -
929 InstallerWindow::_ComparePackages(const void* firstArg, const void* secondArg)
931 const Group* group1 = *static_cast<const Group* const *>(firstArg);
932 const Group* group2 = *static_cast<const Group* const *>(secondArg);
933 const Package* package1 = dynamic_cast<const Package*>(group1);
934 const Package* package2 = dynamic_cast<const Package*>(group2);
935 int sameGroup = strcmp(group1->GroupName(), group2->GroupName());
936 if (sameGroup != 0)
937 return sameGroup;
938 if (package2 == NULL)
939 return -1;
940 if (package1 == NULL)
941 return 1;
942 return strcmp(package1->Name(), package2->Name());