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