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 */ 6 7 #include "InstallerWindow.h" 8 9 #include <stdio.h> 10 #include <string.h> 11 12 #include <Alert.h> 13 #include <Application.h> 14 #include <Autolock.h> 15 #include <Box.h> 16 #include <Button.h> 17 #include <Catalog.h> 18 #include <ControlLook.h> 19 #include <Directory.h> 20 #include <FindDirectory.h> 21 #include <GridLayoutBuilder.h> 22 #include <GroupLayoutBuilder.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> 39 40 #include "tracker_private.h" 41 42 #include "DialogPane.h" 43 #include "PackageViews.h" 44 #include "PartitionMenuItem.h" 45 #include "WorkerThread.h" 46 47 48 #undef B_TRANSLATE_CONTEXT 49 #define B_TRANSLATE_CONTEXT "InstallerWindow" 50 51 #define DRIVESETUP_SIG "application/x-vnd.Haiku-DriveSetup" 52 #define BOOTMAN_SIG "application/x-vnd.Haiku-BootManager" 53 54 55 const uint32 BEGIN_MESSAGE = 'iBGN'; 56 const uint32 SHOW_BOTTOM_MESSAGE = 'iSBT'; 57 const uint32 LAUNCH_DRIVE_SETUP = 'iSEP'; 58 const uint32 LAUNCH_BOOTMAN = 'iWBM'; 59 const uint32 START_SCAN = 'iSSC'; 60 const uint32 PACKAGE_CHECKBOX = 'iPCB'; 61 const uint32 ENCOURAGE_DRIVESETUP = 'iENC'; 62 63 64 class LogoView : public BView { 65 public: 66 LogoView(const BRect& frame); 67 LogoView(); 68 virtual ~LogoView(); 69 70 virtual void Draw(BRect update); 71 72 virtual void GetPreferredSize(float* _width, 73 float* _height); 74 75 private: 76 void _Init(); 77 78 BBitmap* fLogo; 79 }; 80 81 82 LogoView::LogoView(const BRect& frame) 83 : 84 BView(frame, "logoview", B_FOLLOW_LEFT | B_FOLLOW_TOP, 85 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) 86 { 87 _Init(); 88 } 89 90 91 LogoView::LogoView() 92 : 93 BView("logoview", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) 94 { 95 _Init(); 96 } 97 98 99 LogoView::~LogoView(void) 100 { 101 delete fLogo; 102 } 103 104 105 void 106 LogoView::Draw(BRect update) 107 { 108 if (fLogo == NULL) 109 return; 110 111 BRect bounds(Bounds()); 112 BPoint placement; 113 placement.x = (bounds.left + bounds.right - fLogo->Bounds().Width()) / 2; 114 placement.y = (bounds.top + bounds.bottom - fLogo->Bounds().Height()) / 2; 115 116 DrawBitmap(fLogo, placement); 117 } 118 119 120 void 121 LogoView::GetPreferredSize(float* _width, float* _height) 122 { 123 float width = 0.0; 124 float height = 0.0; 125 if (fLogo) { 126 width = fLogo->Bounds().Width(); 127 height = fLogo->Bounds().Height(); 128 } 129 if (_width) 130 *_width = width; 131 if (_height) 132 *_height = height; 133 } 134 135 136 void 137 LogoView::_Init() 138 { 139 fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "logo.png"); 140 } 141 142 143 // #pragma mark - 144 145 146 static BLayoutItem* 147 layout_item_for(BView* view) 148 { 149 BLayout* layout = view->Parent()->GetLayout(); 150 int32 index = layout->IndexOfView(view); 151 return layout->ItemAt(index); 152 } 153 154 155 InstallerWindow::InstallerWindow() 156 : 157 BWindow(BRect(-2000, -2000, -1800, -1800), 158 B_TRANSLATE_SYSTEM_NAME("Installer"), B_TITLED_WINDOW, 159 B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS), 160 fEncouragedToSetupPartitions(false), 161 fDriveSetupLaunched(false), 162 fBootmanLaunched(false), 163 fInstallStatus(kReadyForInstall), 164 fWorkerThread(new WorkerThread(this)), 165 fCopyEngineCancelSemaphore(-1) 166 { 167 LogoView* logoView = new LogoView(); 168 169 fStatusView = new BTextView("statusView", be_plain_font, NULL, 170 B_WILL_DRAW); 171 fStatusView->SetInsets(10, 10, 10, 10); 172 fStatusView->MakeEditable(false); 173 fStatusView->MakeSelectable(false); 174 175 BSize logoSize = logoView->MinSize(); 176 logoView->SetExplicitMaxSize(logoSize); 177 fStatusView->SetExplicitMinSize(BSize(logoSize.width * 0.66, 178 B_SIZE_UNSET)); 179 180 fDestMenu = new BPopUpMenu(B_TRANSLATE("scanning" B_UTF8_ELLIPSIS), 181 true, false); 182 fSrcMenu = new BPopUpMenu(B_TRANSLATE("scanning" B_UTF8_ELLIPSIS), 183 true, false); 184 185 fSrcMenuField = new BMenuField("srcMenuField", 186 B_TRANSLATE("Install from:"), fSrcMenu, NULL); 187 fSrcMenuField->SetAlignment(B_ALIGN_RIGHT); 188 189 fDestMenuField = new BMenuField("destMenuField", B_TRANSLATE("Onto:"), 190 fDestMenu, NULL); 191 fDestMenuField->SetAlignment(B_ALIGN_RIGHT); 192 193 fPackagesSwitch = new PaneSwitch("options_button"); 194 fPackagesSwitch->SetLabels(B_TRANSLATE("Hide optional packages"), 195 B_TRANSLATE("Show optional packages")); 196 fPackagesSwitch->SetMessage(new BMessage(SHOW_BOTTOM_MESSAGE)); 197 fPackagesSwitch->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 198 B_SIZE_UNSET)); 199 fPackagesSwitch->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, 200 B_ALIGN_TOP)); 201 202 fPackagesView = new PackagesView("packages_view"); 203 BScrollView* packagesScrollView = new BScrollView("packagesScroll", 204 fPackagesView, B_WILL_DRAW, false, true); 205 206 const char* requiredDiskSpaceString 207 = B_TRANSLATE("Additional disk space required: 0.0 KiB"); 208 fSizeView = new BStringView("size_view", requiredDiskSpaceString); 209 fSizeView->SetAlignment(B_ALIGN_RIGHT); 210 fSizeView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); 211 fSizeView->SetExplicitAlignment( 212 BAlignment(B_ALIGN_RIGHT, B_ALIGN_MIDDLE)); 213 214 fProgressBar = new BStatusBar("progress", 215 B_TRANSLATE("Install progress: ")); 216 fProgressBar->SetMaxValue(100.0); 217 218 fBeginButton = new BButton("begin_button", B_TRANSLATE("Begin"), 219 new BMessage(BEGIN_MESSAGE)); 220 fBeginButton->MakeDefault(true); 221 fBeginButton->SetEnabled(false); 222 223 fLaunchDriveSetupButton = new BButton("setup_button", 224 B_TRANSLATE("Set up partitions" B_UTF8_ELLIPSIS), 225 new BMessage(LAUNCH_DRIVE_SETUP)); 226 227 fLaunchBootmanItem = new BMenuItem(B_TRANSLATE("Set up boot menu"), 228 new BMessage(LAUNCH_BOOTMAN)); 229 fLaunchBootmanItem->SetEnabled(false); 230 231 fMakeBootableItem = new BMenuItem(B_TRANSLATE("Write boot sector"), 232 new BMessage(MSG_WRITE_BOOT_SECTOR)); 233 fMakeBootableItem->SetEnabled(false); 234 BMenuBar* mainMenu = new BMenuBar("main menu"); 235 BMenu* toolsMenu = new BMenu(B_TRANSLATE("Tools")); 236 toolsMenu->AddItem(fLaunchBootmanItem); 237 toolsMenu->AddItem(fMakeBootableItem); 238 mainMenu->AddItem(toolsMenu); 239 240 float spacing = be_control_look->DefaultItemSpacing(); 241 242 SetLayout(new BGroupLayout(B_HORIZONTAL)); 243 AddChild(BGroupLayoutBuilder(B_VERTICAL, 0) 244 .Add(mainMenu) 245 .Add(BGroupLayoutBuilder(B_HORIZONTAL, 0) 246 .Add(logoView) 247 .Add(fStatusView) 248 ) 249 .Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER)) 250 .Add(BGroupLayoutBuilder(B_VERTICAL, spacing) 251 .Add(BGridLayoutBuilder(0, spacing) 252 .Add(fSrcMenuField->CreateLabelLayoutItem(), 0, 0) 253 .Add(fSrcMenuField->CreateMenuBarLayoutItem(), 1, 0) 254 .Add(fDestMenuField->CreateLabelLayoutItem(), 0, 1) 255 .Add(fDestMenuField->CreateMenuBarLayoutItem(), 1, 1) 256 257 .Add(BSpaceLayoutItem::CreateVerticalStrut(5), 0, 2, 2) 258 259 .Add(fPackagesSwitch, 0, 3, 2) 260 .Add(packagesScrollView, 0, 4, 2) 261 .Add(fProgressBar, 0, 5, 2) 262 .Add(fSizeView, 0, 6, 2) 263 ) 264 265 .Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing) 266 .Add(fLaunchDriveSetupButton) 267 .AddGlue() 268 .Add(fBeginButton) 269 ) 270 .SetInsets(spacing, spacing, spacing, spacing) 271 ) 272 ); 273 274 // Make the optional packages and progress bar invisible on start 275 fPackagesLayoutItem = layout_item_for(packagesScrollView); 276 fPkgSwitchLayoutItem = layout_item_for(fPackagesSwitch); 277 fSizeViewLayoutItem = layout_item_for(fSizeView); 278 fProgressLayoutItem = layout_item_for(fProgressBar); 279 280 fPackagesLayoutItem->SetVisible(false); 281 fSizeViewLayoutItem->SetVisible(false); 282 fProgressLayoutItem->SetVisible(false); 283 284 // Setup tool tips for the non-obvious features 285 fLaunchDriveSetupButton->SetToolTip( 286 B_TRANSLATE("Launch the DriveSetup utility to partition\n" 287 "available hard drives and other media.\n" 288 "Partitions can be initialized with the\n" 289 "Be File System needed for a Haiku boot\n" 290 "partition.")); 291 // fLaunchBootmanItem->SetToolTip( 292 // B_TRANSLATE("Install or uninstall the Haiku boot menu, which allows " 293 // "to choose an operating system to boot when the computer starts.\n" 294 // "If this computer already has a boot manager such as GRUB installed, " 295 // "it is better to add Haiku to that menu than to overwrite it.")); 296 // fMakeBootableItem->SetToolTip( 297 // B_TRANSLATE("Writes the Haiku boot code to the partition start\n" 298 // "sector. This step is automatically performed by\n" 299 // "the installation, but you can manually make a\n" 300 // "partition bootable in case you do not need to\n" 301 // "perform an installation.")); 302 303 // finish creating window 304 if (!be_roster->IsRunning(kDeskbarSignature)) 305 SetFlags(Flags() | B_NOT_MINIMIZABLE); 306 307 CenterOnScreen(); 308 Show(); 309 310 // Register to receive notifications when apps launch or quit... 311 be_roster->StartWatching(this); 312 // ... and check the two we are interested in. 313 fDriveSetupLaunched = be_roster->IsRunning(DRIVESETUP_SIG); 314 fBootmanLaunched = be_roster->IsRunning(BOOTMAN_SIG); 315 316 if (Lock()) { 317 fLaunchDriveSetupButton->SetEnabled(!fDriveSetupLaunched); 318 fLaunchBootmanItem->SetEnabled(!fBootmanLaunched); 319 Unlock(); 320 } 321 322 PostMessage(START_SCAN); 323 } 324 325 326 InstallerWindow::~InstallerWindow() 327 { 328 _SetCopyEngineCancelSemaphore(-1); 329 be_roster->StopWatching(this); 330 } 331 332 333 void 334 InstallerWindow::MessageReceived(BMessage *msg) 335 { 336 switch (msg->what) { 337 case MSG_RESET: 338 { 339 _SetCopyEngineCancelSemaphore(-1); 340 341 status_t error; 342 if (msg->FindInt32("error", &error) == B_OK) { 343 char errorMessage[2048]; 344 snprintf(errorMessage, sizeof(errorMessage), 345 B_TRANSLATE("An error was encountered and the " 346 "installation was not completed:\n\n" 347 "Error: %s"), strerror(error)); 348 (new BAlert("error", errorMessage, B_TRANSLATE("OK")))->Go(); 349 } 350 351 _DisableInterface(false); 352 353 fProgressLayoutItem->SetVisible(false); 354 fPkgSwitchLayoutItem->SetVisible(true); 355 _ShowOptionalPackages(); 356 _UpdateControls(); 357 break; 358 } 359 case START_SCAN: 360 _ScanPartitions(); 361 break; 362 case BEGIN_MESSAGE: 363 switch (fInstallStatus) { 364 case kReadyForInstall: 365 { 366 _SetCopyEngineCancelSemaphore(create_sem(1, 367 "copy engine cancel")); 368 369 BList* list = new BList(); 370 int32 size = 0; 371 fPackagesView->GetPackagesToInstall(list, &size); 372 fWorkerThread->SetLock(fCopyEngineCancelSemaphore); 373 fWorkerThread->SetPackagesList(list); 374 fWorkerThread->SetSpaceRequired(size); 375 fInstallStatus = kInstalling; 376 fWorkerThread->StartInstall(); 377 fBeginButton->SetLabel(B_TRANSLATE("Stop")); 378 _DisableInterface(true); 379 380 fProgressBar->SetTo(0.0, NULL, NULL); 381 382 fPkgSwitchLayoutItem->SetVisible(false); 383 fPackagesLayoutItem->SetVisible(false); 384 fSizeViewLayoutItem->SetVisible(false); 385 fProgressLayoutItem->SetVisible(true); 386 break; 387 } 388 case kInstalling: 389 { 390 _QuitCopyEngine(true); 391 break; 392 } 393 case kFinished: 394 PostMessage(B_QUIT_REQUESTED); 395 break; 396 case kCancelled: 397 break; 398 } 399 break; 400 case SHOW_BOTTOM_MESSAGE: 401 _ShowOptionalPackages(); 402 break; 403 case SOURCE_PARTITION: 404 _PublishPackages(); 405 _UpdateControls(); 406 break; 407 case TARGET_PARTITION: 408 _UpdateControls(); 409 break; 410 case LAUNCH_DRIVE_SETUP: 411 _LaunchDriveSetup(); 412 break; 413 case LAUNCH_BOOTMAN: 414 _LaunchBootman(); 415 break; 416 case PACKAGE_CHECKBOX: 417 { 418 char buffer[15]; 419 fPackagesView->GetTotalSizeAsString(buffer, sizeof(buffer)); 420 char string[256]; 421 snprintf(string, sizeof(string), 422 B_TRANSLATE("Additional disk space required: %s"), buffer); 423 fSizeView->SetText(string); 424 break; 425 } 426 case ENCOURAGE_DRIVESETUP: 427 { 428 (new BAlert("use drive setup", B_TRANSLATE("No partitions have " 429 "been found that are suitable for installation. Please set " 430 "up partitions and initialize at least one partition with the " 431 "Be File System."), B_TRANSLATE("OK")))->Go(); 432 } 433 case MSG_STATUS_MESSAGE: 434 { 435 // TODO: Was this supposed to prevent status messages still arriving 436 // after the copy engine was shut down? 437 // if (fInstallStatus != kInstalling) 438 // break; 439 float progress; 440 if (msg->FindFloat("progress", &progress) == B_OK) { 441 const char* currentItem; 442 if (msg->FindString("item", ¤tItem) != B_OK) { 443 currentItem = B_TRANSLATE_COMMENT("???", 444 "Unknown currently copied item"); 445 } 446 BString trailingLabel; 447 int32 currentCount; 448 int32 maximumCount; 449 if (msg->FindInt32("current", ¤tCount) == B_OK 450 && msg->FindInt32("maximum", &maximumCount) == B_OK) { 451 char buffer[64]; 452 snprintf(buffer, sizeof(buffer), 453 B_TRANSLATE_COMMENT("%1ld of %2ld", 454 "number of files copied"), 455 currentCount, maximumCount); 456 trailingLabel << buffer; 457 } else { 458 trailingLabel << 459 B_TRANSLATE_COMMENT("?? of ??", "Unknown progress"); 460 } 461 fProgressBar->SetTo(progress, currentItem, 462 trailingLabel.String()); 463 } else { 464 const char *status; 465 if (msg->FindString("status", &status) == B_OK) { 466 fLastStatus = fStatusView->Text(); 467 _SetStatusMessage(status); 468 } else 469 _SetStatusMessage(fLastStatus.String()); 470 } 471 break; 472 } 473 case MSG_INSTALL_FINISHED: 474 { 475 476 _SetCopyEngineCancelSemaphore(-1); 477 478 fBeginButton->SetLabel(B_TRANSLATE("Quit")); 479 480 PartitionMenuItem* dstItem 481 = (PartitionMenuItem*)fDestMenu->FindMarked(); 482 483 char status[1024]; 484 if (be_roster->IsRunning(kDeskbarSignature)) { 485 snprintf(status, sizeof(status), B_TRANSLATE("Installation " 486 "completed. Boot sector has been written to '%s'. Press " 487 "Quit to leave the Installer or choose a new target " 488 "volume to perform another installation."), 489 dstItem ? dstItem->Name() : B_TRANSLATE_COMMENT("???", 490 "Unknown partition name")); 491 } else { 492 snprintf(status, sizeof(status), B_TRANSLATE("Installation " 493 "completed. Boot sector has been written to '%s'. Press " 494 "Quit to restart the computer or choose a new target " 495 "volume to perform another installation."), 496 dstItem ? dstItem->Name() : B_TRANSLATE_COMMENT("???", 497 "Unknown partition name")); 498 } 499 500 _SetStatusMessage(status); 501 fInstallStatus = kFinished; 502 _DisableInterface(false); 503 fProgressLayoutItem->SetVisible(false); 504 fPkgSwitchLayoutItem->SetVisible(true); 505 _ShowOptionalPackages(); 506 break; 507 } 508 case B_SOME_APP_LAUNCHED: 509 case B_SOME_APP_QUIT: 510 { 511 const char *signature; 512 if (msg->FindString("be:signature", &signature) != B_OK) 513 break; 514 bool isDriveSetup = strcasecmp(signature, DRIVESETUP_SIG) == 0; 515 bool isBootman = strcasecmp(signature, BOOTMAN_SIG) == 0; 516 if (isDriveSetup || isBootman) { 517 bool scanPartitions = false; 518 if (isDriveSetup) { 519 bool launched = msg->what == B_SOME_APP_LAUNCHED; 520 // We need to scan partitions if DriveSetup has quit. 521 scanPartitions = fDriveSetupLaunched && !launched; 522 fDriveSetupLaunched = launched; 523 } 524 if (isBootman) 525 fBootmanLaunched = msg->what == B_SOME_APP_LAUNCHED; 526 527 fBeginButton->SetEnabled( 528 !fDriveSetupLaunched && !fBootmanLaunched); 529 _DisableInterface(fDriveSetupLaunched || fBootmanLaunched); 530 if (fDriveSetupLaunched && fBootmanLaunched) { 531 _SetStatusMessage(B_TRANSLATE("Running Boot Manager and " 532 "DriveSetup" B_UTF8_ELLIPSIS 533 "\n\nClose both applications to continue with the " 534 "installation.")); 535 } else if (fDriveSetupLaunched) { 536 _SetStatusMessage(B_TRANSLATE("Running DriveSetup" 537 B_UTF8_ELLIPSIS 538 "\n\nClose DriveSetup to continue with the " 539 "installation.")); 540 } else if (fBootmanLaunched) { 541 _SetStatusMessage(B_TRANSLATE("Running Boot Manager" 542 B_UTF8_ELLIPSIS 543 "\n\nClose Boot Manager to continue with the " 544 "installation.")); 545 } else { 546 // If neither DriveSetup nor Bootman is running, we need 547 // to scan partitions in case DriveSetup has quit, or 548 // we need to update the guidance message. 549 if (scanPartitions) 550 _ScanPartitions(); 551 else 552 _UpdateControls(); 553 } 554 } 555 break; 556 } 557 case MSG_WRITE_BOOT_SECTOR: 558 fWorkerThread->WriteBootSector(fDestMenu); 559 break; 560 561 default: 562 BWindow::MessageReceived(msg); 563 break; 564 } 565 } 566 567 568 bool 569 InstallerWindow::QuitRequested() 570 { 571 if ((Flags() & B_NOT_MINIMIZABLE) != 0) { 572 // This means Deskbar is not running, i.e. Installer is the only 573 // thing on the screen and we will reboot the machine once it quits. 574 575 if (fDriveSetupLaunched && fBootmanLaunched) { 576 (new BAlert(B_TRANSLATE("Quit Boot Manager and DriveSetup"), 577 B_TRANSLATE("Please close the Boot Manager and DriveSetup " 578 "windows before closing the Installer window."), 579 B_TRANSLATE("OK")))->Go(); 580 return false; 581 } else if (fDriveSetupLaunched) { 582 (new BAlert(B_TRANSLATE("Quit DriveSetup"), 583 B_TRANSLATE("Please close the DriveSetup window before closing " 584 "the Installer window."), B_TRANSLATE("OK")))->Go(); 585 return false; 586 } else if (fBootmanLaunched) { 587 (new BAlert(B_TRANSLATE("Quit Boot Manager"), 588 B_TRANSLATE("Please close the Boot Manager window before " 589 "closing the Installer window."), B_TRANSLATE("OK")))->Go(); 590 return false; 591 } 592 593 if (fInstallStatus != kFinished) 594 if ((new BAlert(B_TRANSLATE_SYSTEM_NAME("Installer"), 595 B_TRANSLATE("Are you sure you want to abort the installation " 596 "and restart the system?"), 597 B_TRANSLATE("Cancel"), B_TRANSLATE("Restart system"), NULL, 598 B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() == 0) 599 return false; 600 601 } else if (fInstallStatus == kInstalling) { 602 if ((new BAlert(B_TRANSLATE_SYSTEM_NAME("Installer"), 603 B_TRANSLATE("Are you sure you want to abort the installation?"), 604 B_TRANSLATE("Cancel"), B_TRANSLATE("Abort"), NULL, 605 B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() == 0) 606 return false; 607 } 608 609 _QuitCopyEngine(false); 610 fWorkerThread->PostMessage(B_QUIT_REQUESTED); 611 be_app->PostMessage(B_QUIT_REQUESTED); 612 return true; 613 } 614 615 616 // #pragma mark - 617 618 619 void 620 InstallerWindow::_ShowOptionalPackages() 621 { 622 if (fPackagesLayoutItem && fSizeViewLayoutItem) { 623 fPackagesLayoutItem->SetVisible(fPackagesSwitch->Value()); 624 fSizeViewLayoutItem->SetVisible(fPackagesSwitch->Value()); 625 } 626 } 627 628 629 void 630 InstallerWindow::_LaunchDriveSetup() 631 { 632 if (be_roster->Launch(DRIVESETUP_SIG) != B_OK) { 633 // Try really hard to launch it. It's very likely that this fails, 634 // when we run from the CD and there is only an incomplete mime 635 // database for example... 636 BPath path; 637 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &path) != B_OK 638 || path.Append("DriveSetup") != B_OK) { 639 path.SetTo("/boot/system/apps/DriveSetup"); 640 } 641 BEntry entry(path.Path()); 642 entry_ref ref; 643 if (entry.GetRef(&ref) != B_OK || be_roster->Launch(&ref) != B_OK) { 644 BAlert* alert = new BAlert("error", B_TRANSLATE("DriveSetup, the " 645 "application to configure disk partitions, could not be " 646 "launched."), B_TRANSLATE("OK")); 647 alert->Go(); 648 } 649 } 650 } 651 652 653 void 654 InstallerWindow::_LaunchBootman() 655 { 656 // TODO: Currently bootman always tries to install to the "first" harddisk. 657 // If/when it later supports being installed to a certain harddisk, we 658 // would have to pass it the disk that contains the target partition here. 659 if (be_roster->Launch(BOOTMAN_SIG) != B_OK) { 660 // Try really hard to launch it. It's very likely that this fails, 661 // when we run from the CD and there is only an incomplete mime 662 // database for example... 663 BPath path; 664 if (find_directory(B_SYSTEM_BIN_DIRECTORY, &path) != B_OK 665 || path.Append("bootman") != B_OK) { 666 path.SetTo("/boot/system/bin/bootman"); 667 } 668 BEntry entry(path.Path()); 669 entry_ref ref; 670 if (entry.GetRef(&ref) != B_OK || be_roster->Launch(&ref) != B_OK) { 671 BAlert* alert = new BAlert("error", B_TRANSLATE("Bootman, the " 672 "application to configure the Haiku boot menu, could not be " 673 "launched."), B_TRANSLATE("OK")); 674 alert->Go(); 675 } 676 } 677 } 678 679 680 void 681 InstallerWindow::_DisableInterface(bool disable) 682 { 683 fLaunchDriveSetupButton->SetEnabled(!disable); 684 fLaunchBootmanItem->SetEnabled(!disable); 685 fMakeBootableItem->SetEnabled(!disable); 686 fSrcMenuField->SetEnabled(!disable); 687 fDestMenuField->SetEnabled(!disable); 688 } 689 690 691 void 692 InstallerWindow::_ScanPartitions() 693 { 694 _SetStatusMessage(B_TRANSLATE("Scanning for disks" B_UTF8_ELLIPSIS)); 695 696 BMenuItem *item; 697 while ((item = fSrcMenu->RemoveItem((int32)0))) 698 delete item; 699 while ((item = fDestMenu->RemoveItem((int32)0))) 700 delete item; 701 702 fWorkerThread->ScanDisksPartitions(fSrcMenu, fDestMenu); 703 704 if (fSrcMenu->ItemAt(0) != NULL) 705 _PublishPackages(); 706 707 _UpdateControls(); 708 } 709 710 711 void 712 InstallerWindow::_UpdateControls() 713 { 714 PartitionMenuItem* srcItem = (PartitionMenuItem*)fSrcMenu->FindMarked(); 715 BString label; 716 if (srcItem) { 717 label = srcItem->MenuLabel(); 718 } else { 719 if (fSrcMenu->CountItems() == 0) 720 label = B_TRANSLATE_COMMENT("<none>", "No partition available"); 721 else 722 label = ((PartitionMenuItem*)fSrcMenu->ItemAt(0))->MenuLabel(); 723 } 724 fSrcMenuField->MenuItem()->SetLabel(label.String()); 725 726 // Disable any unsuitable target items, check if at least one partition 727 // is suitable. 728 bool foundOneSuitableTarget = false; 729 for (int32 i = fDestMenu->CountItems() - 1; i >= 0; i--) { 730 PartitionMenuItem* dstItem 731 = (PartitionMenuItem*)fDestMenu->ItemAt(i); 732 if (srcItem != NULL && dstItem->ID() == srcItem->ID()) { 733 // Prevent the user from having picked the same partition as source 734 // and destination. 735 dstItem->SetEnabled(false); 736 dstItem->SetMarked(false); 737 } else 738 dstItem->SetEnabled(dstItem->IsValidTarget()); 739 740 if (dstItem->IsEnabled()) 741 foundOneSuitableTarget = true; 742 } 743 744 PartitionMenuItem* dstItem = (PartitionMenuItem*)fDestMenu->FindMarked(); 745 if (dstItem) { 746 label = dstItem->MenuLabel(); 747 } else { 748 if (fDestMenu->CountItems() == 0) 749 label = B_TRANSLATE_COMMENT("<none>", "No partition available"); 750 else 751 label = B_TRANSLATE("Please choose target"); 752 } 753 fDestMenuField->MenuItem()->SetLabel(label.String()); 754 755 if (srcItem != NULL && dstItem != NULL) { 756 char message[255]; 757 sprintf(message, B_TRANSLATE("Press the Begin button to install from " 758 "'%1s' onto '%2s'."), srcItem->Name(), dstItem->Name()); 759 _SetStatusMessage(message); 760 } else if (srcItem != NULL) { 761 _SetStatusMessage(B_TRANSLATE("Choose the disk you want to install " 762 "onto from the pop-up menu. Then click \"Begin\".")); 763 } else if (dstItem != NULL) { 764 _SetStatusMessage(B_TRANSLATE("Choose the source disk from the " 765 "pop-up menu. Then click \"Begin\".")); 766 } else { 767 _SetStatusMessage(B_TRANSLATE("Choose the source and destination disk " 768 "from the pop-up menus. Then click \"Begin\".")); 769 } 770 771 fInstallStatus = kReadyForInstall; 772 fBeginButton->SetLabel(B_TRANSLATE("Begin")); 773 fBeginButton->SetEnabled(srcItem && dstItem); 774 775 // adjust "Write Boot Sector" and "Set up boot menu" buttons 776 if (dstItem != NULL) { 777 char buffer[256]; 778 snprintf(buffer, sizeof(buffer), B_TRANSLATE("Write boot sector to '%s'"), 779 dstItem->Name()); 780 label = buffer; 781 } else 782 label = B_TRANSLATE("Write boot sector"); 783 fMakeBootableItem->SetEnabled(dstItem != NULL); 784 fMakeBootableItem->SetLabel(label.String()); 785 // TODO: Once bootman support writing to specific disks, enable this, since 786 // we would pass it the disk which contains the target partition. 787 // fLaunchBootmanItem->SetEnabled(dstItem != NULL); 788 789 if (!fEncouragedToSetupPartitions && !foundOneSuitableTarget) { 790 // Focus the users attention on the DriveSetup button 791 fEncouragedToSetupPartitions = true; 792 PostMessage(ENCOURAGE_DRIVESETUP); 793 } 794 } 795 796 797 void 798 InstallerWindow::_PublishPackages() 799 { 800 fPackagesView->Clean(); 801 PartitionMenuItem *item = (PartitionMenuItem *)fSrcMenu->FindMarked(); 802 if (item == NULL) 803 return; 804 805 BPath directory; 806 BDiskDeviceRoster roster; 807 BDiskDevice device; 808 BPartition *partition; 809 if (roster.GetPartitionWithID(item->ID(), &device, &partition) == B_OK) { 810 if (partition->GetMountPoint(&directory) != B_OK) 811 return; 812 } else if (roster.GetDeviceWithID(item->ID(), &device) == B_OK) { 813 if (device.GetMountPoint(&directory) != B_OK) 814 return; 815 } else 816 return; // shouldn't happen 817 818 directory.Append(PACKAGES_DIRECTORY); 819 BDirectory dir(directory.Path()); 820 if (dir.InitCheck() != B_OK) 821 return; 822 823 BEntry packageEntry; 824 BList packages; 825 while (dir.GetNextEntry(&packageEntry) == B_OK) { 826 Package* package = Package::PackageFromEntry(packageEntry); 827 if (package != NULL) 828 packages.AddItem(package); 829 } 830 packages.SortItems(_ComparePackages); 831 832 fPackagesView->AddPackages(packages, new BMessage(PACKAGE_CHECKBOX)); 833 PostMessage(PACKAGE_CHECKBOX); 834 } 835 836 837 void 838 InstallerWindow::_SetStatusMessage(const char *text) 839 { 840 fStatusView->SetText(text); 841 } 842 843 844 void 845 InstallerWindow::_SetCopyEngineCancelSemaphore(sem_id id, bool alreadyLocked) 846 { 847 if (fCopyEngineCancelSemaphore >= 0) { 848 if (!alreadyLocked) 849 acquire_sem(fCopyEngineCancelSemaphore); 850 delete_sem(fCopyEngineCancelSemaphore); 851 } 852 fCopyEngineCancelSemaphore = id; 853 } 854 855 856 void 857 InstallerWindow::_QuitCopyEngine(bool askUser) 858 { 859 if (fCopyEngineCancelSemaphore < 0) 860 return; 861 862 // First of all block the copy engine, so that it doesn't continue 863 // while the alert is showing, which would be irritating. 864 acquire_sem(fCopyEngineCancelSemaphore); 865 866 bool quit = true; 867 if (askUser) { 868 quit = (new BAlert("cancel", 869 B_TRANSLATE("Are you sure you want to to stop the installation?"), 870 B_TRANSLATE_COMMENT("Continue", "In alert after pressing Stop"), 871 B_TRANSLATE_COMMENT("Stop", "In alert after pressing Stop"), 0, 872 B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0; 873 } 874 875 if (quit) { 876 // Make it quit by having it's lock fail... 877 _SetCopyEngineCancelSemaphore(-1, true); 878 } else 879 release_sem(fCopyEngineCancelSemaphore); 880 } 881 882 883 // #pragma mark - 884 885 886 int 887 InstallerWindow::_ComparePackages(const void* firstArg, const void* secondArg) 888 { 889 const Group* group1 = *static_cast<const Group* const *>(firstArg); 890 const Group* group2 = *static_cast<const Group* const *>(secondArg); 891 const Package* package1 = dynamic_cast<const Package*>(group1); 892 const Package* package2 = dynamic_cast<const Package*>(group2); 893 int sameGroup = strcmp(group1->GroupName(), group2->GroupName()); 894 if (sameGroup != 0) 895 return sameGroup; 896 if (package2 == NULL) 897 return -1; 898 if (package1 == NULL) 899 return 1; 900 return strcmp(package1->Name(), package2->Name()); 901 } 902 903 904