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