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 fCopyEngine(this) 69 { 70 BRect bounds = Bounds(); 71 bounds.bottom += 1; 72 bounds.right += 1; 73 fBackBox = new BBox(bounds, NULL, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, B_FANCY_BORDER); 74 AddChild(fBackBox); 75 76 BRect logoRect = fBackBox->Bounds(); 77 logoRect.left += 1; 78 logoRect.top = 12; 79 logoRect.right -= 226; 80 logoRect.bottom = logoRect.top + 46 + B_H_SCROLL_BAR_HEIGHT; 81 LogoView *logoView = new LogoView(logoRect); 82 fBackBox->AddChild(logoView); 83 84 BRect statusRect(bounds.right-222, logoRect.top+2, bounds.right-14, logoRect.bottom - B_H_SCROLL_BAR_HEIGHT+4); 85 BRect textRect(statusRect); 86 textRect.OffsetTo(B_ORIGIN); 87 textRect.InsetBy(2,2); 88 fStatusView = new BTextView(statusRect, "statusView", textRect, 89 be_plain_font, NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); 90 fStatusView->MakeEditable(false); 91 fStatusView->MakeSelectable(false); 92 93 BScrollView *scroll = new BScrollView("statusScroll", fStatusView, B_FOLLOW_LEFT|B_FOLLOW_TOP, B_WILL_DRAW|B_FRAME_EVENTS); 94 fBackBox->AddChild(scroll); 95 96 fBeginButton = new BButton(BRect(bounds.right-90, bounds.bottom-35, bounds.right-11, bounds.bottom-11), 97 "begin_button", "Begin", new BMessage(BEGIN_MESSAGE), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 98 fBeginButton->MakeDefault(true); 99 fBackBox->AddChild(fBeginButton); 100 101 fSetupButton = new BButton(BRect(bounds.left+11, bounds.bottom-35, bounds.left+121, bounds.bottom-22), 102 "setup_button", "Setup partitions" B_UTF8_ELLIPSIS, new BMessage(SETUP_MESSAGE), B_FOLLOW_LEFT|B_FOLLOW_BOTTOM); 103 fBackBox->AddChild(fSetupButton); 104 fSetupButton->Hide(); 105 106 fPackagesView = new PackagesView(BRect(bounds.left+12, bounds.top+4, bounds.right-15-B_V_SCROLL_BAR_WIDTH, bounds.bottom-61), "packages_view"); 107 fPackagesScrollView = new BScrollView("packagesScroll", fPackagesView, B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW, 108 false, true); 109 fBackBox->AddChild(fPackagesScrollView); 110 fPackagesScrollView->Hide(); 111 112 fDrawButton = new DrawButton(BRect(bounds.left+12, bounds.bottom-33, bounds.left+120, bounds.bottom-20), 113 "options_button", "Fewer options", "More options", new BMessage(SHOW_BOTTOM_MESSAGE)); 114 fBackBox->AddChild(fDrawButton); 115 116 fDestMenu = new BPopUpMenu("scanning" B_UTF8_ELLIPSIS, true, false); 117 fSrcMenu = new BPopUpMenu("scanning" B_UTF8_ELLIPSIS, true, false); 118 119 BRect fieldRect(bounds.left+50, bounds.top+70, bounds.right-13, bounds.top+90); 120 fSrcMenuField = new BMenuField(fieldRect, "srcMenuField", 121 "Install from: ", fSrcMenu); 122 fSrcMenuField->SetDivider(bounds.right-274); 123 fSrcMenuField->SetAlignment(B_ALIGN_RIGHT); 124 fBackBox->AddChild(fSrcMenuField); 125 126 fieldRect.OffsetBy(0,23); 127 fDestMenuField = new BMenuField(fieldRect, "destMenuField", 128 "Onto: ", fDestMenu); 129 fDestMenuField->SetDivider(bounds.right-274); 130 fDestMenuField->SetAlignment(B_ALIGN_RIGHT); 131 fBackBox->AddChild(fDestMenuField); 132 133 BRect sizeRect = fBackBox->Bounds(); 134 sizeRect.top = 105; 135 sizeRect.bottom = sizeRect.top + 15; 136 sizeRect.right -= 12; 137 sizeRect.left = sizeRect.right - 170; 138 fSizeView = new BStringView(sizeRect, "size_view", "Disk space required: 0.0 KB", B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 139 fSizeView->SetAlignment(B_ALIGN_RIGHT); 140 fBackBox->AddChild(fSizeView); 141 fSizeView->Hide(); 142 143 // finish creating window 144 Show(); 145 146 fDriveSetupLaunched = be_roster->IsRunning(DRIVESETUP_SIG); 147 be_roster->StartWatching(this); 148 149 PostMessage(START_SCAN); 150 } 151 152 InstallerWindow::~InstallerWindow() 153 { 154 be_roster->StopWatching(this); 155 } 156 157 158 void 159 InstallerWindow::MessageReceived(BMessage *msg) 160 { 161 switch (msg->what) { 162 case START_SCAN: 163 StartScan(); 164 break; 165 case BEGIN_MESSAGE: 166 fCopyEngine.Start(); 167 break; 168 case SHOW_BOTTOM_MESSAGE: 169 ShowBottom(); 170 break; 171 case SRC_PARTITION: 172 PublishPackages(); 173 AdjustMenus(); 174 break; 175 case TARGET_PARTITION: 176 AdjustMenus(); 177 break; 178 case SETUP_MESSAGE: 179 LaunchDriveSetup(); 180 break; 181 case PACKAGE_CHECKBOX: { 182 char buffer[15]; 183 fPackagesView->GetTotalSizeAsString(buffer); 184 char string[255]; 185 sprintf(string, "Disk space required: %s", buffer); 186 fSizeView->SetText(string); 187 break; 188 } 189 case B_SOME_APP_LAUNCHED: 190 case B_SOME_APP_QUIT: 191 { 192 const char *signature; 193 if (msg->FindString("be:signature", &signature)==B_OK 194 && strcasecmp(signature, DRIVESETUP_SIG)==0) { 195 DisableInterface(msg->what == B_SOME_APP_LAUNCHED); 196 } 197 break; 198 } 199 default: 200 BWindow::MessageReceived(msg); 201 break; 202 } 203 } 204 205 bool 206 InstallerWindow::QuitRequested() 207 { 208 if (fDriveSetupLaunched) { 209 (new BAlert("driveSetup", 210 "Please close the DriveSetup window before closing the\nInstaller window.", "OK"))->Go(); 211 return false; 212 } 213 be_app->PostMessage(B_QUIT_REQUESTED); 214 return true; 215 } 216 217 218 void 219 InstallerWindow::ShowBottom() 220 { 221 if (fDrawButton->Value()) { 222 ResizeTo(INSTALLER_RIGHT, 306); 223 if (fSetupButton->IsHidden()) 224 fSetupButton->Show(); 225 if (fPackagesScrollView->IsHidden()) 226 fPackagesScrollView->Show(); 227 if (fSizeView->IsHidden()) 228 fSizeView->Show(); 229 } else { 230 if (!fSetupButton->IsHidden()) 231 fSetupButton->Hide(); 232 if (!fPackagesScrollView->IsHidden()) 233 fPackagesScrollView->Hide(); 234 if (!fSizeView->IsHidden()) 235 fSizeView->Hide(); 236 ResizeTo(INSTALLER_RIGHT, 160); 237 } 238 } 239 240 241 void 242 InstallerWindow::LaunchDriveSetup() 243 { 244 if (be_roster->Launch(DRIVESETUP_SIG)!=B_OK) 245 fprintf(stderr, "There was an error while launching DriveSetup\n"); 246 } 247 248 249 void 250 InstallerWindow::DisableInterface(bool disable) 251 { 252 if (!disable) { 253 StartScan(); 254 } 255 fDriveSetupLaunched = disable; 256 fBeginButton->SetEnabled(!disable); 257 fSetupButton->SetEnabled(!disable); 258 fSrcMenuField->SetEnabled(!disable); 259 fDestMenuField->SetEnabled(!disable); 260 if (disable) 261 SetStatusMessage("Running DriveSetup" B_UTF8_ELLIPSIS "\nClose DriveSetup to continue with the\ninstallation."); 262 } 263 264 265 void 266 InstallerWindow::StartScan() 267 { 268 SetStatusMessage("Scanning for disks" B_UTF8_ELLIPSIS); 269 270 BMenuItem *item; 271 while ((item = fSrcMenu->RemoveItem((int32)0))) 272 delete item; 273 while ((item = fDestMenu->RemoveItem((int32)0))) 274 delete item; 275 276 fCopyEngine.ScanDisksPartitions(fSrcMenu, fDestMenu); 277 278 if (fSrcMenu->ItemAt(0)) { 279 PublishPackages(); 280 } 281 AdjustMenus(); 282 SetStatusMessage("Choose the disk you want to install onto from the pop-up menu. Then click \"Begin\"."); 283 } 284 285 286 void 287 InstallerWindow::AdjustMenus() 288 { 289 PartitionMenuItem *item1 = (PartitionMenuItem *)fSrcMenu->FindMarked(); 290 if (!item1) { 291 } else { 292 fSrcMenuField->MenuItem()->SetLabel(item1->MenuLabel()); 293 } 294 295 PartitionMenuItem *item2 = (PartitionMenuItem *)fDestMenu->FindMarked(); 296 if (!item2) { 297 } else { 298 fDestMenuField->MenuItem()->SetLabel(item2->MenuLabel()); 299 } 300 char message[255]; 301 sprintf(message, "Press the Begin button to install from '%s' onto '%s'", item1->Name(), item2->Name()); 302 SetStatusMessage(message); 303 } 304 305 306 void 307 InstallerWindow::PublishPackages() 308 { 309 fPackagesView->Clean(); 310 PartitionMenuItem *item = (PartitionMenuItem *)fSrcMenu->FindMarked(); 311 if (!item) 312 return; 313 314 BPath directory; 315 BDiskDeviceRoster roster; 316 BDiskDevice device; 317 BPartition *partition; 318 if (roster.GetPartitionWithID(item->ID(), &device, &partition) == B_OK) { 319 if (partition->GetMountPoint(&directory)!=B_OK) 320 return; 321 } else if (roster.GetDeviceWithID(item->ID(), &device) == B_OK) { 322 if (device.GetMountPoint(&directory)!=B_OK) 323 return; 324 } else 325 return; // shouldn't happen 326 327 directory.Append("_packages_"); 328 BDirectory dir(directory.Path()); 329 if (dir.InitCheck()!=B_OK) 330 return; 331 332 BEntry packageEntry; 333 BList packages; 334 while (dir.GetNextEntry(&packageEntry)==B_OK) { 335 Package *package = Package::PackageFromEntry(packageEntry); 336 if (package) { 337 packages.AddItem(package); 338 } 339 } 340 packages.SortItems(ComparePackages); 341 342 fPackagesView->AddPackages(packages, new BMessage(PACKAGE_CHECKBOX)); 343 PostMessage(PACKAGE_CHECKBOX); 344 } 345 346 347 int 348 InstallerWindow::ComparePackages(const void *firstArg, const void *secondArg) 349 { 350 const Group *group1 = *static_cast<const Group * const *>(firstArg); 351 const Group *group2 = *static_cast<const Group * const *>(secondArg); 352 const Package *package1 = dynamic_cast<const Package *>(group1); 353 const Package *package2 = dynamic_cast<const Package *>(group2); 354 int sameGroup = strcmp(group1->GroupName(), group2->GroupName()); 355 if (sameGroup != 0) 356 return sameGroup; 357 if (!package2) 358 return -1; 359 if (!package1) 360 return 1; 361 return strcmp(package1->Name(), package2->Name()); 362 } 363 364 365 void 366 InstallerWindow::SetStatusMessage(char *text) 367 { 368 BAutolock(this); 369 fStatusView->SetText(text); 370 } 371