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.
8 #include "InstallerWindow.h"
14 #include <Application.h>
19 #include <ControlLook.h>
20 #include <Directory.h>
21 #include <FindDirectory.h>
22 #include <LayoutBuilder.h>
23 #include <LayoutUtils.h>
26 #include <MenuField.h>
28 #include <PopUpMenu.h>
31 #include <ScrollView.h>
32 #include <SeparatorView.h>
33 #include <SpaceLayoutItem.h>
34 #include <StatusBar.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
{
68 LogoView(const BRect
& frame
);
72 virtual void Draw(BRect update
);
74 virtual void GetPreferredSize(float* _width
,
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
)
95 BView("logoview", B_WILL_DRAW
| B_FULL_UPDATE_ON_RESIZE
)
101 LogoView::~LogoView(void)
108 LogoView::Draw(BRect update
)
113 BRect
bounds(Bounds());
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
);
123 LogoView::GetPreferredSize(float* _width
, float* _height
)
128 width
= fLogo
->Bounds().Width();
129 height
= fLogo
->Bounds().Height();
141 fLogo
= BTranslationUtils::GetBitmap(B_PNG_FORMAT
, "logo.png");
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
,
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,
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
),
195 fSrcMenu
= new BPopUpMenu(B_TRANSLATE("scanning" B_UTF8_ELLIPSIS
),
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:"),
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
,
212 fPackagesSwitch
->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT
,
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)
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)
273 .AddGroup(B_HORIZONTAL
, B_USE_WINDOW_SPACING
)
274 .Add(fLaunchDriveSetupButton
)
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"
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
);
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
);
321 fLaunchDriveSetupButton
->SetEnabled(!fDriveSetupLaunched
);
322 fLaunchBootManagerItem
->SetEnabled(!fBootManagerLaunched
);
326 PostMessage(START_SCAN
);
330 InstallerWindow::~InstallerWindow()
332 _SetCopyEngineCancelSemaphore(-1);
333 be_roster
->StopWatching(this);
338 InstallerWindow::MessageReceived(BMessage
*msg
)
343 _SetCopyEngineCancelSemaphore(-1);
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
);
357 _DisableInterface(false);
359 fProgressLayoutItem
->SetVisible(false);
360 fPkgSwitchLayoutItem
->SetVisible(true);
361 _ShowOptionalPackages();
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
)
380 _SetCopyEngineCancelSemaphore(create_sem(1,
381 "copy engine cancel"));
383 BList
* list
= new BList();
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(),
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);
405 _QuitCopyEngine(true);
409 PostMessage(B_QUIT_REQUESTED
);
415 case SHOW_BOTTOM_MESSAGE
:
416 _ShowOptionalPackages();
418 case SOURCE_PARTITION
:
422 case TARGET_PARTITION
:
425 case LAUNCH_DRIVE_SETUP
:
429 _LaunchBootManager();
431 case PACKAGE_CHECKBOX
:
434 fPackagesView
->GetTotalSizeAsString(buffer
, sizeof(buffer
));
436 snprintf(string
, sizeof(string
),
437 B_TRANSLATE("Additional disk space required: %s"), buffer
);
438 fSizeView
->SetText(string
);
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
);
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)
458 if (msg
->FindFloat("progress", &progress
) == B_OK
) {
459 const char* currentItem
;
460 if (msg
->FindString("item", ¤tItem
) != B_OK
) {
461 currentItem
= B_TRANSLATE_COMMENT("???",
462 "Unknown currently copied item");
464 BString trailingLabel
;
467 if (msg
->FindInt32("current", ¤tCount
) == B_OK
468 && msg
->FindInt32("maximum", &maximumCount
) == B_OK
) {
470 snprintf(buffer
, sizeof(buffer
),
471 B_TRANSLATE_COMMENT("%1ld of %2ld",
472 "number of files copied"),
473 currentCount
, maximumCount
);
474 trailingLabel
<< buffer
;
477 B_TRANSLATE_COMMENT("?? of ??", "Unknown progress");
479 fProgressBar
->SetTo(progress
, currentItem
,
480 trailingLabel
.String());
483 if (msg
->FindString("status", &status
) == B_OK
) {
484 fLastStatus
= fStatusView
->Text();
485 _SetStatusMessage(status
);
487 _SetStatusMessage(fLastStatus
.String());
491 case MSG_INSTALL_FINISHED
:
494 _SetCopyEngineCancelSemaphore(-1);
496 PartitionMenuItem
* dstItem
497 = (PartitionMenuItem
*)fDestMenu
->FindMarked();
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"));
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();
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
)
532 bool isDriveSetup
= !strcasecmp(signature
, kDriveSetupSignature
);
533 bool isBootManager
= !strcasecmp(signature
, kBootManagerSignature
);
534 if (isDriveSetup
|| isBootManager
) {
535 bool scanPartitions
= false;
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
;
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 "
553 } else if (fDriveSetupLaunched
) {
554 _SetStatusMessage(B_TRANSLATE("Running DriveSetup"
556 "\n\nClose DriveSetup to continue with the "
558 } else if (fBootManagerLaunched
) {
559 _SetStatusMessage(B_TRANSLATE("Running Boot Manager"
561 "\n\nClose Boot Manager to continue with the "
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.
575 case MSG_WRITE_BOOT_SECTOR
:
576 fWorkerThread
->WriteBootSector(fDestMenu
);
580 BWindow::MessageReceived(msg
);
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."),
598 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
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
);
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
);
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)
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)
638 _QuitCopyEngine(false);
639 fWorkerThread
->PostMessage(B_QUIT_REQUESTED
);
640 be_app
->PostMessage(B_QUIT_REQUESTED
);
649 InstallerWindow::_ShowOptionalPackages()
651 if (fPackagesLayoutItem
&& fSizeViewLayoutItem
) {
652 fPackagesLayoutItem
->SetVisible(fPackagesSwitch
->Value());
653 fSizeViewLayoutItem
->SetVisible(fPackagesSwitch
->Value());
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...
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());
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
);
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
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...
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());
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
);
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
);
726 InstallerWindow::_ScanPartitions()
728 _SetStatusMessage(B_TRANSLATE("Scanning for disks" B_UTF8_ELLIPSIS
));
731 while ((item
= fSrcMenu
->RemoveItem((int32
)0)))
733 while ((item
= fDestMenu
->RemoveItem((int32
)0)))
736 fWorkerThread
->ScanDisksPartitions(fSrcMenu
, fDestMenu
);
738 if (fSrcMenu
->ItemAt(0) != NULL
)
746 InstallerWindow::_UpdateControls()
748 PartitionMenuItem
* srcItem
= (PartitionMenuItem
*)fSrcMenu
->FindMarked();
751 label
= srcItem
->MenuLabel();
753 if (fSrcMenu
->CountItems() == 0)
754 label
= B_TRANSLATE_COMMENT("<none>", "No partition available");
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
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
769 dstItem
->SetEnabled(false);
770 dstItem
->SetMarked(false);
772 dstItem
->SetEnabled(dstItem
->IsValidTarget());
774 if (dstItem
->IsEnabled())
775 foundOneSuitableTarget
= true;
778 PartitionMenuItem
* dstItem
= (PartitionMenuItem
*)fDestMenu
->FindMarked();
780 label
= dstItem
->MenuLabel();
782 if (fDestMenu
->CountItems() == 0)
783 label
= B_TRANSLATE_COMMENT("<none>", "No partition available");
785 label
= B_TRANSLATE("Please choose target");
787 fDestMenuField
->MenuItem()->SetLabel(label
.String());
789 if (srcItem
!= NULL
&& dstItem
!= NULL
) {
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\"."));
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
) {
812 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("Write boot sector to '%s'"),
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
);
832 InstallerWindow::_PublishPackages()
834 fPackagesView
->Clean();
835 PartitionMenuItem
*item
= (PartitionMenuItem
*)fSrcMenu
->FindMarked();
840 BDiskDeviceRoster roster
;
842 BPartition
*partition
;
843 if (roster
.GetPartitionWithID(item
->ID(), &device
, &partition
) == B_OK
) {
844 if (partition
->GetMountPoint(&directory
) != B_OK
)
846 } else if (roster
.GetDeviceWithID(item
->ID(), &device
) == B_OK
) {
847 if (device
.GetMountPoint(&directory
) != B_OK
)
850 return; // shouldn't happen
852 directory
.Append(kPackagesDirectoryPath
);
853 BDirectory
dir(directory
.Path());
854 if (dir
.InitCheck() != B_OK
)
859 while (dir
.GetNextEntry(&packageEntry
) == B_OK
) {
860 Package
* package
= Package::PackageFromEntry(packageEntry
);
862 packages
.AddItem(package
);
864 packages
.SortItems(_ComparePackages
);
866 fPackagesView
->AddPackages(packages
, new BMessage(PACKAGE_CHECKBOX
));
867 PostMessage(PACKAGE_CHECKBOX
);
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
));
885 InstallerWindow::_SetCopyEngineCancelSemaphore(sem_id id
, bool alreadyLocked
)
887 if (fCopyEngineCancelSemaphore
>= 0) {
889 acquire_sem(fCopyEngineCancelSemaphore
);
890 delete_sem(fCopyEngineCancelSemaphore
);
892 fCopyEngineCancelSemaphore
= id
;
897 InstallerWindow::_QuitCopyEngine(bool askUser
)
899 if (fCopyEngineCancelSemaphore
< 0)
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
);
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;
918 // Make it quit by having it's lock fail...
919 _SetCopyEngineCancelSemaphore(-1, true);
921 release_sem(fCopyEngineCancelSemaphore
);
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());
938 if (package2
== NULL
)
940 if (package1
== NULL
)
942 return strcmp(package1
->Name(), package2
->Name());