1 /* 2 * Copyright 2005, Jérôme DUVAL. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <Alert.h> 7 #include <Application.h> 8 #include <Autolock.h> 9 #include <Box.h> 10 #include <ClassInfo.h> 11 #include <Directory.h> 12 #include <Path.h> 13 #include <PopUpMenu.h> 14 #include <Roster.h> 15 #include <string.h> 16 #include <String.h> 17 #include <TranslationUtils.h> 18 #include "InstallerWindow.h" 19 #include "PartitionMenuItem.h" 20 21 #define DRIVESETUP_SIG "application/x-vnd.Be-DRV$" 22 23 const uint32 BEGIN_MESSAGE = 'iBGN'; 24 const uint32 SHOW_BOTTOM_MESSAGE = 'iSBT'; 25 const uint32 SETUP_MESSAGE = 'iSEP'; 26 const uint32 START_SCAN = 'iSSC'; 27 const uint32 PACKAGE_CHECKBOX = 'iPCB'; 28 29 class LogoView : public BBox { 30 public: 31 LogoView(const BRect &r); 32 ~LogoView(void); 33 virtual void Draw(BRect update); 34 private: 35 BBitmap *fLogo; 36 BPoint fDrawPoint; 37 }; 38 39 40 LogoView::LogoView(const BRect &r) 41 : BBox(r, "logoview", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW, B_NO_BORDER) 42 { 43 fLogo = BTranslationUtils::GetBitmap('PNG ', "haikulogo.png"); 44 if (fLogo) { 45 fDrawPoint.x = (r.Width() - fLogo->Bounds().Width()) / 2; 46 fDrawPoint.y = 0; 47 } 48 } 49 50 51 LogoView::~LogoView(void) 52 { 53 delete fLogo; 54 } 55 56 57 void 58 LogoView::Draw(BRect update) 59 { 60 if (fLogo) 61 DrawBitmap(fLogo, fDrawPoint); 62 } 63 64 65 InstallerWindow::InstallerWindow(BRect frame_rect) 66 : BWindow(frame_rect, "Installer", B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE), 67 fDriveSetupLaunched(false), 68 fLastSrcItem(NULL), 69 fLastTargetItem(NULL) 70 { 71 fCopyEngine = new CopyEngine(this); 72 73 BRect bounds = Bounds(); 74 bounds.bottom += 1; 75 bounds.right += 1; 76 fBackBox = new BBox(bounds, NULL, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, B_FANCY_BORDER); 77 AddChild(fBackBox); 78 79 BRect logoRect = fBackBox->Bounds(); 80 logoRect.left += 1; 81 logoRect.top = 12; 82 logoRect.right -= 226; 83 logoRect.bottom = logoRect.top + 46 + B_H_SCROLL_BAR_HEIGHT; 84 LogoView *logoView = new LogoView(logoRect); 85 fBackBox->AddChild(logoView); 86 87 BRect statusRect(bounds.right - 222, logoRect.top + 2, bounds.right - 14, logoRect.bottom - B_H_SCROLL_BAR_HEIGHT + 4); 88 BRect textRect(statusRect); 89 textRect.OffsetTo(B_ORIGIN); 90 textRect.InsetBy(2, 2); 91 fStatusView = new BTextView(statusRect, "statusView", textRect, 92 be_plain_font, NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); 93 fStatusView->MakeEditable(false); 94 fStatusView->MakeSelectable(false); 95 96 BScrollView *scroll = new BScrollView("statusScroll", fStatusView, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS); 97 fBackBox->AddChild(scroll); 98 99 fBeginButton = new BButton(BRect(bounds.right - 90, bounds.bottom - 35, bounds.right - 11, bounds.bottom - 11), 100 "begin_button", "Begin", new BMessage(BEGIN_MESSAGE), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 101 fBeginButton->MakeDefault(true); 102 fBackBox->AddChild(fBeginButton); 103 104 fSetupButton = new BButton(BRect(bounds.left + 11, bounds.bottom - 35, 105 bounds.left + be_plain_font->StringWidth("Setup partitions") + 36, bounds.bottom - 22), 106 "setup_button", "Setup partitions" B_UTF8_ELLIPSIS, new BMessage(SETUP_MESSAGE), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); 107 fBackBox->AddChild(fSetupButton); 108 fSetupButton->Hide(); 109 110 fPackagesView = new PackagesView(BRect(bounds.left + 12, bounds.top + 4, bounds.right - 15 - B_V_SCROLL_BAR_WIDTH, bounds.bottom - 61), "packages_view"); 111 fPackagesScrollView = new BScrollView("packagesScroll", fPackagesView, B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW, 112 false, true); 113 fBackBox->AddChild(fPackagesScrollView); 114 fPackagesScrollView->Hide(); 115 116 fDrawButton = new DrawButton(BRect(bounds.left + 12, bounds.bottom - 33, bounds.left + 120, bounds.bottom - 20), 117 "options_button", "Fewer options", "More options", new BMessage(SHOW_BOTTOM_MESSAGE)); 118 fBackBox->AddChild(fDrawButton); 119 120 fDestMenu = new BPopUpMenu("scanning" B_UTF8_ELLIPSIS, true, false); 121 fSrcMenu = new BPopUpMenu("scanning" B_UTF8_ELLIPSIS, true, false); 122 123 BRect fieldRect(bounds.left + 50, bounds.top + 70, bounds.right - 13, bounds.top + 90); 124 fSrcMenuField = new BMenuField(fieldRect, "srcMenuField", 125 "Install from: ", fSrcMenu); 126 fSrcMenuField->SetDivider(bounds.right - 274); 127 fSrcMenuField->SetAlignment(B_ALIGN_RIGHT); 128 fBackBox->AddChild(fSrcMenuField); 129 130 fieldRect.OffsetBy(0, 23); 131 fDestMenuField = new BMenuField(fieldRect, "destMenuField", 132 "Onto: ", fDestMenu); 133 fDestMenuField->SetDivider(bounds.right - 274); 134 fDestMenuField->SetAlignment(B_ALIGN_RIGHT); 135 fBackBox->AddChild(fDestMenuField); 136 137 BRect sizeRect = fBackBox->Bounds(); 138 sizeRect.top = 105; 139 sizeRect.bottom = sizeRect.top + 15; 140 sizeRect.right -= 12; 141 sizeRect.left = sizeRect.right - be_plain_font->StringWidth("Disk space required: 0.0 KB") - 40; 142 fSizeView = new BStringView(sizeRect, "size_view", "Disk space required: 0.0 KB", B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 143 fSizeView->SetAlignment(B_ALIGN_RIGHT); 144 fBackBox->AddChild(fSizeView); 145 fSizeView->Hide(); 146 147 // finish creating window 148 Show(); 149 150 fDriveSetupLaunched = be_roster->IsRunning(DRIVESETUP_SIG); 151 be_roster->StartWatching(this); 152 153 PostMessage(START_SCAN); 154 } 155 156 InstallerWindow::~InstallerWindow() 157 { 158 be_roster->StopWatching(this); 159 } 160 161 162 void 163 InstallerWindow::MessageReceived(BMessage *msg) 164 { 165 switch (msg->what) { 166 case START_SCAN: 167 StartScan(); 168 break; 169 case BEGIN_MESSAGE: 170 { 171 BList *list = new BList(); 172 int32 size = 0; 173 fPackagesView->GetPackagesToInstall(list, &size); 174 fCopyEngine->SetPackagesList(list); 175 fCopyEngine->SetSpaceRequired(size); 176 BMessenger(fCopyEngine).SendMessage(ENGINE_START); 177 DisableInterface(true); 178 break; 179 } 180 case SHOW_BOTTOM_MESSAGE: 181 ShowBottom(); 182 break; 183 case SRC_PARTITION: 184 if (fLastSrcItem == fSrcMenu->FindMarked()) 185 break; 186 fLastSrcItem = fSrcMenu->FindMarked(); 187 PublishPackages(); 188 AdjustMenus(); 189 break; 190 case TARGET_PARTITION: 191 if (fLastTargetItem == fDestMenu->FindMarked()) 192 break; 193 fLastTargetItem = fDestMenu->FindMarked(); 194 AdjustMenus(); 195 break; 196 case SETUP_MESSAGE: 197 LaunchDriveSetup(); 198 break; 199 case PACKAGE_CHECKBOX: { 200 char buffer[15]; 201 fPackagesView->GetTotalSizeAsString(buffer); 202 char string[255]; 203 sprintf(string, "Disk space required: %s", buffer); 204 fSizeView->SetText(string); 205 break; 206 } 207 case STATUS_MESSAGE: { 208 const char *status; 209 if (msg->FindString("status", &status) == B_OK) { 210 fLastStatus = fStatusView->Text(); 211 SetStatusMessage(status); 212 } else 213 SetStatusMessage(fLastStatus.String()); 214 } 215 case INSTALL_FINISHED: 216 DisableInterface(false); 217 break; 218 case B_SOME_APP_LAUNCHED: 219 case B_SOME_APP_QUIT: 220 { 221 const char *signature; 222 if (msg->FindString("be:signature", &signature) == B_OK 223 && strcasecmp(signature, DRIVESETUP_SIG) == 0) { 224 fDriveSetupLaunched = msg->what == B_SOME_APP_LAUNCHED; 225 DisableInterface(fDriveSetupLaunched); 226 if (fDriveSetupLaunched) 227 SetStatusMessage("Running DriveSetup" B_UTF8_ELLIPSIS "\nClose DriveSetup to continue with the\ninstallation."); 228 else 229 StartScan(); 230 } 231 break; 232 } 233 default: 234 BWindow::MessageReceived(msg); 235 break; 236 } 237 } 238 239 bool 240 InstallerWindow::QuitRequested() 241 { 242 if (fDriveSetupLaunched) { 243 (new BAlert("driveSetup", 244 "Please close the DriveSetup window before closing the\nInstaller window.", "OK"))->Go(); 245 return false; 246 } 247 be_app->PostMessage(B_QUIT_REQUESTED); 248 fCopyEngine->PostMessage(B_QUIT_REQUESTED); 249 return true; 250 } 251 252 253 void 254 InstallerWindow::ShowBottom() 255 { 256 if (fDrawButton->Value()) { 257 ResizeTo(INSTALLER_RIGHT, 306); 258 if (fSetupButton->IsHidden()) 259 fSetupButton->Show(); 260 if (fPackagesScrollView->IsHidden()) 261 fPackagesScrollView->Show(); 262 if (fSizeView->IsHidden()) 263 fSizeView->Show(); 264 } else { 265 if (!fSetupButton->IsHidden()) 266 fSetupButton->Hide(); 267 if (!fPackagesScrollView->IsHidden()) 268 fPackagesScrollView->Hide(); 269 if (!fSizeView->IsHidden()) 270 fSizeView->Hide(); 271 ResizeTo(INSTALLER_RIGHT, 160); 272 } 273 } 274 275 276 void 277 InstallerWindow::LaunchDriveSetup() 278 { 279 if (be_roster->Launch(DRIVESETUP_SIG) != B_OK) 280 fprintf(stderr, "There was an error while launching DriveSetup\n"); 281 } 282 283 284 void 285 InstallerWindow::DisableInterface(bool disable) 286 { 287 fBeginButton->SetEnabled(!disable); 288 fSetupButton->SetEnabled(!disable); 289 fSrcMenuField->SetEnabled(!disable); 290 fDestMenuField->SetEnabled(!disable); 291 } 292 293 294 void 295 InstallerWindow::StartScan() 296 { 297 SetStatusMessage("Scanning for disks" B_UTF8_ELLIPSIS); 298 299 BMenuItem *item; 300 while ((item = fSrcMenu->RemoveItem((int32)0))) 301 delete item; 302 while ((item = fDestMenu->RemoveItem((int32)0))) 303 delete item; 304 305 fCopyEngine->ScanDisksPartitions(fSrcMenu, fDestMenu); 306 307 if (fSrcMenu->ItemAt(0)) { 308 PublishPackages(); 309 } 310 AdjustMenus(); 311 SetStatusMessage("Choose the disk you want to install onto from the pop-up menu. Then click \"Begin\"."); 312 } 313 314 315 void 316 InstallerWindow::AdjustMenus() 317 { 318 PartitionMenuItem *item1 = (PartitionMenuItem *)fSrcMenu->FindMarked(); 319 if (item1) { 320 fSrcMenuField->MenuItem()->SetLabel(item1->MenuLabel()); 321 } else { 322 if (fSrcMenu->CountItems() == 0) 323 fSrcMenuField->MenuItem()->SetLabel("<none>"); 324 else 325 fSrcMenuField->MenuItem()->SetLabel(((PartitionMenuItem *)fSrcMenu->ItemAt(0))->MenuLabel()); 326 } 327 328 PartitionMenuItem *item2 = (PartitionMenuItem *)fDestMenu->FindMarked(); 329 if (item2) { 330 fDestMenuField->MenuItem()->SetLabel(item2->MenuLabel()); 331 } else { 332 if (fDestMenu->CountItems() == 0) 333 fDestMenuField->MenuItem()->SetLabel("<none>"); 334 else 335 fDestMenuField->MenuItem()->SetLabel(((PartitionMenuItem *)fDestMenu->ItemAt(0))->MenuLabel()); 336 } 337 char message[255]; 338 sprintf(message, "Press the Begin button to install from '%s' onto '%s'", 339 item1 ? item1->Name() : "null", item2 ? item2->Name() : "null"); 340 SetStatusMessage(message); 341 } 342 343 344 void 345 InstallerWindow::PublishPackages() 346 { 347 fPackagesView->Clean(); 348 PartitionMenuItem *item = (PartitionMenuItem *)fSrcMenu->FindMarked(); 349 if (!item) 350 return; 351 352 #ifdef __HAIKU__ 353 BPath directory; 354 BDiskDeviceRoster roster; 355 BDiskDevice device; 356 BPartition *partition; 357 if (roster.GetPartitionWithID(item->ID(), &device, &partition) == B_OK) { 358 if (partition->GetMountPoint(&directory) != B_OK) 359 return; 360 } else if (roster.GetDeviceWithID(item->ID(), &device) == B_OK) { 361 if (device.GetMountPoint(&directory) != B_OK) 362 return; 363 } else 364 return; // shouldn't happen 365 #else 366 BPath directory = "/BeOS 5 PE Max Edition V3.1 beta"; 367 #endif 368 369 directory.Append(PACKAGES_DIRECTORY); 370 BDirectory dir(directory.Path()); 371 if (dir.InitCheck() != B_OK) 372 return; 373 374 BEntry packageEntry; 375 BList packages; 376 while (dir.GetNextEntry(&packageEntry) == B_OK) { 377 Package *package = Package::PackageFromEntry(packageEntry); 378 if (package) { 379 packages.AddItem(package); 380 } 381 } 382 packages.SortItems(ComparePackages); 383 384 fPackagesView->AddPackages(packages, new BMessage(PACKAGE_CHECKBOX)); 385 PostMessage(PACKAGE_CHECKBOX); 386 } 387 388 389 int 390 InstallerWindow::ComparePackages(const void *firstArg, const void *secondArg) 391 { 392 const Group *group1 = *static_cast<const Group * const *>(firstArg); 393 const Group *group2 = *static_cast<const Group * const *>(secondArg); 394 const Package *package1 = dynamic_cast<const Package *>(group1); 395 const Package *package2 = dynamic_cast<const Package *>(group2); 396 int sameGroup = strcmp(group1->GroupName(), group2->GroupName()); 397 if (sameGroup != 0) 398 return sameGroup; 399 if (!package2) 400 return -1; 401 if (!package1) 402 return 1; 403 return strcmp(package1->Name(), package2->Name()); 404 } 405 406 407 void 408 InstallerWindow::SetStatusMessage(const char *text) 409 { 410 fStatusView->SetText(text); 411 } 412 413