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