xref: /haiku/src/kits/interface/AboutWindow.cpp (revision ae3724532e7e498d0ac591023d58447afedb2240)
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