1 /* 2 * Copyright 2007-2012 Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ryan Leavengood <leavengood@gmail.com> 7 * John Scipione <jscipione@gmail.com> 8 */ 9 10 11 #include <AboutWindow.h> 12 13 #include <stdarg.h> 14 #include <time.h> 15 16 #include <Alert.h> 17 #include <AppFileInfo.h> 18 #include <Bitmap.h> 19 #include <Button.h> 20 #include <File.h> 21 #include <Font.h> 22 #include <GroupLayoutBuilder.h> 23 #include <GroupView.h> 24 #include <InterfaceDefs.h> 25 #include <LayoutBuilder.h> 26 #include <Message.h> 27 #include <MessageFilter.h> 28 #include <Point.h> 29 #include <Roster.h> 30 #include <Screen.h> 31 #include <ScrollView.h> 32 #include <Size.h> 33 #include <String.h> 34 #include <StringView.h> 35 #include <SystemCatalog.h> 36 #include <TextView.h> 37 #include <View.h> 38 #include <Window.h> 39 40 41 static const float kStripeWidth = 30.0; 42 43 using BPrivate::gSystemCatalog; 44 45 46 #undef B_TRANSLATION_CONTEXT 47 #define B_TRANSLATION_CONTEXT "AboutWindow" 48 49 50 class StripeView : public BView { 51 public: 52 StripeView(BBitmap* icon); 53 virtual ~StripeView(); 54 55 virtual void Draw(BRect updateRect); 56 57 BBitmap* Icon() const { return fIcon; }; 58 void SetIcon(BBitmap* icon); 59 60 private: 61 BBitmap* fIcon; 62 }; 63 64 65 class AboutView : public BGroupView { 66 public: 67 AboutView(const char* name, 68 const char* signature); 69 virtual ~AboutView(); 70 71 BTextView* InfoView() const { return fInfoView; }; 72 73 BBitmap* Icon(); 74 status_t SetIcon(BBitmap* icon); 75 76 const char* Name(); 77 status_t SetName(const char* name); 78 79 const char* Version(); 80 status_t SetVersion(const char* version); 81 82 private: 83 const char* _GetVersionFromSignature(const char* signature); 84 BBitmap* _GetIconFromSignature(const char* signature); 85 86 private: 87 BStringView* fNameView; 88 BStringView* fVersionView; 89 BTextView* fInfoView; 90 StripeView* fStripeView; 91 }; 92 93 94 // #pragma mark - StripeView 95 96 97 StripeView::StripeView(BBitmap* icon) 98 : 99 BView("StripeView", B_WILL_DRAW), 100 fIcon(icon) 101 { 102 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 103 104 float width = 0.0f; 105 if (icon != NULL) 106 width += icon->Bounds().Width() + 32.0f; 107 108 SetExplicitMinSize(BSize(width, B_SIZE_UNSET)); 109 SetExplicitPreferredSize(BSize(width, B_SIZE_UNLIMITED)); 110 } 111 112 113 StripeView::~StripeView() 114 { 115 } 116 117 118 void 119 StripeView::Draw(BRect updateRect) 120 { 121 if (fIcon == NULL) 122 return; 123 124 SetHighColor(ViewColor()); 125 FillRect(updateRect); 126 127 BRect stripeRect = Bounds(); 128 stripeRect.right = kStripeWidth; 129 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 130 FillRect(stripeRect); 131 132 SetDrawingMode(B_OP_ALPHA); 133 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 134 DrawBitmapAsync(fIcon, BPoint(15.0f, 10.0f)); 135 } 136 137 138 void 139 StripeView::SetIcon(BBitmap* icon) 140 { 141 if (fIcon != NULL) 142 delete fIcon; 143 144 fIcon = icon; 145 146 float width = 0.0f; 147 if (icon != NULL) 148 width += icon->Bounds().Width() + 32.0f; 149 150 SetExplicitMinSize(BSize(width, B_SIZE_UNSET)); 151 SetExplicitPreferredSize(BSize(width, B_SIZE_UNLIMITED)); 152 }; 153 154 155 // #pragma mark - AboutView 156 157 158 AboutView::AboutView(const char* appName, const char* signature) 159 : 160 BGroupView("AboutView", B_VERTICAL) 161 { 162 fNameView = new BStringView("name", appName); 163 BFont font; 164 fNameView->GetFont(&font); 165 font.SetFace(B_BOLD_FACE); 166 font.SetSize(font.Size() * 2.0); 167 fNameView->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE 168 | B_FONT_FLAGS); 169 170 fVersionView = new BStringView("version", 171 _GetVersionFromSignature(signature)); 172 173 rgb_color documentColor = ui_color(B_DOCUMENT_TEXT_COLOR); 174 fInfoView = new BTextView("info", NULL, &documentColor, B_WILL_DRAW); 175 fInfoView->SetExplicitMinSize(BSize(210.0, 160.0)); 176 fInfoView->MakeEditable(false); 177 fInfoView->SetWordWrap(true); 178 fInfoView->SetInsets(5.0, 5.0, 5.0, 5.0); 179 fInfoView->SetViewColor(ui_color(B_DOCUMENT_BACKGROUND_COLOR)); 180 fInfoView->SetStylable(true); 181 182 BScrollView* infoViewScroller = new BScrollView( 183 "infoViewScroller", fInfoView, B_WILL_DRAW | B_FRAME_EVENTS, 184 false, true, B_PLAIN_BORDER); 185 186 fStripeView = new StripeView(_GetIconFromSignature(signature)); 187 188 const char* ok = B_TRANSLATE_MARK("OK"); 189 BButton* closeButton = new BButton("ok", 190 gSystemCatalog.GetString(ok, "AboutWindow"), 191 new BMessage(B_QUIT_REQUESTED)); 192 193 GroupLayout()->SetSpacing(0); 194 BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0) 195 .Add(fStripeView) 196 .AddGroup(B_VERTICAL, B_USE_SMALL_SPACING) 197 .SetInsets(0, B_USE_DEFAULT_SPACING, 198 B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) 199 .Add(fNameView) 200 .Add(fVersionView) 201 .Add(infoViewScroller) 202 .AddGroup(B_HORIZONTAL, 0) 203 .AddGlue() 204 .Add(closeButton) 205 .End() 206 .End() 207 .AddGlue() 208 .End(); 209 } 210 211 212 AboutView::~AboutView() 213 { 214 } 215 216 217 // #pragma mark - AboutView private methods 218 219 220 const char* 221 AboutView::_GetVersionFromSignature(const char* signature) 222 { 223 if (signature == NULL) 224 return NULL; 225 226 entry_ref ref; 227 if (be_roster->FindApp(signature, &ref) != B_OK) 228 return NULL; 229 230 BFile file(&ref, B_READ_ONLY); 231 BAppFileInfo appMime(&file); 232 if (appMime.InitCheck() != B_OK) 233 return NULL; 234 235 version_info versionInfo; 236 if (appMime.GetVersionInfo(&versionInfo, B_APP_VERSION_KIND) == B_OK) { 237 if (versionInfo.major == 0 && versionInfo.middle == 0 238 && versionInfo.minor == 0) { 239 return NULL; 240 } 241 242 const char* version = B_TRANSLATE_MARK("Version"); 243 version = gSystemCatalog.GetString(version, "AboutWindow"); 244 BString appVersion(version); 245 appVersion << " " << versionInfo.major << "." << versionInfo.middle; 246 if (versionInfo.minor > 0) 247 appVersion << "." << versionInfo.minor; 248 249 // Add the version variety 250 const char* variety = NULL; 251 switch (versionInfo.variety) { 252 case B_DEVELOPMENT_VERSION: 253 variety = B_TRANSLATE_MARK("development"); 254 break; 255 case B_ALPHA_VERSION: 256 variety = B_TRANSLATE_MARK("alpha"); 257 break; 258 case B_BETA_VERSION: 259 variety = B_TRANSLATE_MARK("beta"); 260 break; 261 case B_GAMMA_VERSION: 262 variety = B_TRANSLATE_MARK("gamma"); 263 break; 264 case B_GOLDEN_MASTER_VERSION: 265 variety = B_TRANSLATE_MARK("gold master"); 266 break; 267 } 268 269 if (variety != NULL) { 270 variety = gSystemCatalog.GetString(variety, "AboutWindow"); 271 appVersion << "-" << variety; 272 } 273 274 return appVersion.String(); 275 } 276 277 return NULL; 278 } 279 280 281 BBitmap* 282 AboutView::_GetIconFromSignature(const char* signature) 283 { 284 if (signature == NULL) 285 return NULL; 286 287 entry_ref ref; 288 if (be_roster->FindApp(signature, &ref) != B_OK) 289 return NULL; 290 291 BFile file(&ref, B_READ_ONLY); 292 BAppFileInfo appMime(&file); 293 if (appMime.InitCheck() != B_OK) 294 return NULL; 295 296 BBitmap* icon = new BBitmap(BRect(0.0, 0.0, 127.0, 127.0), B_RGBA32); 297 if (appMime.GetIcon(icon, (icon_size)128) == B_OK) 298 return icon; 299 300 delete icon; 301 return NULL; 302 } 303 304 305 // #pragma mark - AboutView public methods 306 307 308 BBitmap* 309 AboutView::Icon() 310 { 311 if (fStripeView == NULL) 312 return NULL; 313 314 return fStripeView->Icon(); 315 } 316 317 318 status_t 319 AboutView::SetIcon(BBitmap* icon) 320 { 321 if (fStripeView == NULL) 322 return B_NO_INIT; 323 324 fStripeView->SetIcon(icon); 325 326 return B_OK; 327 } 328 329 330 const char* 331 AboutView::Name() 332 { 333 return fNameView->Text(); 334 } 335 336 337 status_t 338 AboutView::SetName(const char* name) 339 { 340 fNameView->SetText(name); 341 342 return B_OK; 343 } 344 345 346 const char* 347 AboutView::Version() 348 { 349 return fVersionView->Text(); 350 } 351 352 353 status_t 354 AboutView::SetVersion(const char* version) 355 { 356 fVersionView->SetText(version); 357 358 return B_OK; 359 } 360 361 362 // #pragma mark - BAboutWindow 363 364 365 BAboutWindow::BAboutWindow(const char* appName, const char* signature) 366 : 367 BWindow(BRect(0.0, 0.0, 200.0, 200.0), appName, B_MODAL_WINDOW, 368 B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE | B_NOT_RESIZABLE 369 | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE) 370 { 371 SetLayout(new BGroupLayout(B_VERTICAL)); 372 373 const char* about = B_TRANSLATE_MARK("About %app%"); 374 about = gSystemCatalog.GetString(about, "AboutWindow"); 375 376 BString title(about); 377 title.ReplaceFirst("%app%", appName); 378 SetTitle(title.String()); 379 380 fAboutView = new AboutView(appName, signature); 381 AddChild(fAboutView); 382 383 MoveTo(AboutPosition(Frame().Width(), Frame().Height())); 384 } 385 386 387 BAboutWindow::~BAboutWindow() 388 { 389 fAboutView->RemoveSelf(); 390 delete fAboutView; 391 fAboutView = NULL; 392 } 393 394 395 // #pragma mark - BAboutWindow virtual methods 396 397 398 void 399 BAboutWindow::Show() 400 { 401 if (IsHidden()) { 402 // move to current workspace 403 SetWorkspaces(B_CURRENT_WORKSPACE); 404 } 405 406 BWindow::Show(); 407 } 408 409 410 // #pragma mark - BAboutWindow public methods 411 412 413 BPoint 414 BAboutWindow::AboutPosition(float width, float height) 415 { 416 BPoint result(100, 100); 417 418 BWindow* window = 419 dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL))); 420 421 BScreen screen(window); 422 BRect screenFrame(0, 0, 640, 480); 423 if (screen.IsValid()) 424 screenFrame = screen.Frame(); 425 426 // Horizontally, we're smack in the middle 427 result.x = screenFrame.left + (screenFrame.Width() / 2.0) - (width / 2.0); 428 429 // This is probably sooo wrong, but it looks right on 1024 x 768 430 result.y = screenFrame.top + (screenFrame.Height() / 4.0) 431 - ceil(height / 3.0); 432 433 return result; 434 } 435 436 437 void 438 BAboutWindow::AddDescription(const char* description) 439 { 440 if (description == NULL) 441 return; 442 443 AddText(description); 444 } 445 446 447 void 448 BAboutWindow::AddCopyright(int32 firstCopyrightYear, 449 const char* copyrightHolder, const char** extraCopyrights) 450 { 451 BString copyright(B_UTF8_COPYRIGHT " %years% %holder%"); 452 453 // Get current year 454 time_t tp; 455 time(&tp); 456 char currentYear[5]; 457 strftime(currentYear, 5, "%Y", localtime(&tp)); 458 BString copyrightYears; 459 copyrightYears << firstCopyrightYear; 460 if (copyrightYears != currentYear) 461 copyrightYears << "-" << currentYear; 462 463 BString text(""); 464 if (fAboutView->InfoView()->TextLength() > 0) 465 text << "\n\n"; 466 467 text << copyright; 468 469 // Fill out the copyright year placeholder 470 text.ReplaceAll("%years%", copyrightYears.String()); 471 472 // Fill in the copyright holder placeholder 473 text.ReplaceAll("%holder%", copyrightHolder); 474 475 // Add extra copyright strings 476 if (extraCopyrights != NULL) { 477 // Add optional extra copyright information 478 for (int32 i = 0; extraCopyrights[i]; i++) 479 text << "\n" << B_UTF8_COPYRIGHT << " " << extraCopyrights[i]; 480 } 481 482 const char* allRightsReserved = B_TRANSLATE_MARK("All Rights Reserved."); 483 allRightsReserved = gSystemCatalog.GetString(allRightsReserved, 484 "AboutWindow"); 485 text << "\n " << allRightsReserved; 486 487 fAboutView->InfoView()->Insert(text.String()); 488 } 489 490 491 void 492 BAboutWindow::AddAuthors(const char** authors) 493 { 494 if (authors == NULL) 495 return; 496 497 const char* writtenBy = B_TRANSLATE_MARK("Written by:"); 498 writtenBy = gSystemCatalog.GetString(writtenBy, "AboutWindow"); 499 500 AddText(writtenBy, authors); 501 } 502 503 504 void 505 BAboutWindow::AddSpecialThanks(const char** thanks) 506 { 507 if (thanks == NULL) 508 return; 509 510 const char* specialThanks = B_TRANSLATE_MARK("Special Thanks:"); 511 specialThanks = gSystemCatalog.GetString(specialThanks, "AboutWindow"); 512 513 AddText(specialThanks, thanks); 514 } 515 516 517 void 518 BAboutWindow::AddVersionHistory(const char** history) 519 { 520 if (history == NULL) 521 return; 522 523 const char* versionHistory = B_TRANSLATE_MARK("Version history:"); 524 versionHistory = gSystemCatalog.GetString(versionHistory, "AboutWindow"); 525 526 AddText(versionHistory, history); 527 } 528 529 530 void 531 BAboutWindow::AddExtraInfo(const char* extraInfo) 532 { 533 if (extraInfo == NULL) 534 return; 535 536 const char* appExtraInfo = B_TRANSLATE_MARK(extraInfo); 537 appExtraInfo = gSystemCatalog.GetString(extraInfo, "AboutWindow"); 538 539 BString extra(""); 540 if (fAboutView->InfoView()->TextLength() > 0) 541 extra << "\n\n"; 542 543 extra << appExtraInfo; 544 545 fAboutView->InfoView()->Insert(extra.String()); 546 } 547 548 549 void 550 BAboutWindow::AddText(const char* header, const char** contents) 551 { 552 BTextView* infoView = fAboutView->InfoView(); 553 int32 textLength = infoView->TextLength(); 554 BString text(""); 555 556 if (textLength > 0) { 557 text << "\n\n"; 558 textLength += 2; 559 } 560 561 const char* indent = ""; 562 if (header != NULL) { 563 indent = " "; 564 text << header; 565 } 566 567 if (contents != NULL) { 568 text << "\n"; 569 for (int32 i = 0; contents[i]; i++) 570 text << indent << contents[i] << "\n"; 571 } 572 573 infoView->Insert(text.String()); 574 575 if (contents != NULL && header != NULL) { 576 infoView->SetFontAndColor(textLength, textLength + strlen(header), 577 be_bold_font); 578 } 579 } 580 581 582 BBitmap* 583 BAboutWindow::Icon() 584 { 585 return fAboutView->Icon(); 586 } 587 588 589 void 590 BAboutWindow::SetIcon(BBitmap* icon) 591 { 592 fAboutView->SetIcon(icon); 593 } 594 595 596 const char* 597 BAboutWindow::Name() 598 { 599 return fAboutView->Name(); 600 } 601 602 603 void 604 BAboutWindow::SetName(const char* name) 605 { 606 fAboutView->SetName(name); 607 } 608 609 610 const char* 611 BAboutWindow::Version() 612 { 613 return fAboutView->Version(); 614 } 615 616 617 void 618 BAboutWindow::SetVersion(const char* version) 619 { 620 fAboutView->SetVersion(version); 621 } 622 623 624 // FBC padding 625 626 void BAboutWindow::_ReservedAboutWindow20() {} 627 void BAboutWindow::_ReservedAboutWindow19() {} 628 void BAboutWindow::_ReservedAboutWindow18() {} 629 void BAboutWindow::_ReservedAboutWindow17() {} 630 void BAboutWindow::_ReservedAboutWindow16() {} 631 void BAboutWindow::_ReservedAboutWindow15() {} 632 void BAboutWindow::_ReservedAboutWindow14() {} 633 void BAboutWindow::_ReservedAboutWindow13() {} 634 void BAboutWindow::_ReservedAboutWindow12() {} 635 void BAboutWindow::_ReservedAboutWindow11() {} 636 void BAboutWindow::_ReservedAboutWindow10() {} 637 void BAboutWindow::_ReservedAboutWindow9() {} 638 void BAboutWindow::_ReservedAboutWindow8() {} 639 void BAboutWindow::_ReservedAboutWindow7() {} 640 void BAboutWindow::_ReservedAboutWindow6() {} 641 void BAboutWindow::_ReservedAboutWindow5() {} 642 void BAboutWindow::_ReservedAboutWindow4() {} 643 void BAboutWindow::_ReservedAboutWindow3() {} 644 void BAboutWindow::_ReservedAboutWindow2() {} 645 void BAboutWindow::_ReservedAboutWindow1() {} 646