xref: /haiku/src/kits/interface/AboutWindow.cpp (revision 37fedaf8494b34aad811abcc49e79aa32943f880)
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 	fInfoView = new BTextView("info", B_WILL_DRAW);
174 	fInfoView->SetExplicitMinSize(BSize(210.0, 160.0));
175 	fInfoView->MakeEditable(false);
176 	fInfoView->SetWordWrap(true);
177 	fInfoView->SetInsets(5.0, 5.0, 5.0, 5.0);
178 	fInfoView->SetViewColor(ui_color(B_DOCUMENT_BACKGROUND_COLOR));
179 	fInfoView->SetHighColor(ui_color(B_DOCUMENT_TEXT_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