xref: /haiku/src/kits/interface/AboutWindow.cpp (revision 44d19f4d32b8f7e9c01f00294c87ca5cc2e057f7)
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 
60 			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 
76 			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 			const char*		_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 
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() + 32.0f;
112 
113 	SetExplicitMinSize(BSize(width, B_SIZE_UNSET));
114 	SetExplicitPreferredSize(BSize(width, B_SIZE_UNLIMITED));
115 }
116 
117 
118 StripeView::~StripeView()
119 {
120 }
121 
122 
123 void
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
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() + 32.0f;
154 
155 	SetExplicitMinSize(BSize(width, B_SIZE_UNSET));
156 	SetExplicitPreferredSize(BSize(width, B_SIZE_UNLIMITED));
157 };
158 
159 
160 //	#pragma mark - AboutView
161 
162 
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 
176 	fVersionView = new BStringView("version",
177 		_GetVersionFromSignature(signature));
178 
179 	rgb_color documentColor = ui_color(B_DOCUMENT_TEXT_COLOR);
180 	fInfoView = new BTextView("info", NULL, &documentColor, B_WILL_DRAW);
181 	fInfoView->SetExplicitMinSize(BSize(210.0, 160.0));
182 	fInfoView->MakeEditable(false);
183 	fInfoView->SetWordWrap(true);
184 	fInfoView->SetInsets(5.0, 5.0, 5.0, 5.0);
185 	fInfoView->SetStylable(true);
186 
187 	BScrollView* infoViewScroller = new BScrollView(
188 		"infoViewScroller", fInfoView, B_WILL_DRAW | B_FRAME_EVENTS,
189 		false, true, B_PLAIN_BORDER);
190 
191 	fStripeView = new StripeView(_GetIconFromSignature(signature));
192 
193 	const char* ok = B_TRANSLATE_MARK("OK");
194 	BButton* closeButton = new BButton("ok",
195 		gSystemCatalog.GetString(ok, "AboutWindow"),
196 		new BMessage(B_QUIT_REQUESTED));
197 
198 	GroupLayout()->SetSpacing(0);
199 	BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0)
200 		.Add(fStripeView)
201 		.AddGroup(B_VERTICAL, B_USE_SMALL_SPACING)
202 			.SetInsets(0, B_USE_DEFAULT_SPACING,
203 				B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING)
204 			.Add(fNameView)
205 			.Add(fVersionView)
206 			.Add(infoViewScroller)
207 			.AddGroup(B_HORIZONTAL, 0)
208 				.AddGlue()
209 				.Add(closeButton)
210 				.End()
211 			.End()
212 		.AddGlue()
213 		.View()->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
214 
215 }
216 
217 
218 AboutView::~AboutView()
219 {
220 }
221 
222 
223 void
224 AboutView::AllAttached()
225 {
226 	fNameView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
227 	fInfoView->SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
228 	fVersionView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
229 }
230 
231 
232 //	#pragma mark - AboutView private methods
233 
234 
235 const char*
236 AboutView::_GetVersionFromSignature(const char* signature)
237 {
238 	if (signature == NULL)
239 		return NULL;
240 
241 	entry_ref ref;
242 	if (be_roster->FindApp(signature, &ref) != B_OK)
243 		return NULL;
244 
245 	BFile file(&ref, B_READ_ONLY);
246 	BAppFileInfo appMime(&file);
247 	if (appMime.InitCheck() != B_OK)
248 		return NULL;
249 
250 	version_info versionInfo;
251 	if (appMime.GetVersionInfo(&versionInfo, B_APP_VERSION_KIND) == B_OK) {
252 		if (versionInfo.major == 0 && versionInfo.middle == 0
253 			&& versionInfo.minor == 0) {
254 			return NULL;
255 		}
256 
257 		const char* version = B_TRANSLATE_MARK("Version");
258 		version = gSystemCatalog.GetString(version, "AboutWindow");
259 		BString appVersion(version);
260 		appVersion << " " << versionInfo.major << "." << versionInfo.middle;
261 		if (versionInfo.minor > 0)
262 			appVersion << "." << versionInfo.minor;
263 
264 		// Add the version variety
265 		const char* variety = NULL;
266 		switch (versionInfo.variety) {
267 			case B_DEVELOPMENT_VERSION:
268 				variety = B_TRANSLATE_MARK("development");
269 				break;
270 			case B_ALPHA_VERSION:
271 				variety = B_TRANSLATE_MARK("alpha");
272 				break;
273 			case B_BETA_VERSION:
274 				variety = B_TRANSLATE_MARK("beta");
275 				break;
276 			case B_GAMMA_VERSION:
277 				variety = B_TRANSLATE_MARK("gamma");
278 				break;
279 			case B_GOLDEN_MASTER_VERSION:
280 				variety = B_TRANSLATE_MARK("gold master");
281 				break;
282 		}
283 
284 		if (variety != NULL) {
285 			variety = gSystemCatalog.GetString(variety, "AboutWindow");
286 			appVersion << "-" << variety;
287 		}
288 
289 		return appVersion.String();
290 	}
291 
292 	return NULL;
293 }
294 
295 
296 BBitmap*
297 AboutView::_GetIconFromSignature(const char* signature)
298 {
299 	if (signature == NULL)
300 		return NULL;
301 
302 	entry_ref ref;
303 	if (be_roster->FindApp(signature, &ref) != B_OK)
304 		return NULL;
305 
306 	BFile file(&ref, B_READ_ONLY);
307 	BAppFileInfo appMime(&file);
308 	if (appMime.InitCheck() != B_OK)
309 		return NULL;
310 
311 	BBitmap* icon = new BBitmap(BRect(0.0, 0.0, 127.0, 127.0), B_RGBA32);
312 	if (appMime.GetIcon(icon, (icon_size)128) == B_OK)
313 		return icon;
314 
315 	delete icon;
316 	return NULL;
317 }
318 
319 
320 //	#pragma mark - AboutView public methods
321 
322 
323 BBitmap*
324 AboutView::Icon()
325 {
326 	if (fStripeView == NULL)
327 		return NULL;
328 
329 	return fStripeView->Icon();
330 }
331 
332 
333 status_t
334 AboutView::SetIcon(BBitmap* icon)
335 {
336 	if (fStripeView == NULL)
337 		return B_NO_INIT;
338 
339 	fStripeView->SetIcon(icon);
340 
341 	return B_OK;
342 }
343 
344 
345 const char*
346 AboutView::Name()
347 {
348 	return fNameView->Text();
349 }
350 
351 
352 status_t
353 AboutView::SetName(const char* name)
354 {
355 	fNameView->SetText(name);
356 
357 	return B_OK;
358 }
359 
360 
361 const char*
362 AboutView::Version()
363 {
364 	return fVersionView->Text();
365 }
366 
367 
368 status_t
369 AboutView::SetVersion(const char* version)
370 {
371 	fVersionView->SetText(version);
372 
373 	return B_OK;
374 }
375 
376 } // namespace BPrivate
377 
378 
379 //	#pragma mark - BAboutWindow
380 
381 
382 BAboutWindow::BAboutWindow(const char* appName, const char* signature)
383 	:
384 	BWindow(BRect(0.0, 0.0, 200.0, 200.0), appName, B_MODAL_WINDOW,
385 		B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE | B_NOT_RESIZABLE
386 			| B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE)
387 {
388 	SetLayout(new BGroupLayout(B_VERTICAL));
389 
390 	const char* about = B_TRANSLATE_MARK("About %app%");
391 	about = gSystemCatalog.GetString(about, "AboutWindow");
392 
393 	BString title(about);
394 	title.ReplaceFirst("%app%", appName);
395 	SetTitle(title.String());
396 
397 	fAboutView = new BPrivate::AboutView(appName, signature);
398 	AddChild(fAboutView);
399 
400 	MoveTo(AboutPosition(Frame().Width(), Frame().Height()));
401 }
402 
403 
404 BAboutWindow::~BAboutWindow()
405 {
406 	fAboutView->RemoveSelf();
407 	delete fAboutView;
408 	fAboutView = NULL;
409 }
410 
411 
412 //	#pragma mark - BAboutWindow virtual methods
413 
414 
415 void
416 BAboutWindow::Show()
417 {
418 	if (IsHidden()) {
419 		// move to current workspace
420 		SetWorkspaces(B_CURRENT_WORKSPACE);
421 	}
422 
423 	BWindow::Show();
424 }
425 
426 
427 //	#pragma mark - BAboutWindow public methods
428 
429 
430 BPoint
431 BAboutWindow::AboutPosition(float width, float height)
432 {
433 	BPoint result(100, 100);
434 
435 	BWindow* window =
436 		dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
437 
438 	BScreen screen(window);
439 	BRect screenFrame(0, 0, 640, 480);
440 	if (screen.IsValid())
441 		screenFrame = screen.Frame();
442 
443 	// Horizontally, we're smack in the middle
444 	result.x = screenFrame.left + (screenFrame.Width() / 2.0) - (width / 2.0);
445 
446 	// This is probably sooo wrong, but it looks right on 1024 x 768
447 	result.y = screenFrame.top + (screenFrame.Height() / 4.0)
448 		- ceil(height / 3.0);
449 
450 	return result;
451 }
452 
453 
454 void
455 BAboutWindow::AddDescription(const char* description)
456 {
457 	if (description == NULL)
458 		return;
459 
460 	AddText(description);
461 }
462 
463 
464 void
465 BAboutWindow::AddCopyright(int32 firstCopyrightYear,
466 	const char* copyrightHolder, const char** extraCopyrights)
467 {
468 	BString copyright(B_UTF8_COPYRIGHT " %years% %holder%");
469 
470 	// Get current year
471 	time_t tp;
472 	time(&tp);
473 	char currentYear[5];
474 	strftime(currentYear, 5, "%Y", localtime(&tp));
475 	BString copyrightYears;
476 	copyrightYears << firstCopyrightYear;
477 	if (copyrightYears != currentYear)
478 		copyrightYears << "-" << currentYear;
479 
480 	BString text("");
481 	if (fAboutView->InfoView()->TextLength() > 0)
482 		text << "\n\n";
483 
484 	text << copyright;
485 
486 	// Fill out the copyright year placeholder
487 	text.ReplaceAll("%years%", copyrightYears.String());
488 
489 	// Fill in the copyright holder placeholder
490 	text.ReplaceAll("%holder%", copyrightHolder);
491 
492 	// Add extra copyright strings
493 	if (extraCopyrights != NULL) {
494 		// Add optional extra copyright information
495 		for (int32 i = 0; extraCopyrights[i]; i++)
496 			text << "\n" << B_UTF8_COPYRIGHT << " " << extraCopyrights[i];
497 	}
498 
499 	const char* allRightsReserved = B_TRANSLATE_MARK("All Rights Reserved.");
500 	allRightsReserved = gSystemCatalog.GetString(allRightsReserved,
501 		"AboutWindow");
502 	text << "\n    " << allRightsReserved;
503 
504 	fAboutView->InfoView()->Insert(text.String());
505 }
506 
507 
508 void
509 BAboutWindow::AddAuthors(const char** authors)
510 {
511 	if (authors == NULL)
512 		return;
513 
514 	const char* writtenBy = B_TRANSLATE_MARK("Written by:");
515 	writtenBy = gSystemCatalog.GetString(writtenBy, "AboutWindow");
516 
517 	AddText(writtenBy, authors);
518 }
519 
520 
521 void
522 BAboutWindow::AddSpecialThanks(const char** thanks)
523 {
524 	if (thanks == NULL)
525 		return;
526 
527 	const char* specialThanks = B_TRANSLATE_MARK("Special Thanks:");
528 	specialThanks = gSystemCatalog.GetString(specialThanks, "AboutWindow");
529 
530 	AddText(specialThanks, thanks);
531 }
532 
533 
534 void
535 BAboutWindow::AddVersionHistory(const char** history)
536 {
537 	if (history == NULL)
538 		return;
539 
540 	const char* versionHistory = B_TRANSLATE_MARK("Version history:");
541 	versionHistory = gSystemCatalog.GetString(versionHistory, "AboutWindow");
542 
543 	AddText(versionHistory, history);
544 }
545 
546 
547 void
548 BAboutWindow::AddExtraInfo(const char* extraInfo)
549 {
550 	if (extraInfo == NULL)
551 		return;
552 
553 	const char* appExtraInfo = B_TRANSLATE_MARK(extraInfo);
554 	appExtraInfo = gSystemCatalog.GetString(extraInfo, "AboutWindow");
555 
556 	BString extra("");
557 	if (fAboutView->InfoView()->TextLength() > 0)
558 		extra << "\n\n";
559 
560 	extra << appExtraInfo;
561 
562 	fAboutView->InfoView()->Insert(extra.String());
563 }
564 
565 
566 void
567 BAboutWindow::AddText(const char* header, const char** contents)
568 {
569 	BTextView* infoView = fAboutView->InfoView();
570 	int32 textLength = infoView->TextLength();
571 	BString text("");
572 
573 	if (textLength > 0) {
574 		text << "\n\n";
575 		textLength += 2;
576 	}
577 
578 	const char* indent = "";
579 	if (header != NULL) {
580 		indent = "    ";
581 		text << header;
582 	}
583 
584 	if (contents != NULL) {
585 		text << "\n";
586 		for (int32 i = 0; contents[i]; i++)
587 			text << indent << contents[i] << "\n";
588 	}
589 
590 	infoView->Insert(text.String());
591 
592 	if (contents != NULL && header != NULL) {
593 		infoView->SetFontAndColor(textLength, textLength + strlen(header),
594 			be_bold_font);
595 	}
596 }
597 
598 
599 BBitmap*
600 BAboutWindow::Icon()
601 {
602 	return fAboutView->Icon();
603 }
604 
605 
606 void
607 BAboutWindow::SetIcon(BBitmap* icon)
608 {
609 	fAboutView->SetIcon(icon);
610 }
611 
612 
613 const char*
614 BAboutWindow::Name()
615 {
616 	return fAboutView->Name();
617 }
618 
619 
620 void
621 BAboutWindow::SetName(const char* name)
622 {
623 	fAboutView->SetName(name);
624 }
625 
626 
627 const char*
628 BAboutWindow::Version()
629 {
630 	return fAboutView->Version();
631 }
632 
633 
634 void
635 BAboutWindow::SetVersion(const char* version)
636 {
637 	fAboutView->SetVersion(version);
638 }
639 
640 
641 // FBC padding
642 
643 void BAboutWindow::_ReservedAboutWindow20() {}
644 void BAboutWindow::_ReservedAboutWindow19() {}
645 void BAboutWindow::_ReservedAboutWindow18() {}
646 void BAboutWindow::_ReservedAboutWindow17() {}
647 void BAboutWindow::_ReservedAboutWindow16() {}
648 void BAboutWindow::_ReservedAboutWindow15() {}
649 void BAboutWindow::_ReservedAboutWindow14() {}
650 void BAboutWindow::_ReservedAboutWindow13() {}
651 void BAboutWindow::_ReservedAboutWindow12() {}
652 void BAboutWindow::_ReservedAboutWindow11() {}
653 void BAboutWindow::_ReservedAboutWindow10() {}
654 void BAboutWindow::_ReservedAboutWindow9() {}
655 void BAboutWindow::_ReservedAboutWindow8() {}
656 void BAboutWindow::_ReservedAboutWindow7() {}
657 void BAboutWindow::_ReservedAboutWindow6() {}
658 void BAboutWindow::_ReservedAboutWindow5() {}
659 void BAboutWindow::_ReservedAboutWindow4() {}
660 void BAboutWindow::_ReservedAboutWindow3() {}
661 void BAboutWindow::_ReservedAboutWindow2() {}
662 void BAboutWindow::_ReservedAboutWindow1() {}
663