xref: /haiku/src/apps/aboutsystem/AboutSystem.cpp (revision 97dfeb96704e5dbc5bec32ad7b21379d0125e031)
1 /*
2  * Copyright 2005-2014, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Augustin Cavalier <waddlesplash>
7  *		DarkWyrm <bpmagic@columbus.rr.com>
8  *		René Gollent
9  *		Wim van der Meer <WPJvanderMeer@gmail.com>
10  */
11 
12 
13 #include <ctype.h>
14 #include <stdio.h>
15 #include <time.h>
16 #include <unistd.h>
17 
18 #include <algorithm>
19 #include <map>
20 #include <string>
21 
22 #include <AppFileInfo.h>
23 #include <Application.h>
24 #include <Bitmap.h>
25 #include <DateTimeFormat.h>
26 #include <DurationFormat.h>
27 #include <File.h>
28 #include <FindDirectory.h>
29 #include <Font.h>
30 #include <fs_attr.h>
31 #include <LayoutBuilder.h>
32 #include <MessageFormat.h>
33 #include <MessageRunner.h>
34 #include <Messenger.h>
35 #include <ObjectList.h>
36 #include <OS.h>
37 #include <Path.h>
38 #include <PathFinder.h>
39 #include <Resources.h>
40 #include <Screen.h>
41 #include <ScrollView.h>
42 #include <String.h>
43 #include <StringList.h>
44 #include <StringView.h>
45 #include <TranslationUtils.h>
46 #include <TranslatorFormats.h>
47 #include <View.h>
48 #include <Volume.h>
49 #include <VolumeRoster.h>
50 #include <Window.h>
51 
52 #include <AppMisc.h>
53 #include <AutoDeleter.h>
54 #include <cpu_type.h>
55 #include <parsedate.h>
56 #include <system_revision.h>
57 
58 #include <Catalog.h>
59 #include <Language.h>
60 #include <Locale.h>
61 #include <LocaleRoster.h>
62 
63 #include "HyperTextActions.h"
64 #include "HyperTextView.h"
65 #include "Utilities.h"
66 
67 #include "Credits.h"
68 
69 #ifndef LINE_MAX
70 #define LINE_MAX 2048
71 #endif
72 
73 #define SCROLL_CREDITS_VIEW 'mviv'
74 
75 #undef B_TRANSLATION_CONTEXT
76 #define B_TRANSLATION_CONTEXT "AboutWindow"
77 
78 
79 
80 static const char* UptimeToString(char string[], size_t size);
81 static const char* MemSizeToString(char string[], size_t size,
82 	system_info* info);
83 static const char* MemUsageToString(char string[], size_t size,
84 	system_info* info);
85 
86 
87 static const rgb_color kDarkGrey = { 100, 100, 100, 255 };
88 static const rgb_color kHaikuGreen = { 42, 131, 36, 255 };
89 static const rgb_color kHaikuOrange = { 255, 69, 0, 255 };
90 static const rgb_color kHaikuYellow = { 255, 176, 0, 255 };
91 static const rgb_color kLinkBlue = { 80, 80, 200, 255 };
92 static const rgb_color kBeOSBlue = { 0, 0, 200, 255 };
93 static const rgb_color kBeOSRed = { 200, 0, 0, 255 };
94 
95 static const char* kBSDTwoClause = B_TRANSLATE_MARK("BSD (2-clause)");
96 static const char* kBSDThreeClause = B_TRANSLATE_MARK("BSD (3-clause)");
97 static const char* kBSDFourClause = B_TRANSLATE_MARK("BSD (4-clause)");
98 static const char* kGPLv2 = B_TRANSLATE_MARK("GNU GPL v2");
99 static const char* kGPLv3 = B_TRANSLATE_MARK("GNU GPL v3");
100 static const char* kLGPLv2 = B_TRANSLATE_MARK("GNU LGPL v2");
101 static const char* kLGPLv21 = B_TRANSLATE_MARK("GNU LGPL v2.1");
102 static const char* kPublicDomain = B_TRANSLATE_MARK("Public Domain");
103 #ifdef __INTEL__
104 static const char* kIntel2xxxFirmware = B_TRANSLATE_MARK("Intel (2xxx firmware)");
105 static const char* kIntelFirmware = B_TRANSLATE_MARK("Intel (firmware)");
106 static const char* kMarvellFirmware = B_TRANSLATE_MARK("Marvell (firmware)");
107 static const char* kRalinkFirmware = B_TRANSLATE_MARK("Ralink (firmware)");
108 #endif
109 
110 
111 static int
112 TranslationComparator(const void* left, const void* right)
113 {
114 	const Translation* leftTranslation = *(const Translation**)left;
115 	const Translation* rightTranslation = *(const Translation**)right;
116 
117 	BLanguage* language;
118 	BString leftName;
119 	if (BLocaleRoster::Default()->GetLanguage(leftTranslation->languageCode,
120 			&language) == B_OK) {
121 		language->GetName(leftName);
122 		delete language;
123 	} else
124 		leftName = leftTranslation->languageCode;
125 
126 	BString rightName;
127 	if (BLocaleRoster::Default()->GetLanguage(rightTranslation->languageCode,
128 			&language) == B_OK) {
129 		language->GetName(rightName);
130 		delete language;
131 	} else
132 		rightName = rightTranslation->languageCode;
133 
134 	BCollator collator;
135 	BLocale::Default()->GetCollator(&collator);
136 	return collator.Compare(leftName.String(), rightName.String());
137 }
138 
139 
140 class AboutApp : public BApplication {
141 public:
142 							AboutApp();
143 			void			MessageReceived(BMessage* message);
144 };
145 
146 
147 class AboutView;
148 
149 class AboutWindow : public BWindow {
150 public:
151 							AboutWindow();
152 
153 	virtual	bool			QuitRequested();
154 
155 			AboutView*		fAboutView;
156 };
157 
158 
159 class LogoView : public BView {
160 public:
161 							LogoView();
162 	virtual					~LogoView();
163 
164 	virtual	BSize			MinSize();
165 	virtual	BSize			MaxSize();
166 
167 	virtual void			Draw(BRect updateRect);
168 
169 private:
170 			BBitmap*		fLogo;
171 };
172 
173 
174 class CropView : public BView {
175 public:
176 							CropView(BView* target, int32 left, int32 top,
177 								int32 right, int32 bottom);
178 	virtual					~CropView();
179 
180 	virtual	BSize			MinSize();
181 	virtual	BSize			MaxSize();
182 
183 	virtual void			DoLayout();
184 
185 private:
186 			BView*			fTarget;
187 			int32			fCropLeft;
188 			int32			fCropTop;
189 			int32			fCropRight;
190 			int32			fCropBottom;
191 };
192 
193 
194 class AboutView : public BView {
195 public:
196 							AboutView();
197 							~AboutView();
198 
199 	virtual void			AttachedToWindow();
200 	virtual	void			AllAttached();
201 	virtual void			Pulse();
202 
203 	virtual void			MessageReceived(BMessage* msg);
204 	virtual void			MouseDown(BPoint point);
205 
206 			void			AddCopyrightEntry(const char* name,
207 								const char* text,
208 								const StringVector& licenses,
209 								const StringVector& sources,
210 								const char* url);
211 			void			AddCopyrightEntry(const char* name,
212 								const char* text, const char* url = NULL);
213 			void			PickRandomHaiku();
214 
215 
216 			void			_AdjustTextColors();
217 private:
218 	typedef std::map<std::string, PackageCredit*> PackageCreditMap;
219 
220 private:
221 			BView*			_CreateLabel(const char* name, const char* label);
222 			BView*			_CreateCreditsView();
223 			status_t		_GetLicensePath(const char* license,
224 								BPath& path);
225 			void			_AddCopyrightsFromAttribute();
226 			void			_AddPackageCredit(const PackageCredit& package);
227 			void			_AddPackageCreditEntries();
228 
229 			BStringView*	fMemView;
230 			BStringView*	fUptimeView;
231 			BView*			fInfoView;
232 			HyperTextView*	fCreditsView;
233 
234 			BObjectList<BView> fTextViews;
235 			BObjectList<BView> fSubTextViews;
236 
237 			BBitmap*		fLogo;
238 
239 			bigtime_t		fLastActionTime;
240 			BMessageRunner*	fScrollRunner;
241 			PackageCreditMap fPackageCredits;
242 };
243 
244 
245 //	#pragma mark -
246 
247 
248 AboutApp::AboutApp()
249 	: BApplication("application/x-vnd.Haiku-About")
250 {
251 	B_TRANSLATE_MARK_SYSTEM_NAME_VOID("AboutSystem");
252 
253 	AboutWindow *window = new(std::nothrow) AboutWindow();
254 	if (window)
255 		window->Show();
256 }
257 
258 
259 void
260 AboutApp::MessageReceived(BMessage* message)
261 {
262 	switch (message->what) {
263 		case B_SILENT_RELAUNCH:
264 			WindowAt(0)->Activate();
265 			break;
266 	}
267 
268 	BApplication::MessageReceived(message);
269 }
270 
271 
272 //	#pragma mark -
273 
274 
275 AboutWindow::AboutWindow()
276 	: BWindow(BRect(0, 0, 500, 300), B_TRANSLATE("About this system"),
277 		B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE)
278 {
279 	SetLayout(new BGroupLayout(B_VERTICAL));
280 	fAboutView = new AboutView();
281 	AddChild(fAboutView);
282 
283 	// Make sure we take the minimal window size into account when centering
284 	BSize size = GetLayout()->MinSize();
285 	ResizeTo(max_c(size.width, Bounds().Width()),
286 		max_c(size.height, Bounds().Height()));
287 
288 	CenterOnScreen();
289 }
290 
291 
292 bool
293 AboutWindow::QuitRequested()
294 {
295 	be_app->PostMessage(B_QUIT_REQUESTED);
296 	return true;
297 }
298 
299 
300 //	#pragma mark - LogoView
301 
302 
303 LogoView::LogoView()
304 	: BView("logo", B_WILL_DRAW)
305 {
306 	fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "logo.png");
307 	SetViewColor(255, 255, 255);
308 }
309 
310 
311 LogoView::~LogoView()
312 {
313 	delete fLogo;
314 }
315 
316 
317 BSize
318 LogoView::MinSize()
319 {
320 	if (fLogo == NULL)
321 		return BSize(0, 0);
322 
323 	return BSize(fLogo->Bounds().Width(), fLogo->Bounds().Height());
324 }
325 
326 
327 BSize
328 LogoView::MaxSize()
329 {
330 	if (fLogo == NULL)
331 		return BSize(0, 0);
332 
333 	return BSize(B_SIZE_UNLIMITED, fLogo->Bounds().Height());
334 }
335 
336 
337 void
338 LogoView::Draw(BRect updateRect)
339 {
340 	if (fLogo != NULL) {
341 		DrawBitmap(fLogo,
342 			BPoint((Bounds().Width() - fLogo->Bounds().Width()) / 2, 0));
343 	}
344 }
345 
346 
347 //	#pragma mark - CropView
348 
349 
350 CropView::CropView(BView* target, int32 left, int32 top, int32 right,
351 		int32 bottom)
352 	: BView("crop view", 0),
353 	fTarget(target),
354 	fCropLeft(left),
355 	fCropTop(top),
356 	fCropRight(right),
357 	fCropBottom(bottom)
358 {
359 	AddChild(target);
360 }
361 
362 
363 CropView::~CropView()
364 {
365 }
366 
367 
368 BSize
369 CropView::MinSize()
370 {
371 	if (fTarget == NULL)
372 		return BSize();
373 
374 	BSize size = fTarget->MinSize();
375 	if (size.width != B_SIZE_UNSET)
376 		size.width -= fCropLeft + fCropRight;
377 	if (size.height != B_SIZE_UNSET)
378 		size.height -= fCropTop + fCropBottom;
379 
380 	return size;
381 }
382 
383 
384 BSize
385 CropView::MaxSize()
386 {
387 	if (fTarget == NULL)
388 		return BSize();
389 
390 	BSize size = fTarget->MaxSize();
391 	if (size.width != B_SIZE_UNSET)
392 		size.width -= fCropLeft + fCropRight;
393 	if (size.height != B_SIZE_UNSET)
394 		size.height -= fCropTop + fCropBottom;
395 
396 	return size;
397 }
398 
399 
400 void
401 CropView::DoLayout()
402 {
403 	BView::DoLayout();
404 
405 	if (fTarget == NULL)
406 		return;
407 
408 	fTarget->MoveTo(-fCropLeft, -fCropTop);
409 	fTarget->ResizeTo(Bounds().Width() + fCropLeft + fCropRight,
410 		Bounds().Height() + fCropTop + fCropBottom);
411 }
412 
413 
414 //	#pragma mark - AboutView
415 
416 #undef B_TRANSLATION_CONTEXT
417 #define B_TRANSLATION_CONTEXT "AboutView"
418 
419 AboutView::AboutView()
420 	: BView("aboutview", B_WILL_DRAW | B_PULSE_NEEDED),
421 	fLastActionTime(system_time()),
422 	fScrollRunner(NULL)
423 {
424 	// Begin Construction of System Information controls
425 	system_info systemInfo;
426 	get_system_info(&systemInfo);
427 
428 	// Create all the various labels for system infomation
429 
430 	// OS Version
431 
432 	char string[1024];
433 	strlcpy(string, B_TRANSLATE("Unknown"), sizeof(string));
434 
435 	// the version is stored in the BEOS:APP_VERSION attribute of libbe.so
436 	BPath path;
437 	if (find_directory(B_BEOS_LIB_DIRECTORY, &path) == B_OK) {
438 		path.Append("libbe.so");
439 
440 		BAppFileInfo appFileInfo;
441 		version_info versionInfo;
442 		BFile file;
443 		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
444 			&& appFileInfo.SetTo(&file) == B_OK
445 			&& appFileInfo.GetVersionInfo(&versionInfo,
446 				B_APP_VERSION_KIND) == B_OK
447 			&& versionInfo.short_info[0] != '\0')
448 			strlcpy(string, versionInfo.short_info, sizeof(string));
449 	}
450 
451 	// Add system revision
452 	const char* haikuRevision = __get_haiku_revision();
453 	if (haikuRevision != NULL) {
454 		strlcat(string, " (", sizeof(string));
455 		strlcat(string, B_TRANSLATE("Revision"), sizeof(string));
456 		strlcat(string, " ", sizeof(string));
457 		strlcat(string, haikuRevision, sizeof(string));
458 		strlcat(string, ")", sizeof(string));
459 	}
460 
461 	BStringView* versionView = new BStringView("ostext", string);
462 	fSubTextViews.AddItem(versionView);
463 	versionView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
464 		B_ALIGN_VERTICAL_UNSET));
465 
466 	BStringView* abiView = new BStringView("abitext", B_HAIKU_ABI_NAME);
467 	fSubTextViews.AddItem(abiView);
468 	abiView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
469 		B_ALIGN_VERTICAL_UNSET));
470 
471 	// CPU count, type and clock speed
472 	static BMessageFormat format(B_TRANSLATE_COMMENT(
473 		"{0, plural, one{Processor:} other{# Processors:}}",
474 		"\"Processor:\" or \"2 Processors:\""));
475 
476 	BString processorLabel;
477 	format.Format(processorLabel, systemInfo.cpu_count);
478 
479 	uint32 topologyNodeCount = 0;
480 	cpu_topology_node_info* topology = NULL;
481 	get_cpu_topology_info(NULL, &topologyNodeCount);
482 	if (topologyNodeCount != 0)
483 		topology = new cpu_topology_node_info[topologyNodeCount];
484 	get_cpu_topology_info(topology, &topologyNodeCount);
485 
486 	enum cpu_platform platform = B_CPU_UNKNOWN;
487 	enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN;
488 	uint32 cpuModel = 0;
489 	for (uint32 i = 0; i < topologyNodeCount; i++) {
490 		switch (topology[i].type) {
491 			case B_TOPOLOGY_ROOT:
492 				platform = topology[i].data.root.platform;
493 				break;
494 
495 			case B_TOPOLOGY_PACKAGE:
496 				cpuVendor = topology[i].data.package.vendor;
497 				break;
498 
499 			case B_TOPOLOGY_CORE:
500 				cpuModel = topology[i].data.core.model;
501 				break;
502 
503 			default:
504 				break;
505 		}
506 	}
507 
508 	delete[] topology;
509 
510 	BString cpuType;
511 	cpuType << get_cpu_vendor_string(cpuVendor)
512 		<< " " << get_cpu_model_string(platform, cpuVendor, cpuModel);
513 
514 	BStringView* cpuView = new BStringView("cputext", cpuType.String());
515 	fSubTextViews.AddItem(cpuView);
516 	cpuView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
517 		B_ALIGN_VERTICAL_UNSET));
518 
519 	int32 clockSpeed = get_rounded_cpu_speed();
520 	if (clockSpeed < 1000)
521 		snprintf(string, sizeof(string), B_TRANSLATE("%ld MHz"), clockSpeed);
522 	else
523 		snprintf(string, sizeof(string), B_TRANSLATE("%.2f GHz"),
524 			clockSpeed / 1000.0f);
525 
526 	BStringView* frequencyView = new BStringView("frequencytext", string);
527 	fSubTextViews.AddItem(frequencyView);
528 	frequencyView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
529 		B_ALIGN_VERTICAL_UNSET));
530 
531 	// RAM
532 	BStringView *memSizeView = new BStringView("ramsizetext",
533 		MemSizeToString(string, sizeof(string), &systemInfo));
534 	fSubTextViews.AddItem(memSizeView);
535 	memSizeView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
536 		B_ALIGN_VERTICAL_UNSET));
537 
538 	fMemView = new BStringView("ramtext",
539 		MemUsageToString(string, sizeof(string), &systemInfo));
540 	fSubTextViews.AddItem(fMemView);
541 	fMemView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
542 		B_ALIGN_VERTICAL_UNSET));
543 
544 	// Kernel build time/date
545 	BString kernelTimeDate;
546 	kernelTimeDate << systemInfo.kernel_build_date
547 		<< " " << systemInfo.kernel_build_time;
548 	BString buildTimeDate;
549 
550 	time_t buildTimeDateStamp = parsedate(kernelTimeDate, -1);
551 	if (buildTimeDateStamp > 0) {
552 		if (BDateTimeFormat().Format(buildTimeDate, buildTimeDateStamp,
553 			B_LONG_DATE_FORMAT, B_MEDIUM_TIME_FORMAT) != B_OK)
554 			buildTimeDate.SetTo(kernelTimeDate);
555 	} else
556 		buildTimeDate.SetTo(kernelTimeDate);
557 
558 	BStringView* kernelView = new BStringView("kerneltext", buildTimeDate);
559 	fSubTextViews.AddItem(kernelView);
560 	kernelView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
561 		B_ALIGN_VERTICAL_UNSET));
562 
563 	// Uptime
564 	fUptimeView = new BStringView("uptimetext", "...");
565 	fSubTextViews.AddItem(fUptimeView);
566 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
567 
568 	const float offset = 5;
569 
570 	SetLayout(new BGroupLayout(B_HORIZONTAL, 0));
571 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
572 
573 	BLayoutBuilder::Group<>((BGroupLayout*)GetLayout())
574 		.AddGroup(B_VERTICAL, 0)
575 			.Add(new LogoView())
576 			.AddGroup(B_VERTICAL, 0)
577 				.Add(_CreateLabel("oslabel", B_TRANSLATE("Version:")))
578 				.Add(versionView)
579 				.Add(abiView)
580 				.AddStrut(offset)
581 				.Add(_CreateLabel("cpulabel", processorLabel.String()))
582 				.Add(cpuView)
583 				.Add(frequencyView)
584 				.AddStrut(offset)
585 				.Add(_CreateLabel("memlabel", B_TRANSLATE("Memory:")))
586 				.Add(memSizeView)
587 				.Add(fMemView)
588 				.AddStrut(offset)
589 				.Add(_CreateLabel("kernellabel", B_TRANSLATE("Kernel:")))
590 				.Add(kernelView)
591 				.AddStrut(offset)
592 				.Add(_CreateLabel("uptimelabel",
593 					B_TRANSLATE("Time running:")))
594 				.Add(fUptimeView)
595 				.SetInsets(5, 5, 5, 5)
596 			.End()
597 			// TODO: investigate: adding this causes the time to be cut
598 			//.AddGlue()
599 		.End()
600 		.Add(_CreateCreditsView());
601 
602 	float min = fMemView->MinSize().width * 1.1f;
603 	fCreditsView->SetExplicitMinSize(BSize(min, min));
604 }
605 
606 
607 AboutView::~AboutView()
608 {
609 	for (PackageCreditMap::iterator it = fPackageCredits.begin();
610 		it != fPackageCredits.end(); it++) {
611 
612 		delete it->second;
613 	}
614 
615 	delete fScrollRunner;
616 }
617 
618 
619 void
620 AboutView::AttachedToWindow()
621 {
622 	BView::AttachedToWindow();
623 	Window()->SetPulseRate(500000);
624 	SetEventMask(B_POINTER_EVENTS);
625 	DoLayout();
626 }
627 
628 
629 void
630 AboutView::AllAttached()
631 {
632 	_AdjustTextColors();
633 }
634 
635 
636 void
637 AboutView::MouseDown(BPoint point)
638 {
639 	BRect r(92, 26, 105, 31);
640 	if (r.Contains(point))
641 		BMessenger(this).SendMessage('eegg');
642 
643 	if (Bounds().Contains(point)) {
644 		fLastActionTime = system_time();
645 		delete fScrollRunner;
646 		fScrollRunner = NULL;
647 	}
648 }
649 
650 
651 void
652 AboutView::Pulse()
653 {
654 	char string[255];
655 	system_info info;
656 	get_system_info(&info);
657 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
658 	fMemView->SetText(MemUsageToString(string, sizeof(string), &info));
659 
660 	if (fScrollRunner == NULL
661 		&& system_time() > fLastActionTime + 10000000) {
662 		BMessage message(SCROLL_CREDITS_VIEW);
663 		//fScrollRunner = new BMessageRunner(this, &message, 25000, -1);
664 	}
665 }
666 
667 
668 void
669 AboutView::MessageReceived(BMessage* msg)
670 {
671 	switch (msg->what) {
672 		case B_COLORS_UPDATED:
673 		{
674 			if (msg->HasColor(ui_color_name(B_PANEL_TEXT_COLOR)))
675 				_AdjustTextColors();
676 
677 			break;
678 		}
679 		case SCROLL_CREDITS_VIEW:
680 		{
681 			BScrollBar* scrollBar =
682 				fCreditsView->ScrollBar(B_VERTICAL);
683 			if (scrollBar == NULL)
684 				break;
685 			float max, min;
686 			scrollBar->GetRange(&min, &max);
687 			if (scrollBar->Value() < max)
688 				fCreditsView->ScrollBy(0, 1);
689 
690 			break;
691 		}
692 
693 		case 'eegg':
694 		{
695 			printf("Easter egg\n");
696 			PickRandomHaiku();
697 			break;
698 		}
699 
700 		default:
701 			BView::MessageReceived(msg);
702 			break;
703 	}
704 }
705 
706 
707 void
708 AboutView::AddCopyrightEntry(const char* name, const char* text,
709 	const char* url)
710 {
711 	AddCopyrightEntry(name, text, StringVector(), StringVector(), url);
712 }
713 
714 
715 void
716 AboutView::AddCopyrightEntry(const char* name, const char* text,
717 	const StringVector& licenses, const StringVector& sources,
718 	const char* url)
719 {
720 	BFont font(be_bold_font);
721 	//font.SetSize(be_bold_font->Size());
722 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
723 
724 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuYellow);
725 	fCreditsView->Insert(name);
726 	fCreditsView->Insert("\n");
727 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
728 	fCreditsView->Insert(text);
729 	fCreditsView->Insert("\n");
730 
731 	if (licenses.CountStrings() > 0) {
732 		if (licenses.CountStrings() > 1)
733 			fCreditsView->Insert(B_TRANSLATE("Licenses: "));
734 		else
735 			fCreditsView->Insert(B_TRANSLATE("License: "));
736 
737 		for (int32 i = 0; i < licenses.CountStrings(); i++) {
738 			const char* license = licenses.StringAt(i);
739 
740 			if (i > 0)
741 				fCreditsView->Insert(", ");
742 
743 			BString licenseName;
744 			BString licenseURL;
745 			parse_named_url(license, licenseName, licenseURL);
746 
747 			BPath licensePath;
748 			if (_GetLicensePath(licenseURL, licensePath) == B_OK) {
749 				fCreditsView->InsertHyperText(B_TRANSLATE_NOCOLLECT(licenseName),
750 					new OpenFileAction(licensePath.Path()));
751 			} else
752 				fCreditsView->Insert(licenseName);
753 		}
754 
755 		fCreditsView->Insert("\n");
756 	}
757 
758 	if (sources.CountStrings() > 0) {
759 		fCreditsView->Insert(B_TRANSLATE("Source Code: "));
760 
761 		for (int32 i = 0; i < sources.CountStrings(); i++) {
762 			const char* source = sources.StringAt(i);
763 
764 			if (i > 0)
765 				fCreditsView->Insert(", ");
766 
767 			BString urlName;
768 			BString urlAddress;
769 			parse_named_url(source, urlName, urlAddress);
770 
771 			fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
772 				&kLinkBlue);
773 			fCreditsView->InsertHyperText(urlName,
774 				new URLAction(urlAddress));
775 		}
776 
777 		fCreditsView->Insert("\n");
778 	}
779 
780 	if (url) {
781 		BString urlName;
782 		BString urlAddress;
783 		parse_named_url(url, urlName, urlAddress);
784 
785 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
786 			&kLinkBlue);
787 		fCreditsView->InsertHyperText(urlName,
788 			new URLAction(urlAddress));
789 		fCreditsView->Insert("\n");
790 	}
791 	fCreditsView->Insert("\n");
792 }
793 
794 
795 void
796 AboutView::PickRandomHaiku()
797 {
798 	BPath path;
799 	if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) != B_OK)
800 		path = "/system/data";
801 	path.Append("fortunes");
802 	path.Append("Haiku");
803 
804 	BFile fortunes(path.Path(), B_READ_ONLY);
805 	struct stat st;
806 	if (fortunes.InitCheck() < B_OK)
807 		return;
808 	if (fortunes.GetStat(&st) < B_OK)
809 		return;
810 
811 	char* buff = (char*)malloc((size_t)st.st_size + 1);
812 	if (!buff)
813 		return;
814 	buff[(size_t)st.st_size] = '\0';
815 	BList haikuList;
816 	if (fortunes.Read(buff, (size_t)st.st_size) == (ssize_t)st.st_size) {
817 		char* p = buff;
818 		while (p && *p) {
819 			char* e = strchr(p, '%');
820 			BString* s = new BString(p, e ? (e - p) : -1);
821 			haikuList.AddItem(s);
822 			p = e;
823 			if (p && (*p == '%'))
824 				p++;
825 			if (p && (*p == '\n'))
826 				p++;
827 		}
828 	}
829 	free(buff);
830 	if (haikuList.CountItems() < 1)
831 		return;
832 
833 	BString* s = (BString*)haikuList.ItemAt(rand() % haikuList.CountItems());
834 	BFont font(be_bold_font);
835 	font.SetSize(be_bold_font->Size());
836 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
837 	fCreditsView->SelectAll();
838 	fCreditsView->Delete();
839 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kDarkGrey);
840 	fCreditsView->Insert(s->String());
841 	fCreditsView->Insert("\n");
842 	while ((s = (BString*)haikuList.RemoveItem((int32)0))) {
843 		delete s;
844 	}
845 }
846 
847 
848 void
849 AboutView::_AdjustTextColors()
850 {
851 	rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
852 	rgb_color color = mix_color(ViewColor(), textColor, 192);
853 
854 	BView* view = NULL;
855 	for (int32 index = 0; index < fSubTextViews.CountItems(); ++index) {
856 		view = fSubTextViews.ItemAt(index);
857 		view->SetHighColor(color);
858 		view->Invalidate();
859 	}
860 
861 	// Labels
862 	for (int32 index = 0; index < fTextViews.CountItems(); ++index) {
863 		view = fTextViews.ItemAt(index);
864 		view->SetHighColor(textColor);
865 		view->Invalidate();
866 	}
867 }
868 
869 
870 BView*
871 AboutView::_CreateLabel(const char* name, const char* label)
872 {
873 	BStringView* labelView = new BStringView(name, label);
874 	labelView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
875 		B_ALIGN_VERTICAL_UNSET));
876 	labelView->SetFont(be_bold_font);
877 	fTextViews.AddItem(labelView);
878 	return labelView;
879 }
880 
881 
882 BView*
883 AboutView::_CreateCreditsView()
884 {
885 	// Begin construction of the credits view
886 	fCreditsView = new HyperTextView("credits");
887 	fCreditsView->SetFlags(fCreditsView->Flags() | B_FRAME_EVENTS);
888 	fCreditsView->SetStylable(true);
889 	fCreditsView->MakeEditable(false);
890 	fCreditsView->SetWordWrap(true);
891 	fCreditsView->SetInsets(5, 5, 5, 5);
892 	fCreditsView->SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
893 
894 	BScrollView* creditsScroller = new BScrollView("creditsScroller",
895 		fCreditsView, B_WILL_DRAW | B_FRAME_EVENTS, false, true,
896 		B_PLAIN_BORDER);
897 
898 	// Haiku copyright
899 	BFont font(be_bold_font);
900 	font.SetSize(font.Size() + 4);
901 
902 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
903 	fCreditsView->Insert("Haiku\n");
904 
905 	char string[1024];
906 	time_t time = ::time(NULL);
907 	struct tm* tm = localtime(&time);
908 	int32 year = tm->tm_year + 1900;
909 	if (year < 2008)
910 		year = 2008;
911 	snprintf(string, sizeof(string),
912 		COPYRIGHT_STRING "2001-%" B_PRId32 " The Haiku project. ", year);
913 
914 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
915 	fCreditsView->Insert(string);
916 
917 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
918 	fCreditsView->Insert(B_TRANSLATE("The copyright to the Haiku code is "
919 		"property of Haiku, Inc. or of the respective authors where expressly "
920 		"noted in the source. Haiku" B_UTF8_REGISTERED
921 		" and the HAIKU logo" B_UTF8_REGISTERED
922 		" are registered trademarks of Haiku, Inc."
923 		"\n\n"));
924 
925 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kLinkBlue);
926 	fCreditsView->InsertHyperText("https://www.haiku-os.org",
927 		new URLAction("https://www.haiku-os.org"));
928 	fCreditsView->Insert("\n\n");
929 
930 	font.SetSize(be_bold_font->Size());
931 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
932 
933 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
934 	fCreditsView->Insert(B_TRANSLATE("Current maintainers:\n"));
935 
936 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
937 	fCreditsView->Insert(kCurrentMaintainers);
938 
939 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
940 	fCreditsView->Insert(B_TRANSLATE("Past maintainers:\n"));
941 
942 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
943 	fCreditsView->Insert(kPastMaintainers);
944 
945 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
946 	fCreditsView->Insert(B_TRANSLATE("Website & marketing:\n"));
947 
948 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
949 	fCreditsView->Insert(kWebsiteTeam);
950 
951 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
952 	fCreditsView->Insert(B_TRANSLATE("Past website & marketing:\n"));
953 
954 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
955 	fCreditsView->Insert(kPastWebsiteTeam);
956 
957 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
958 	fCreditsView->Insert(B_TRANSLATE("Contributors:\n"));
959 
960 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
961 	fCreditsView->Insert(kContributors);
962 	fCreditsView->Insert(
963 		B_TRANSLATE("\n" B_UTF8_ELLIPSIS
964 			"and probably some more we forgot to mention (sorry!)"
965 			"\n\n"));
966 
967 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
968 	fCreditsView->Insert(B_TRANSLATE("Translations:\n"));
969 
970 	BLanguage* lang;
971 	BString langName;
972 
973 	BList sortedTranslations;
974 	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
975 		const Translation* translation = &kTranslations[i];
976 		sortedTranslations.AddItem((void*)translation);
977 	}
978 	sortedTranslations.SortItems(TranslationComparator);
979 
980 	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
981 		const Translation& translation
982 			= *(const Translation*)sortedTranslations.ItemAt(i);
983 
984 		langName.Truncate(0);
985 		if (BLocaleRoster::Default()->GetLanguage(translation.languageCode,
986 				&lang) == B_OK) {
987 			lang->GetName(langName);
988 			delete lang;
989 		} else {
990 			// We failed to get the localized readable name,
991 			// go with what we have.
992 			langName.Append(translation.languageCode);
993 		}
994 
995 		fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
996 		fCreditsView->Insert("\n");
997 		fCreditsView->Insert(langName);
998 		fCreditsView->Insert("\n");
999 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1000 		fCreditsView->Insert(translation.names);
1001 	}
1002 
1003 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
1004 	fCreditsView->Insert(B_TRANSLATE("\n\nSpecial thanks to:\n"));
1005 
1006 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1007 	BString beosCredits(B_TRANSLATE(
1008 		"Be Inc. and its developer team, for having created BeOS!\n\n"));
1009 	int32 beosOffset = beosCredits.FindFirst("BeOS");
1010 	fCreditsView->Insert(beosCredits.String(),
1011 		(beosOffset < 0) ? beosCredits.Length() : beosOffset);
1012 	if (beosOffset > -1) {
1013 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kBeOSBlue);
1014 		fCreditsView->Insert("B");
1015 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kBeOSRed);
1016 		fCreditsView->Insert("e");
1017 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1018 		beosCredits.Remove(0, beosOffset + 2);
1019 		fCreditsView->Insert(beosCredits.String(), beosCredits.Length());
1020 	}
1021 	fCreditsView->Insert(
1022 		B_TRANSLATE("Travis Geiselbrecht (and his NewOS kernel)\n"));
1023 	fCreditsView->Insert(
1024 		B_TRANSLATE("Michael Phipps (project founder)\n\n"));
1025 	fCreditsView->Insert(
1026 		B_TRANSLATE("The HaikuPorts team\n"));
1027 	fCreditsView->Insert(
1028 		B_TRANSLATE("The Haikuware team and their bounty program\n"));
1029 	fCreditsView->Insert(
1030 		B_TRANSLATE("The BeGeistert team\n"));
1031 	fCreditsView->Insert(
1032 		B_TRANSLATE("Google and their Google Summer of Code and Google Code In "
1033 			"programs\n"));
1034 	fCreditsView->Insert(
1035 		B_TRANSLATE("The University of Auckland and Christof Lutteroth\n\n"));
1036 	fCreditsView->Insert(
1037 		B_TRANSLATE(B_UTF8_ELLIPSIS "and the many people making donations!\n\n"));
1038 
1039 	// copyrights for various projects we use
1040 
1041 	BPath mitPath;
1042 	_GetLicensePath("MIT", mitPath);
1043 	BPath lgplPath;
1044 	_GetLicensePath("GNU LGPL v2.1", lgplPath);
1045 
1046 	font.SetSize(be_bold_font->Size() + 4);
1047 	font.SetFace(B_BOLD_FACE);
1048 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
1049 	fCreditsView->Insert(B_TRANSLATE("\nCopyrights\n\n"));
1050 
1051 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1052 	fCreditsView->Insert(B_TRANSLATE("[Click a license name to read the "
1053 		"respective license.]\n\n"));
1054 
1055 	// Haiku license
1056 	BString haikuLicense = B_TRANSLATE_COMMENT("The code that is unique to "
1057 		"Haiku, especially the kernel and all code that applications may link "
1058 		"against, is distributed under the terms of the <MIT license>. "
1059 		"Some system libraries contain third party code distributed under the "
1060 		"<LGPL license>. You can find the copyrights to third party code below."
1061 		"\n\n", "<MIT license> and <LGPL license> aren't variables and can be "
1062 		"translated. However, please, don't remove < and > as they're needed "
1063 		"as placeholders for proper hypertext functionality.");
1064 	int32 licensePart1 = haikuLicense.FindFirst("<");
1065 	int32 licensePart2 = haikuLicense.FindFirst(">");
1066 	int32 licensePart3 = haikuLicense.FindLast("<");
1067 	int32 licensePart4 = haikuLicense.FindLast(">");
1068 	BString part;
1069 	haikuLicense.CopyInto(part, 0, licensePart1);
1070 	fCreditsView->Insert(part);
1071 
1072 	part.Truncate(0);
1073 	haikuLicense.CopyInto(part, licensePart1 + 1, licensePart2 - 1
1074 		- licensePart1);
1075 	fCreditsView->InsertHyperText(part, new OpenFileAction(mitPath.Path()));
1076 
1077 	part.Truncate(0);
1078 	haikuLicense.CopyInto(part, licensePart2 + 1, licensePart3 - 1
1079 		- licensePart2);
1080 	fCreditsView->Insert(part);
1081 
1082 	part.Truncate(0);
1083 	haikuLicense.CopyInto(part, licensePart3 + 1, licensePart4 - 1
1084 		- licensePart3);
1085 	fCreditsView->InsertHyperText(part, new OpenFileAction(lgplPath.Path()));
1086 
1087 	part.Truncate(0);
1088 	haikuLicense.CopyInto(part, licensePart4 + 1, haikuLicense.Length() - 1
1089 		- licensePart4);
1090 	fCreditsView->Insert(part);
1091 
1092 	// GNU copyrights
1093 	AddCopyrightEntry("The GNU Project",
1094 		B_TRANSLATE("Contains software from the GNU Project, "
1095 		"released under the GPL and LGPL licenses:\n"
1096 		"GNU C Library, "
1097 		"GNU coretools, diffutils, findutils, "
1098 		"sharutils, gawk, bison, m4, make, "
1099 		"wget, ncurses, termcap, "
1100 		"Bourne Again Shell.\n"
1101 		COPYRIGHT_STRING "The Free Software Foundation."),
1102 		StringVector(kLGPLv21, kGPLv2, kGPLv3, NULL),
1103 		StringVector(),
1104 		"https://www.gnu.org");
1105 
1106 	// FreeBSD copyrights
1107 	AddCopyrightEntry("The FreeBSD Project",
1108 		B_TRANSLATE("Contains software from the FreeBSD Project, "
1109 		"released under the BSD license:\n"
1110 		"ftpd, ping, telnet, telnetd, traceroute\n"
1111 		COPYRIGHT_STRING "1994-2008 The FreeBSD Project. "
1112 		"All rights reserved."),
1113 		StringVector(kBSDTwoClause, kBSDThreeClause, kBSDFourClause,
1114 			NULL),
1115 		StringVector(),
1116 		"https://www.freebsd.org");
1117 
1118 	// NetBSD copyrights
1119 	AddCopyrightEntry("The NetBSD Project",
1120 		B_TRANSLATE("Contains software developed by the NetBSD "
1121 		"Foundation, Inc. and its contributors:\n"
1122 		"ftp, tput\n"
1123 		COPYRIGHT_STRING "1996-2008 The NetBSD Foundation, Inc. "
1124 		"All rights reserved."),
1125 		"https://www.netbsd.org");
1126 			// TODO: License!
1127 
1128 	// FFmpeg copyrights
1129 	_AddPackageCredit(PackageCredit("FFmpeg")
1130 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2000-2014 Fabrice "
1131 			"Bellard, et al."))
1132 		.SetLicenses(kLGPLv21, kLGPLv2, NULL)
1133 		.SetURL("https://www.ffmpeg.org"));
1134 
1135 	// AGG copyrights
1136 	_AddPackageCredit(PackageCredit("AntiGrain Geometry")
1137 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2006 Maxim "
1138 			"Shemanarev (McSeem)."))
1139 		.SetLicenses("Anti-Grain Geometry", kBSDThreeClause, "GPC", NULL)
1140 		.SetURL("http://www.antigrain.com"));
1141 
1142 	// PDFLib copyrights
1143 	_AddPackageCredit(PackageCredit("PDFLib")
1144 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1997-2006 PDFlib GmbH and "
1145 			"Thomas Merz. All rights reserved.\n"
1146 			"PDFlib and PDFlib logo are registered trademarks of PDFlib GmbH."))
1147 		.SetLicense("PDFlib Lite")
1148 		.SetURL("http://www.pdflib.com"));
1149 
1150 	// FreeType copyrights
1151 	_AddPackageCredit(PackageCredit("FreeType2")
1152 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1996-2002, 2006 "
1153 			"David Turner, Robert Wilhelm and Werner Lemberg."),
1154 			COPYRIGHT_STRING "2014 The FreeType Project. "
1155 			"All rights reserved.",
1156 			NULL)
1157 		.SetLicense("FreeType")
1158 		.SetURL("http://www.freetype.org"));
1159 
1160 	// Mesa3D (http://www.mesa3d.org) copyrights
1161 	_AddPackageCredit(PackageCredit("Mesa")
1162 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2006 Brian Paul. "
1163 			"Mesa3D Project. All rights reserved."))
1164 		.SetLicense("MIT")
1165 		.SetURL("http://www.mesa3d.org"));
1166 
1167 	// SGI's GLU implementation copyrights
1168 	_AddPackageCredit(PackageCredit("GLU")
1169 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1991-2000 "
1170 			"Silicon Graphics, Inc. All rights reserved."))
1171 		.SetLicense("SGI Free B")
1172 		.SetURL("http://www.sgi.com/products/software/opengl"));
1173 
1174 	// GLUT implementation copyrights
1175 	_AddPackageCredit(PackageCredit("GLUT")
1176 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1994-1997 Mark Kilgard. "
1177 			"All rights reserved."),
1178 			COPYRIGHT_STRING "1997 Be Inc.",
1179 			COPYRIGHT_STRING "1999 Jake Hamby.",
1180 			NULL)
1181 		.SetLicense("GLUT (Mark Kilgard)")
1182 		.SetURL("http://www.opengl.org/resources/libraries/glut"));
1183 
1184 	// OpenGroup & DEC (BRegion backend) copyright
1185 	_AddPackageCredit(PackageCredit("BRegion backend (XFree86)")
1186 		.SetCopyrights(COPYRIGHT_STRING "1987-1988, 1998 The Open Group.",
1187 			B_TRANSLATE(COPYRIGHT_STRING "1987-1988 Digital Equipment "
1188 			"Corporation, Maynard, Massachusetts.\n"
1189 			"All rights reserved."),
1190 			NULL)
1191 		.SetLicenses("OpenGroup", "DEC", NULL));
1192 			// TODO: URL
1193 
1194 	// VL-Gothic font
1195 	_AddPackageCredit(PackageCredit("VL-Gothic font")
1196 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1990-2003 Wada Laboratory,"
1197 			" the University of Tokyo."), COPYRIGHT_STRING
1198 			"2003-2004 Electronic Font Open Laboratory (/efont/).",
1199 			COPYRIGHT_STRING "2003-2012 M+ FONTS PROJECT.",
1200 			COPYRIGHT_STRING "2006-2012 Daisuke SUZUKI.",
1201 			COPYRIGHT_STRING "2006-2012 Project Vine.",
1202 			B_TRANSLATE("MIT license. All rights reserved."),
1203 			NULL)
1204 		.SetLicense(kBSDThreeClause)
1205 		.SetURL("http://vlgothic.dicey.org/"));
1206 
1207 	// expat copyrights
1208 	_AddPackageCredit(PackageCredit("expat")
1209 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1998-2000 Thai "
1210 			"Open Source Software Center Ltd and Clark Cooper."),
1211 			B_TRANSLATE(COPYRIGHT_STRING "2001-2003 Expat maintainers."),
1212 			NULL)
1213 		.SetLicense("Expat")
1214 		.SetURL("http://expat.sourceforge.net"));
1215 
1216 	// zlib copyrights
1217 	_AddPackageCredit(PackageCredit("zlib")
1218 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2004 Jean-loup "
1219 			"Gailly and Mark Adler."))
1220 		.SetLicense("Zlib")
1221 		.SetURL("http://www.zlib.net"));
1222 
1223 	// zip copyrights
1224 	_AddPackageCredit(PackageCredit("Info-ZIP")
1225 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1990-2002 Info-ZIP. "
1226 			"All rights reserved."))
1227 		.SetLicense("Info-ZIP")
1228 		.SetURL("http://www.info-zip.org"));
1229 
1230 	// bzip2 copyrights
1231 	_AddPackageCredit(PackageCredit("bzip2")
1232 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-2005 Julian R "
1233 			"Seward. All rights reserved."))
1234 		.SetLicense(kBSDFourClause)
1235 		.SetURL("http://bzip.org"));
1236 
1237 	// OpenEXR copyrights
1238 	_AddPackageCredit(PackageCredit("OpenEXR")
1239 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2005 Industrial "
1240 			"Light & Magic, a division of Lucas Digital Ltd. LLC."))
1241 		.SetLicense(kBSDThreeClause)
1242 		.SetURL("http://www.openexr.com"));
1243 
1244 	// Bullet copyrights
1245 	_AddPackageCredit(PackageCredit("Bullet")
1246 		.SetCopyright(COPYRIGHT_STRING "2003-2008 Erwin Coumans")
1247 		.SetLicense("Bullet")
1248 		.SetURL("http://www.bulletphysics.com"));
1249 
1250 	// Netcat copyrights
1251 	_AddPackageCredit(PackageCredit("Netcat")
1252 		.SetCopyright(COPYRIGHT_STRING "1996 Hobbit.")
1253 		.SetLicense(kPublicDomain)
1254 		.SetURL("http://nc110.sourceforge.net/"));
1255 
1256 	// acpica copyrights
1257 	_AddPackageCredit(PackageCredit("acpica")
1258 		.SetCopyright(COPYRIGHT_STRING "1999-2014 Intel Corp.")
1259 		.SetLicense("Intel (ACPICA)")
1260 		.SetURL("https://www.acpica.org"));
1261 
1262 	// libpng copyrights
1263 	_AddPackageCredit(PackageCredit("libpng")
1264 		.SetCopyright(COPYRIGHT_STRING "2004, 2006-2008 Glenn "
1265 			"Randers-Pehrson.")
1266 		.SetLicense("LibPNG")
1267 		.SetURL("http://www.libpng.org"));
1268 
1269 	// libjpeg copyrights
1270 	_AddPackageCredit(PackageCredit("libjpeg")
1271 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1994-2009, Thomas G. "
1272 			"Lane, Guido Vollbeding. This software is based in part on the "
1273 			"work of the Independent JPEG Group."))
1274 		.SetLicense("LibJPEG")
1275 		.SetURL("http://www.ijg.org"));
1276 
1277 	// libprint copyrights
1278 	_AddPackageCredit(PackageCredit("libprint")
1279 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2000 Y.Takagi. "
1280 			"All rights reserved.")));
1281 			// TODO: License!
1282 
1283 	// cortex copyrights
1284 	_AddPackageCredit(PackageCredit("Cortex")
1285 		.SetCopyright(COPYRIGHT_STRING "1999-2000 Eric Moon.")
1286 		.SetLicense(kBSDThreeClause)
1287 		.SetURL("http://cortex.sourceforge.net/documentation"));
1288 
1289 	// FluidSynth copyrights
1290 	_AddPackageCredit(PackageCredit("FluidSynth")
1291 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003 Peter Hanappe "
1292 			"and others."))
1293 		.SetLicense(kLGPLv2)
1294 		.SetURL("http://www.fluidsynth.org"));
1295 
1296 	// Xiph.org Foundation copyrights
1297 	_AddPackageCredit(PackageCredit("Xiph.org Foundation")
1298 		.SetCopyrights("libvorbis, libogg, libtheora, libspeex",
1299 			B_TRANSLATE(COPYRIGHT_STRING "1994-2008 Xiph.Org. "
1300 			"All rights reserved."), NULL)
1301 		.SetLicense(kBSDThreeClause)
1302 		.SetURL("http://www.xiph.org"));
1303 
1304 	// The Tcpdump Group
1305 	_AddPackageCredit(PackageCredit("The Tcpdump Group")
1306 		.SetCopyright("tcpdump, libpcap")
1307 		.SetLicense(kBSDThreeClause)
1308 		.SetURL("http://www.tcpdump.org"));
1309 
1310 	// Matroska
1311 	_AddPackageCredit(PackageCredit("libmatroska")
1312 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2003 Steve Lhomme. "
1313 			"All rights reserved."))
1314 		.SetLicense(kLGPLv21)
1315 		.SetURL("http://www.matroska.org"));
1316 
1317 	// BColorQuantizer (originally CQuantizer code)
1318 	_AddPackageCredit(PackageCredit("CQuantizer")
1319 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-1997 Jeff Prosise. "
1320 			"All rights reserved."))
1321 		.SetLicense("CQuantizer")
1322 		.SetURL("http://www.xdp.it"));
1323 
1324 	// MAPM (Mike's Arbitrary Precision Math Library) used by DeskCalc
1325 	_AddPackageCredit(PackageCredit("MAPM")
1326 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2007 Michael C. "
1327 			"Ring. All rights reserved."))
1328 		.SetLicense("MAPM")
1329 		.SetURL("http://tc.umn.edu/~ringx004"));
1330 
1331 	// MkDepend 1.7 copyright (Makefile dependency generator)
1332 	_AddPackageCredit(PackageCredit("MkDepend")
1333 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2001 Lars Düning. "
1334 			"All rights reserved."))
1335 		.SetLicense("MkDepend")
1336 		.SetURL("http://bearnip.com/lars/be"));
1337 
1338 	// libhttpd copyright (used as Poorman backend)
1339 	_AddPackageCredit(PackageCredit("libhttpd")
1340 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995, 1998-2001 "
1341 			"Jef Poskanzer. All rights reserved."))
1342 		.SetLicense("LibHTTPd")
1343 		.SetURL("http://www.acme.com/software/thttpd/"));
1344 
1345 #ifdef __INTEL__
1346 	// Udis86 copyrights
1347 	_AddPackageCredit(PackageCredit("Udis86")
1348 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2004 "
1349 			"Vivek Mohan. All rights reserved."))
1350 		.SetLicense(kBSDTwoClause)
1351 		.SetURL("http://udis86.sourceforge.net"));
1352 
1353 	// Intel PRO/Wireless 2100 Firmware
1354 	_AddPackageCredit(PackageCredit("Intel PRO/Wireless 2100 Firmware")
1355 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003-2006 "
1356 			"Intel Corporation. All rights reserved."))
1357 		.SetLicense(kIntel2xxxFirmware)
1358 		.SetURL("http://ipw2100.sourceforge.net/"));
1359 
1360 	// Intel PRO/Wireless 2200BG Firmware
1361 	_AddPackageCredit(PackageCredit("Intel PRO/Wireless 2200BG Firmware")
1362 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2004-2005 "
1363 			"Intel Corporation. All rights reserved."))
1364 		.SetLicense(kIntel2xxxFirmware)
1365 		.SetURL("http://ipw2200.sourceforge.net/"));
1366 
1367 	// Intel PRO/Wireless 3945ABG/BG Network Connection Adapter Firmware
1368 	_AddPackageCredit(
1369 		PackageCredit(
1370 			"Intel PRO/Wireless 3945ABG/BG Network Connection Adapter Firmware")
1371 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2007 "
1372 			"Intel Corporation. All rights reserved."))
1373 		.SetLicense(kIntelFirmware)
1374 		.SetURL("http://www.intellinuxwireless.org/"));
1375 
1376 	// Intel Wireless WiFi Link 4965AGN Adapter Firmware
1377 	_AddPackageCredit(
1378 		PackageCredit("Intel Wireless WiFi Link 4965AGN Adapter Firmware")
1379 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2007 "
1380 			"Intel Corporation. All rights reserved."))
1381 		.SetLicense(kIntelFirmware)
1382 		.SetURL("http://www.intellinuxwireless.org/"));
1383 
1384 	// Marvell 88w8363
1385 	_AddPackageCredit(PackageCredit("Marvell 88w8363")
1386 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007-2009 "
1387 			"Marvell Semiconductor, Inc. All rights reserved."))
1388 		.SetLicense(kMarvellFirmware)
1389 		.SetURL("http://www.marvell.com/"));
1390 
1391 	// Ralink Firmware RT2501/RT2561/RT2661
1392 	_AddPackageCredit(PackageCredit("Ralink Firmware RT2501/RT2561/RT2661")
1393 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007 "
1394 			"Ralink Technology Corporation. All rights reserved."))
1395 		.SetLicense(kRalinkFirmware)
1396 		.SetURL("http://www.ralinktech.com/"));
1397 #endif
1398 
1399 	// Gutenprint
1400 	_AddPackageCredit(PackageCredit("Gutenprint")
1401 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
1402 			"1999-2010 by the authors of Gutenprint. All rights reserved."))
1403 		.SetLicense(kGPLv2)
1404 		.SetURL("http://gutenprint.sourceforge.net/"));
1405 
1406 	// libwebp
1407 	_AddPackageCredit(PackageCredit("libwebp")
1408 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
1409 			"2010-2011 Google Inc. All rights reserved."))
1410 		.SetLicense(kBSDThreeClause)
1411 		.SetURL("http://www.webmproject.org/code/#libwebp_webp_image_library"));
1412 
1413 	// GTF
1414 	_AddPackageCredit(PackageCredit("GTF")
1415 		.SetCopyright(B_TRANSLATE("2001 by Andy Ritger based on the "
1416 			"Generalized Timing Formula"))
1417 		.SetLicense(kBSDThreeClause)
1418 		.SetURL("http://gtf.sourceforge.net/"));
1419 
1420 	// libqrencode
1421 	_AddPackageCredit(PackageCredit("libqrencode")
1422 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2012 Kentaro Fukuchi"))
1423 		.SetLicense(kLGPLv21)
1424 		.SetURL("http://fukuchi.org/works/qrencode/"));
1425 
1426 	_AddCopyrightsFromAttribute();
1427 	_AddPackageCreditEntries();
1428 
1429 	return new CropView(creditsScroller, 0, 1, 1, 1);
1430 }
1431 
1432 
1433 status_t
1434 AboutView::_GetLicensePath(const char* license, BPath& path)
1435 {
1436 	BPathFinder pathFinder;
1437 	BStringList paths;
1438 	struct stat st;
1439 
1440 	status_t error = pathFinder.FindPaths(B_FIND_PATH_DATA_DIRECTORY,
1441 		"licenses", paths);
1442 
1443 	for (int i = 0; i < paths.CountStrings(); ++i) {
1444 		if (error == B_OK && path.SetTo(paths.StringAt(i)) == B_OK
1445 			&& path.Append(license) == B_OK
1446 			&& lstat(path.Path(), &st) == 0) {
1447 			return B_OK;
1448 		}
1449 	}
1450 
1451 	path.Unset();
1452 	return B_ENTRY_NOT_FOUND;
1453 }
1454 
1455 
1456 void
1457 AboutView::_AddCopyrightsFromAttribute()
1458 {
1459 #ifdef __HAIKU__
1460 	// open the app executable file
1461 	char appPath[B_PATH_NAME_LENGTH];
1462 	int appFD;
1463 	if (BPrivate::get_app_path(appPath) != B_OK
1464 		|| (appFD = open(appPath, O_RDONLY)) < 0) {
1465 		return;
1466 	}
1467 
1468 	// open the attribute
1469 	int attrFD = fs_fopen_attr(appFD, "COPYRIGHTS", B_STRING_TYPE, O_RDONLY);
1470 	close(appFD);
1471 	if (attrFD < 0)
1472 		return;
1473 
1474 	// attach it to a FILE
1475 	FILE* attrFile = fdopen(attrFD, "r");
1476 	if (attrFile == NULL) {
1477 		close(attrFD);
1478 		return;
1479 	}
1480 	CObjectDeleter<FILE, int> _(attrFile, fclose);
1481 
1482 	// read and parse the copyrights
1483 	BMessage package;
1484 	BString fieldName;
1485 	BString fieldValue;
1486 	char lineBuffer[LINE_MAX];
1487 	while (char* line = fgets(lineBuffer, sizeof(lineBuffer), attrFile)) {
1488 		// chop off line break
1489 		size_t lineLen = strlen(line);
1490 		if (lineLen > 0 && line[lineLen - 1] == '\n')
1491 			line[--lineLen] = '\0';
1492 
1493 		// flush previous field, if a new field begins, otherwise append
1494 		if (lineLen == 0 || !isspace(line[0])) {
1495 			// new field -- flush the previous one
1496 			if (fieldName.Length() > 0) {
1497 				fieldValue = trim_string(fieldValue.String(),
1498 					fieldValue.Length());
1499 				package.AddString(fieldName.String(), fieldValue);
1500 				fieldName = "";
1501 			}
1502 		} else if (fieldName.Length() > 0) {
1503 			// append to current field
1504 			fieldValue += line;
1505 			continue;
1506 		} else {
1507 			// bogus line -- ignore
1508 			continue;
1509 		}
1510 
1511 		if (lineLen == 0)
1512 			continue;
1513 
1514 		// parse new field
1515 		char* colon = strchr(line, ':');
1516 		if (colon == NULL) {
1517 			// bogus line -- ignore
1518 			continue;
1519 		}
1520 
1521 		fieldName.SetTo(line, colon - line);
1522 		fieldName = trim_string(line, colon - line);
1523 		if (fieldName.Length() == 0) {
1524 			// invalid field name
1525 			continue;
1526 		}
1527 
1528 		fieldValue = colon + 1;
1529 
1530 		if (fieldName == "Package") {
1531 			// flush the current package
1532 			_AddPackageCredit(PackageCredit(package));
1533 			package.MakeEmpty();
1534 		}
1535 	}
1536 
1537 	// flush current package
1538 	_AddPackageCredit(PackageCredit(package));
1539 #endif
1540 }
1541 
1542 
1543 void
1544 AboutView::_AddPackageCreditEntries()
1545 {
1546 	// sort the packages case-insensitively
1547 	PackageCredit* packages[fPackageCredits.size()];
1548 	int32 count = 0;
1549 	for (PackageCreditMap::iterator it = fPackageCredits.begin();
1550 			it != fPackageCredits.end(); ++it) {
1551 		packages[count++] = it->second;
1552 	}
1553 
1554 	if (count > 1) {
1555 		std::sort(packages, packages + count,
1556 			&PackageCredit::NameLessInsensitive);
1557 	}
1558 
1559 	// add the credits
1560 	for (int32 i = 0; i < count; i++) {
1561 		PackageCredit* package = packages[i];
1562 
1563 		BString text(package->CopyrightAt(0));
1564 		int32 count = package->CountCopyrights();
1565 		for (int32 i = 1; i < count; i++)
1566 			text << "\n" << package->CopyrightAt(i);
1567 
1568 		AddCopyrightEntry(package->PackageName(), text.String(),
1569 			package->Licenses(), package->Sources(), package->URL());
1570 	}
1571 }
1572 
1573 
1574 void
1575 AboutView::_AddPackageCredit(const PackageCredit& package)
1576 {
1577 	if (!package.IsValid())
1578 		return;
1579 
1580 	PackageCreditMap::iterator it = fPackageCredits.find(package.PackageName());
1581 	if (it != fPackageCredits.end()) {
1582 		// If the new package credit isn't "better" than the old one, ignore it.
1583 		PackageCredit* oldPackage = it->second;
1584 		if (!package.IsBetterThan(*oldPackage))
1585 			return;
1586 
1587 		// replace the old credit
1588 		fPackageCredits.erase(it);
1589 		delete oldPackage;
1590 	}
1591 
1592 	fPackageCredits[package.PackageName()] = new PackageCredit(package);
1593 }
1594 
1595 
1596 //	#pragma mark -
1597 
1598 
1599 static const char*
1600 MemSizeToString(char string[], size_t size, system_info* info)
1601 {
1602 	int inaccessibleMemory = int(info->ignored_pages
1603 		* (B_PAGE_SIZE / 1048576.0f) + 0.5f);
1604 	if (inaccessibleMemory > 0) {
1605 		BString message(B_TRANSLATE("%total MiB total, %inaccessible MiB "
1606 			"inaccessible"));
1607 
1608 		snprintf(string, size, "%d", int((info->max_pages
1609 			+ info->ignored_pages) * (B_PAGE_SIZE / 1048576.0f) + 0.5f));
1610 		message.ReplaceFirst("%total", string);
1611 
1612 		snprintf(string, size, "%d", inaccessibleMemory);
1613 		message.ReplaceFirst("%inaccessible", string);
1614 		strncpy(string, message.String(), size);
1615 	} else {
1616 		snprintf(string, size, B_TRANSLATE("%d MiB total"),
1617 			int(info->max_pages * (B_PAGE_SIZE / 1048576.0f) + 0.5f));
1618 	}
1619 
1620 	return string;
1621 }
1622 
1623 
1624 static const char*
1625 MemUsageToString(char string[], size_t size, system_info* info)
1626 {
1627 	snprintf(string, size, B_TRANSLATE("%d MiB used (%d%%)"),
1628 		int(info->used_pages * (B_PAGE_SIZE / 1048576.0f) + 0.5f),
1629 		int(100 * info->used_pages / info->max_pages));
1630 
1631 	return string;
1632 }
1633 
1634 
1635 static const char*
1636 UptimeToString(char string[], size_t size)
1637 {
1638 	BDurationFormat formatter;
1639 	BString str;
1640 
1641 	bigtime_t uptime = system_time();
1642 	bigtime_t now = (bigtime_t)time(NULL) * 1000000;
1643 	formatter.Format(str, now - uptime, now);
1644 	str.CopyInto(string, 0, size);
1645 	string[std::min((size_t)str.Length(), size)] = '\0';
1646 
1647 	return string;
1648 }
1649 
1650 
1651 int
1652 main()
1653 {
1654 	AboutApp app;
1655 	app.Run();
1656 	return 0;
1657 }
1658 
1659