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