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