xref: /haiku/src/apps/aboutsystem/AboutSystem.cpp (revision 991dadd6324f7b7a68e94743a39ebae789823228)
1 /*
2  * Copyright 2005-2012, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		René Gollent
8  *		Wim van der Meer <WPJvanderMeer@gmail.com>
9  */
10 
11 
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <time.h>
15 #include <unistd.h>
16 
17 #include <algorithm>
18 #include <map>
19 #include <string>
20 
21 #include <AppFileInfo.h>
22 #include <Application.h>
23 #include <Bitmap.h>
24 #include <DurationFormat.h>
25 #include <File.h>
26 #include <FindDirectory.h>
27 #include <Font.h>
28 #include <fs_attr.h>
29 #include <LayoutBuilder.h>
30 #include <MessageRunner.h>
31 #include <Messenger.h>
32 #include <OS.h>
33 #include <Path.h>
34 #include <PathFinder.h>
35 #include <Resources.h>
36 #include <Screen.h>
37 #include <ScrollView.h>
38 #include <String.h>
39 #include <StringList.h>
40 #include <StringView.h>
41 #include <TranslationUtils.h>
42 #include <TranslatorFormats.h>
43 #include <View.h>
44 #include <Volume.h>
45 #include <VolumeRoster.h>
46 #include <Window.h>
47 
48 #include <AppMisc.h>
49 #include <AutoDeleter.h>
50 #include <cpu_type.h>
51 #include <parsedate.h>
52 #include <system_revision.h>
53 
54 #include <Catalog.h>
55 #include <Language.h>
56 #include <Locale.h>
57 #include <LocaleRoster.h>
58 
59 #include "HyperTextActions.h"
60 #include "HyperTextView.h"
61 #include "Utilities.h"
62 
63 
64 #ifndef LINE_MAX
65 #define LINE_MAX 2048
66 #endif
67 
68 #define SCROLL_CREDITS_VIEW 'mviv'
69 
70 
71 static const char* UptimeToString(char string[], size_t size);
72 static const char* MemSizeToString(char string[], size_t size,
73 	system_info* info);
74 static const char* MemUsageToString(char string[], size_t size,
75 	system_info* info);
76 
77 
78 static const rgb_color kDarkGrey = { 100, 100, 100, 255 };
79 static const rgb_color kHaikuGreen = { 42, 131, 36, 255 };
80 static const rgb_color kHaikuOrange = { 255, 69, 0, 255 };
81 static const rgb_color kHaikuYellow = { 255, 176, 0, 255 };
82 static const rgb_color kLinkBlue = { 80, 80, 200, 255 };
83 static const rgb_color kBeOSBlue = { 0, 0, 200, 255 };
84 static const rgb_color kBeOSRed = { 200, 0, 0, 255 };
85 
86 static const char* kBSDTwoClause = B_TRANSLATE_MARK("BSD (2-clause)");
87 static const char* kBSDThreeClause = B_TRANSLATE_MARK("BSD (3-clause)");
88 static const char* kBSDFourClause = B_TRANSLATE_MARK("BSD (4-clause)");
89 static const char* kGPLv2 = B_TRANSLATE_MARK("GNU GPL v2");
90 static const char* kGPLv3 = B_TRANSLATE_MARK("GNU GPL v3");
91 static const char* kLGPLv2 = B_TRANSLATE_MARK("GNU LGPL v2");
92 static const char* kLGPLv21 = B_TRANSLATE_MARK("GNU LGPL v2.1");
93 static const char* kMITNoPromotion = B_TRANSLATE_MARK("MIT (no promotion)");
94 static const char* kPublicDomain = B_TRANSLATE_MARK("Public Domain");
95 #ifdef __INTEL__
96 static const char* kIntel2xxxFirmware = B_TRANSLATE_MARK("Intel (2xxx firmware)");
97 static const char* kIntelFirmware = B_TRANSLATE_MARK("Intel (firmware)");
98 static const char* kMarvellFirmware = B_TRANSLATE_MARK("Marvell (firmware)");
99 static const char* kRalinkFirmware = B_TRANSLATE_MARK("Ralink (firmware)");
100 #endif
101 
102 typedef struct
103 {
104 	const char* languageCode;
105 	const char* names;
106 } Translation;
107 
108 static const Translation gTranslations[] =
109 {
110 	{ "ar",
111 		"Khaled Berraoui - khallebal\n"
112 		"Kendhia\n"
113 	},
114 	{ "be",
115 		"Michael Bulash\n"
116 	},
117 	{ "bg",
118 		"Ognyan Valeri Angelov\n"
119 		"cssvb94\n"
120 	},
121 	{ "cs",
122 		"Pavel Drotár\n"
123 		"Matěj Kocián\n"
124 	},
125 	{ "da",
126 		"Brian Matzon\n"
127 	},
128 	{ "de",
129 		"Colin Günther\n"
130 		"Mirko Israel\n"
131 		"leszek\n"
132 		"Christian Morgenroth\n"
133 		"Aleksas Pantechovskis\n"
134 		"Joachim Seemer - Humdinger\n"
135 		"Matthias Spreiter\n"
136 		"Ivaylo Tsenkov\n"
137 		"svend\n"
138 	},
139 	{ "el",
140 		"Γιάννης Κωνσταντινίδης (Giannis Konstantinidis) - giannisk\n"
141 		"Βαγγέλης Μαμαλάκης (Vaggelis Mamalakis)\n"
142 		"Άλεξ-Π. Νάτσιος (Alex-P. Natsios) - Drakevr\n"
143 	},
144 	{ "eo",
145 		"Travis D. Reed - Dancxjo\n"
146 	},
147 	{ "es",
148 		"Pedro Arregui\n"
149 		"Zola Bridges\n"
150 		"Nicolás C - CapitanPico\n"
151 		"Oscar Carballal - oscarcp\n"
152 		"Miguel Zúñiga González - miguel~1.mx\n"
153 		"Luis Gustavo Lira\n"
154 		"Victor Madariaga\n"
155 		"César Ortiz Pantoja - ccortiz\n"
156 	},
157 	{ "fi",
158 		"Jorma Karvonen - Karvjorm\n"
159 		"Jaakko Leikas - Garjala\n"
160 		"Slavi Stefanov Sotirov\n"
161 	},
162 	{ "fr",
163 		"Jean-Loïc Charroud\n"
164 		"Adrien Destugues - PulkoMandy\n"
165 		"Florent Revest\n"
166 		"Harsh Vardhan\n"
167 	},
168 	{ "hi",
169 		"Abhishek Arora\n"
170 		"Dhruwat Bhagat\n"
171 		"Jayneil Dalal\n"
172 		"Atharva Lath\n"
173 	},
174 	{ "hr",
175 		"Ivica Koli\n"
176 		"Zlatko Sehanović\n"
177 		"zvacet\n"
178 	},
179 	{ "hu",
180 		"Zsolt Bicskei\n"
181 		"Róbert Dancsó - dsjonny\n"
182 		"Kálmán Kéménczy\n"
183 		"Zoltán Mizsei - miqlas\n"
184 		"Bence Nagy\n"
185 		"Zoltán Szabó - Bird\n"
186 	},
187 	{ "it",
188 		"Andrea Bernardi\n"
189 		"Dario Casalinuovo\n"
190 		"Francesco Franchina\n"
191 		"Lorenzo Frezza\n"
192 		"Mometto Nicola\n"
193 		"Michael Peppers\n"
194 	},
195 	{ "ja",
196 		"Satoshi Eguchi\n"
197 		"Shota Fukumori\n"
198 		"hiromu1996\n"
199 		"Hironori Ichimiya\n"
200 		"Jorge G. Mare - Koki\n"
201 		"Takashi Murai\n"
202 		"nolze\n"
203 		"SHINTA\n"
204 		"thebowseat\n"
205 		"Hiroyuki Tsutsumi\n"
206 		"Hiromu Yakura\n"
207 		"The JPBE.net user group\n"
208 	},
209 	{ "lt",
210 		"Algirdas Buckus\n"
211 		"Simonas Kazlauskas\n"
212 		"Rimas Kudelis\n"
213 	},
214 	{ "nl",
215 		"Floris Kint\n"
216 		"Meanwhile\n"
217 	},
218 	{ "pl",
219 		"Szymon Barczak\n"
220 		"Grzegorz Dąbrowski\n"
221 		"Hubert Hareńczyk\n"
222 		"Krzysztof Miemiec\n"
223 		"Artur Wyszyński\n"
224 	},
225 	{ "pt",
226 		"Marcos Alves - Xeon3D\n"
227 		"Vasco Costa - gluon\n"
228 		"Michael Vinícius de Oliveira - michaelvo\n"
229 	},
230 	{ "pt_BR",
231 		"Cabral Bandeira - beyraq\n"
232 		"Adriano A. Duarte - Sri_Dhryko\n"
233 		"Tiago Matos - tiagoms\n"
234 		"Nadilson Santana - nadilsonsantana\n"
235 	},
236 	{ "ro",
237 		"Victor Carbune\n"
238 		"Silviu Dureanu\n"
239 		"Alexsander Krustev\n"
240 		"Danca Monica\n"
241 		"Florentina Mușat\n"
242 		"Dragos Serban\n"
243 		"Hedeș Cristian Teodor\n"
244 		"Ivaylo Tsenkov\n"
245 		"Călinescu Valentin\n"
246 	},
247 	{ "ru",
248 		"Tatyana Fursic - iceid\n"
249 		"StoroZ Gneva\n"
250 		"Rodastahm Islamov - RISC\n"
251 		"Eugene Katashov - mrNoisy\n"
252 		"Reznikov Sergei - Diver\n"
253 		"Michael Smirnov\n"
254 		"Vladimir Vasilenko\n"
255 	},
256 	{ "sk",
257 		"Ivan Masár\n"
258 	},
259 	{ "sr",
260 		"Nikola Miljković\n"
261 	},
262 	{ "sv",
263 		"Patrik Gissberg\n"
264 		"Johan Holmberg\n"
265 		"Jimmy Olsson - phalax\n"
266 		"Jonas Sundström\n"
267 		"Victor Widell\n"
268 	},
269 	{ "tr",
270 		"Hüseyin Aksu\n"
271 		"Halil İbrahim Azak\n"
272 		"Aras Ergus\n"
273 		"Enes Burhan Kuran\n"
274 		"Ali Rıza Nazlı\n"
275 	},
276 	{ "uk",
277 		"Mariya Pilipchuk\n"
278 		"Alex Rudyk - totish\n"
279 		"Oleg Varunok\n"
280 	},
281 	{ "zh",
282 		"Pengfei Han - kurain\n"
283 	}
284 };
285 
286 #define kNumberOfTranslations (sizeof(gTranslations) / sizeof(Translation))
287 
288 
289 static int
290 TranslationComparator(const void* left, const void* right)
291 {
292 	const Translation* leftTranslation = *(const Translation**)left;
293 	const Translation* rightTranslation = *(const Translation**)right;
294 
295 	BLanguage* language;
296 	BString leftName;
297 	if (BLocaleRoster::Default()->GetLanguage(leftTranslation->languageCode,
298 			&language) == B_OK) {
299 		language->GetName(leftName);
300 		delete language;
301 	} else
302 		leftName = leftTranslation->languageCode;
303 
304 	BString rightName;
305 	if (BLocaleRoster::Default()->GetLanguage(rightTranslation->languageCode,
306 			&language) == B_OK) {
307 		language->GetName(rightName);
308 		delete language;
309 	} else
310 		rightName = rightTranslation->languageCode;
311 
312 	BCollator collator;
313 	BLocale::Default()->GetCollator(&collator);
314 	return collator.Compare(leftName.String(), rightName.String());
315 }
316 
317 
318 class AboutApp : public BApplication {
319 public:
320 							AboutApp();
321 };
322 
323 
324 class AboutWindow : public BWindow {
325 public:
326 							AboutWindow();
327 
328 	virtual	bool			QuitRequested();
329 };
330 
331 
332 class LogoView : public BView {
333 public:
334 							LogoView();
335 	virtual					~LogoView();
336 
337 	virtual	BSize			MinSize();
338 	virtual	BSize			MaxSize();
339 
340 	virtual void			Draw(BRect updateRect);
341 
342 private:
343 			BBitmap*		fLogo;
344 };
345 
346 
347 class CropView : public BView {
348 public:
349 							CropView(BView* target, int32 left, int32 top,
350 								int32 right, int32 bottom);
351 	virtual					~CropView();
352 
353 	virtual	BSize			MinSize();
354 	virtual	BSize			MaxSize();
355 
356 	virtual void			DoLayout();
357 
358 private:
359 			BView*			fTarget;
360 			int32			fCropLeft;
361 			int32			fCropTop;
362 			int32			fCropRight;
363 			int32			fCropBottom;
364 };
365 
366 
367 class AboutView : public BView {
368 public:
369 							AboutView();
370 							~AboutView();
371 
372 	virtual void			AttachedToWindow();
373 	virtual void			Pulse();
374 
375 	virtual void			MessageReceived(BMessage* msg);
376 	virtual void			MouseDown(BPoint point);
377 
378 			void			AddCopyrightEntry(const char* name,
379 								const char* text,
380 								const StringVector& licenses,
381 								const StringVector& sources,
382 								const char* url);
383 			void			AddCopyrightEntry(const char* name,
384 								const char* text, const char* url = NULL);
385 			void			PickRandomHaiku();
386 
387 
388 private:
389 	typedef std::map<std::string, PackageCredit*> PackageCreditMap;
390 
391 private:
392 			BView*			_CreateLabel(const char* name, const char* label);
393 			BView*			_CreateCreditsView();
394 			status_t		_GetLicensePath(const char* license,
395 								BPath& path);
396 			void			_AddCopyrightsFromAttribute();
397 			void			_AddPackageCredit(const PackageCredit& package);
398 			void			_AddPackageCreditEntries();
399 
400 			BStringView*	fMemView;
401 			BTextView*		fUptimeView;
402 			BView*			fInfoView;
403 			HyperTextView*	fCreditsView;
404 
405 			BBitmap*		fLogo;
406 
407 			bigtime_t		fLastActionTime;
408 			BMessageRunner*	fScrollRunner;
409 			PackageCreditMap fPackageCredits;
410 };
411 
412 
413 //	#pragma mark -
414 
415 
416 AboutApp::AboutApp()
417 	: BApplication("application/x-vnd.Haiku-About")
418 {
419 	B_TRANSLATE_MARK_SYSTEM_NAME_VOID("AboutSystem");
420 
421 	AboutWindow *window = new(std::nothrow) AboutWindow();
422 	if (window)
423 		window->Show();
424 }
425 
426 
427 //	#pragma mark -
428 
429 
430 #undef B_TRANSLATION_CONTEXT
431 #define B_TRANSLATION_CONTEXT "AboutWindow"
432 
433 AboutWindow::AboutWindow()
434 	: BWindow(BRect(0, 0, 500, 300), B_TRANSLATE("About this system"),
435 		B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE)
436 {
437 	SetLayout(new BGroupLayout(B_VERTICAL));
438 	AddChild(new AboutView());
439 
440 	// Make sure we take the minimal window size into account when centering
441 	BSize size = GetLayout()->MinSize();
442 	ResizeTo(max_c(size.width, Bounds().Width()),
443 		max_c(size.height, Bounds().Height()));
444 
445 	CenterOnScreen();
446 }
447 
448 
449 bool
450 AboutWindow::QuitRequested()
451 {
452 	be_app->PostMessage(B_QUIT_REQUESTED);
453 	return true;
454 }
455 
456 
457 //	#pragma mark - LogoView
458 
459 
460 LogoView::LogoView()
461 	: BView("logo", B_WILL_DRAW)
462 {
463 	fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "logo.png");
464 	SetViewColor(255, 255, 255);
465 }
466 
467 
468 LogoView::~LogoView()
469 {
470 	delete fLogo;
471 }
472 
473 
474 BSize
475 LogoView::MinSize()
476 {
477 	if (fLogo == NULL)
478 		return BSize(0, 0);
479 
480 	return BSize(fLogo->Bounds().Width(), fLogo->Bounds().Height());
481 }
482 
483 
484 BSize
485 LogoView::MaxSize()
486 {
487 	if (fLogo == NULL)
488 		return BSize(0, 0);
489 
490 	return BSize(B_SIZE_UNLIMITED, fLogo->Bounds().Height());
491 }
492 
493 
494 void
495 LogoView::Draw(BRect updateRect)
496 {
497 	if (fLogo != NULL) {
498 		DrawBitmap(fLogo,
499 			BPoint((Bounds().Width() - fLogo->Bounds().Width()) / 2, 0));
500 	}
501 }
502 
503 
504 //	#pragma mark - CropView
505 
506 
507 CropView::CropView(BView* target, int32 left, int32 top, int32 right,
508 		int32 bottom)
509 	: BView("crop view", 0),
510 	fTarget(target),
511 	fCropLeft(left),
512 	fCropTop(top),
513 	fCropRight(right),
514 	fCropBottom(bottom)
515 {
516 	AddChild(target);
517 }
518 
519 
520 CropView::~CropView()
521 {
522 }
523 
524 
525 BSize
526 CropView::MinSize()
527 {
528 	if (fTarget == NULL)
529 		return BSize();
530 
531 	BSize size = fTarget->MinSize();
532 	if (size.width != B_SIZE_UNSET)
533 		size.width -= fCropLeft + fCropRight;
534 	if (size.height != B_SIZE_UNSET)
535 		size.height -= fCropTop + fCropBottom;
536 
537 	return size;
538 }
539 
540 
541 BSize
542 CropView::MaxSize()
543 {
544 	if (fTarget == NULL)
545 		return BSize();
546 
547 	BSize size = fTarget->MaxSize();
548 	if (size.width != B_SIZE_UNSET)
549 		size.width -= fCropLeft + fCropRight;
550 	if (size.height != B_SIZE_UNSET)
551 		size.height -= fCropTop + fCropBottom;
552 
553 	return size;
554 }
555 
556 
557 void
558 CropView::DoLayout()
559 {
560 	BView::DoLayout();
561 
562 	if (fTarget == NULL)
563 		return;
564 
565 	fTarget->MoveTo(-fCropLeft, -fCropTop);
566 	fTarget->ResizeTo(Bounds().Width() + fCropLeft + fCropRight,
567 		Bounds().Height() + fCropTop + fCropBottom);
568 }
569 
570 
571 //	#pragma mark - AboutView
572 
573 #undef B_TRANSLATION_CONTEXT
574 #define B_TRANSLATION_CONTEXT "AboutView"
575 
576 AboutView::AboutView()
577 	: BView("aboutview", B_WILL_DRAW | B_PULSE_NEEDED),
578 	fLastActionTime(system_time()),
579 	fScrollRunner(NULL)
580 {
581 	// Begin Construction of System Information controls
582 
583 	system_info systemInfo;
584 	get_system_info(&systemInfo);
585 
586 	// Create all the various labels for system infomation
587 
588 	// OS Version
589 
590 	char string[1024];
591 	strlcpy(string, B_TRANSLATE("Unknown"), sizeof(string));
592 
593 	// the version is stored in the BEOS:APP_VERSION attribute of libbe.so
594 	BPath path;
595 	if (find_directory(B_BEOS_LIB_DIRECTORY, &path) == B_OK) {
596 		path.Append("libbe.so");
597 
598 		BAppFileInfo appFileInfo;
599 		version_info versionInfo;
600 		BFile file;
601 		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
602 			&& appFileInfo.SetTo(&file) == B_OK
603 			&& appFileInfo.GetVersionInfo(&versionInfo,
604 				B_APP_VERSION_KIND) == B_OK
605 			&& versionInfo.short_info[0] != '\0')
606 			strlcpy(string, versionInfo.short_info, sizeof(string));
607 	}
608 
609 	// Add system revision
610 	const char* haikuRevision = __get_haiku_revision();
611 	if (haikuRevision != NULL) {
612 		strlcat(string, " (", sizeof(string));
613 		strlcat(string, B_TRANSLATE("Revision"), sizeof(string));
614 		strlcat(string, " ", sizeof(string));
615 		strlcat(string, haikuRevision, sizeof(string));
616 		strlcat(string, ")", sizeof(string));
617 	}
618 
619 	BStringView* versionView = new BStringView("ostext", string);
620 	versionView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
621 		B_ALIGN_VERTICAL_UNSET));
622 
623 	BStringView* abiView = new BStringView("abitext", B_HAIKU_ABI_NAME);
624 	abiView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
625 		B_ALIGN_VERTICAL_UNSET));
626 
627 	// CPU count, type and clock speed
628 	char processorLabel[256];
629 	if (systemInfo.cpu_count > 1) {
630 		snprintf(processorLabel, sizeof(processorLabel),
631 			B_TRANSLATE("%ld Processors:"), systemInfo.cpu_count);
632 	} else
633 		strlcpy(processorLabel, B_TRANSLATE("Processor:"),
634 			sizeof(processorLabel));
635 
636 	uint32 topologyNodeCount = 0;
637 	cpu_topology_node_info* topology = NULL;
638 	get_cpu_topology_info(NULL, &topologyNodeCount);
639 	if (topologyNodeCount != 0)
640 		topology = new cpu_topology_node_info[topologyNodeCount];
641 	get_cpu_topology_info(topology, &topologyNodeCount);
642 
643 	enum cpu_platform platform = B_CPU_UNKNOWN;
644 	enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN;
645 	uint32 cpuModel = 0;
646 	for (uint32 i = 0; i < topologyNodeCount; i++) {
647 		switch (topology[i].type) {
648 			case B_TOPOLOGY_ROOT:
649 				platform = topology[i].data.root.platform;
650 				break;
651 
652 			case B_TOPOLOGY_PACKAGE:
653 				cpuVendor = topology[i].data.package.vendor;
654 				break;
655 
656 			case B_TOPOLOGY_CORE:
657 				cpuModel = topology[i].data.core.model;
658 				break;
659 
660 			default:
661 				break;
662 		}
663 	}
664 
665 	delete[] topology;
666 
667 	BString cpuType;
668 	cpuType << get_cpu_vendor_string(cpuVendor)
669 		<< " " << get_cpu_model_string(platform, cpuVendor, cpuModel);
670 
671 	BStringView* cpuView = new BStringView("cputext", cpuType.String());
672 	cpuView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
673 		B_ALIGN_VERTICAL_UNSET));
674 
675 	int32 clockSpeed = get_rounded_cpu_speed();
676 	if (clockSpeed < 1000)
677 		snprintf(string, sizeof(string), B_TRANSLATE("%ld MHz"), clockSpeed);
678 	else
679 		snprintf(string, sizeof(string), B_TRANSLATE("%.2f GHz"),
680 			clockSpeed / 1000.0f);
681 
682 	BStringView* frequencyView = new BStringView("frequencytext", string);
683 	frequencyView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
684 		B_ALIGN_VERTICAL_UNSET));
685 
686 	// RAM
687 	BStringView *memSizeView = new BStringView("ramsizetext",
688 		MemSizeToString(string, sizeof(string), &systemInfo));
689 	memSizeView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
690 		B_ALIGN_VERTICAL_UNSET));
691 	fMemView = new BStringView("ramtext",
692 		MemUsageToString(string, sizeof(string), &systemInfo));
693 	fMemView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
694 		B_ALIGN_VERTICAL_UNSET));
695 
696 	// Kernel build time/date
697 	BString kernelTimeDate;
698 	kernelTimeDate << systemInfo.kernel_build_date
699 		<< " " << systemInfo.kernel_build_time;
700 	BString buildTimeDate;
701 	const BLocale* locale = BLocale::Default();
702 
703 	time_t buildTimeDateStamp = parsedate(kernelTimeDate, -1);
704 	if (buildTimeDateStamp > 0) {
705 		if (locale->FormatDateTime(&buildTimeDate, buildTimeDateStamp,
706 			B_LONG_DATE_FORMAT, B_MEDIUM_TIME_FORMAT) != B_OK)
707 			buildTimeDate.SetTo(kernelTimeDate);
708 	} else
709 		buildTimeDate.SetTo(kernelTimeDate);
710 
711 	BStringView* kernelView = new BStringView("kerneltext", buildTimeDate);
712 	kernelView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
713 		B_ALIGN_VERTICAL_UNSET));
714 
715 	// Uptime
716 	fUptimeView = new BTextView("uptimetext");
717 	fUptimeView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
718 	fUptimeView->MakeEditable(false);
719 	fUptimeView->MakeSelectable(false);
720 	fUptimeView->SetWordWrap(true);
721 
722 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
723 
724 	const float offset = 5;
725 
726 	SetLayout(new BGroupLayout(B_HORIZONTAL, 0));
727 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
728 
729 	BLayoutBuilder::Group<>((BGroupLayout*)GetLayout())
730 		.AddGroup(B_VERTICAL, 0)
731 			.Add(new LogoView())
732 			.AddGroup(B_VERTICAL, 0)
733 				.Add(_CreateLabel("oslabel", B_TRANSLATE("Version:")))
734 				.Add(versionView)
735 				.Add(abiView)
736 				.AddStrut(offset)
737 				.Add(_CreateLabel("cpulabel", processorLabel))
738 				.Add(cpuView)
739 				.Add(frequencyView)
740 				.AddStrut(offset)
741 				.Add(_CreateLabel("memlabel", B_TRANSLATE("Memory:")))
742 				.Add(memSizeView)
743 				.Add(fMemView)
744 				.AddStrut(offset)
745 				.Add(_CreateLabel("kernellabel", B_TRANSLATE("Kernel:")))
746 				.Add(kernelView)
747 				.AddStrut(offset)
748 				.Add(_CreateLabel("uptimelabel",
749 					B_TRANSLATE("Time running:")))
750 				.Add(fUptimeView)
751 				.SetInsets(5, 5, 5, 5)
752 			.End()
753 			// TODO: investigate: adding this causes the time to be cut
754 			//.AddGlue()
755 		.End()
756 		.Add(_CreateCreditsView());
757 
758 	float min = fMemView->MinSize().width * 1.1f;
759 	fCreditsView->SetExplicitMinSize(BSize(min, min));
760 }
761 
762 
763 AboutView::~AboutView()
764 {
765 	delete fScrollRunner;
766 }
767 
768 
769 void
770 AboutView::AttachedToWindow()
771 {
772 	BView::AttachedToWindow();
773 	Window()->SetPulseRate(500000);
774 	SetEventMask(B_POINTER_EVENTS);
775 }
776 
777 
778 void
779 AboutView::MouseDown(BPoint point)
780 {
781 	BRect r(92, 26, 105, 31);
782 	if (r.Contains(point))
783 		BMessenger(this).SendMessage('eegg');
784 
785 	if (Bounds().Contains(point)) {
786 		fLastActionTime = system_time();
787 		delete fScrollRunner;
788 		fScrollRunner = NULL;
789 	}
790 }
791 
792 
793 void
794 AboutView::Pulse()
795 {
796 	char string[255];
797 	system_info info;
798 	get_system_info(&info);
799 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
800 	fMemView->SetText(MemUsageToString(string, sizeof(string), &info));
801 
802 	if (fScrollRunner == NULL
803 		&& system_time() > fLastActionTime + 10000000) {
804 		BMessage message(SCROLL_CREDITS_VIEW);
805 		//fScrollRunner = new BMessageRunner(this, &message, 25000, -1);
806 	}
807 }
808 
809 
810 void
811 AboutView::MessageReceived(BMessage* msg)
812 {
813 	switch (msg->what) {
814 		case SCROLL_CREDITS_VIEW:
815 		{
816 			BScrollBar* scrollBar =
817 				fCreditsView->ScrollBar(B_VERTICAL);
818 			if (scrollBar == NULL)
819 				break;
820 			float max, min;
821 			scrollBar->GetRange(&min, &max);
822 			if (scrollBar->Value() < max)
823 				fCreditsView->ScrollBy(0, 1);
824 
825 			break;
826 		}
827 
828 		case 'eegg':
829 		{
830 			printf("Easter egg\n");
831 			PickRandomHaiku();
832 			break;
833 		}
834 
835 		default:
836 			BView::MessageReceived(msg);
837 			break;
838 	}
839 }
840 
841 
842 void
843 AboutView::AddCopyrightEntry(const char* name, const char* text,
844 	const char* url)
845 {
846 	AddCopyrightEntry(name, text, StringVector(), StringVector(), url);
847 }
848 
849 
850 void
851 AboutView::AddCopyrightEntry(const char* name, const char* text,
852 	const StringVector& licenses, const StringVector& sources,
853 	const char* url)
854 {
855 	BFont font(be_bold_font);
856 	//font.SetSize(be_bold_font->Size());
857 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
858 
859 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuYellow);
860 	fCreditsView->Insert(name);
861 	fCreditsView->Insert("\n");
862 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
863 	fCreditsView->Insert(text);
864 	fCreditsView->Insert("\n");
865 
866 	if (licenses.CountStrings() > 0) {
867 		if (licenses.CountStrings() > 1)
868 			fCreditsView->Insert(B_TRANSLATE("Licenses: "));
869 		else
870 			fCreditsView->Insert(B_TRANSLATE("License: "));
871 
872 		for (int32 i = 0; i < licenses.CountStrings(); i++) {
873 			const char* license = licenses.StringAt(i);
874 
875 			if (i > 0)
876 				fCreditsView->Insert(", ");
877 
878 			BString licenseName;
879 			BString licenseURL;
880 			parse_named_url(license, licenseName, licenseURL);
881 
882 			BPath licensePath;
883 			if (_GetLicensePath(licenseURL, licensePath) == B_OK) {
884 				fCreditsView->InsertHyperText(B_TRANSLATE_NOCOLLECT(licenseName),
885 					new OpenFileAction(licensePath.Path()));
886 			} else
887 				fCreditsView->Insert(licenseName);
888 		}
889 
890 		fCreditsView->Insert("\n");
891 	}
892 
893 	if (sources.CountStrings() > 0) {
894 		fCreditsView->Insert(B_TRANSLATE("Source Code: "));
895 
896 		for (int32 i = 0; i < sources.CountStrings(); i++) {
897 			const char* source = sources.StringAt(i);
898 
899 			if (i > 0)
900 				fCreditsView->Insert(", ");
901 
902 			BString urlName;
903 			BString urlAddress;
904 			parse_named_url(source, urlName, urlAddress);
905 
906 			fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
907 				&kLinkBlue);
908 			fCreditsView->InsertHyperText(urlName,
909 				new URLAction(urlAddress));
910 		}
911 
912 		fCreditsView->Insert("\n");
913 	}
914 
915 	if (url) {
916 		BString urlName;
917 		BString urlAddress;
918 		parse_named_url(url, urlName, urlAddress);
919 
920 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
921 			&kLinkBlue);
922 		fCreditsView->InsertHyperText(urlName,
923 			new URLAction(urlAddress));
924 		fCreditsView->Insert("\n");
925 	}
926 	fCreditsView->Insert("\n");
927 }
928 
929 
930 void
931 AboutView::PickRandomHaiku()
932 {
933 	BPath path;
934 	if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) != B_OK)
935 		path = "/system/data";
936 	path.Append("fortunes");
937 	path.Append("Haiku");
938 
939 	BFile fortunes(path.Path(), B_READ_ONLY);
940 	struct stat st;
941 	if (fortunes.InitCheck() < B_OK)
942 		return;
943 	if (fortunes.GetStat(&st) < B_OK)
944 		return;
945 
946 	char* buff = (char*)malloc((size_t)st.st_size + 1);
947 	if (!buff)
948 		return;
949 	buff[(size_t)st.st_size] = '\0';
950 	BList haikuList;
951 	if (fortunes.Read(buff, (size_t)st.st_size) == (ssize_t)st.st_size) {
952 		char* p = buff;
953 		while (p && *p) {
954 			char* e = strchr(p, '%');
955 			BString* s = new BString(p, e ? (e - p) : -1);
956 			haikuList.AddItem(s);
957 			p = e;
958 			if (p && (*p == '%'))
959 				p++;
960 			if (p && (*p == '\n'))
961 				p++;
962 		}
963 	}
964 	free(buff);
965 	if (haikuList.CountItems() < 1)
966 		return;
967 
968 	BString* s = (BString*)haikuList.ItemAt(rand() % haikuList.CountItems());
969 	BFont font(be_bold_font);
970 	font.SetSize(be_bold_font->Size());
971 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
972 	fCreditsView->SelectAll();
973 	fCreditsView->Delete();
974 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kDarkGrey);
975 	fCreditsView->Insert(s->String());
976 	fCreditsView->Insert("\n");
977 	while ((s = (BString*)haikuList.RemoveItem((int32)0))) {
978 		delete s;
979 	}
980 }
981 
982 
983 BView*
984 AboutView::_CreateLabel(const char* name, const char* label)
985 {
986 	BStringView* labelView = new BStringView(name, label);
987 	labelView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
988 		B_ALIGN_VERTICAL_UNSET));
989 	labelView->SetFont(be_bold_font);
990 	return labelView;
991 }
992 
993 
994 BView*
995 AboutView::_CreateCreditsView()
996 {
997 	// Begin construction of the credits view
998 	fCreditsView = new HyperTextView("credits");
999 	fCreditsView->SetFlags(fCreditsView->Flags() | B_FRAME_EVENTS);
1000 	fCreditsView->SetStylable(true);
1001 	fCreditsView->MakeEditable(false);
1002 	fCreditsView->SetWordWrap(true);
1003 	fCreditsView->SetInsets(5, 5, 5, 5);
1004 	fCreditsView->SetViewColor(ui_color(B_DOCUMENT_BACKGROUND_COLOR));
1005 
1006 	BScrollView* creditsScroller = new BScrollView("creditsScroller",
1007 		fCreditsView, B_WILL_DRAW | B_FRAME_EVENTS, false, true,
1008 		B_PLAIN_BORDER);
1009 
1010 	// Haiku copyright
1011 	BFont font(be_bold_font);
1012 	font.SetSize(font.Size() + 4);
1013 
1014 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
1015 	fCreditsView->Insert("Haiku\n");
1016 
1017 	char string[1024];
1018 	time_t time = ::time(NULL);
1019 	struct tm* tm = localtime(&time);
1020 	int32 year = tm->tm_year + 1900;
1021 	if (year < 2008)
1022 		year = 2008;
1023 	snprintf(string, sizeof(string),
1024 		COPYRIGHT_STRING "2001-%" B_PRId32 " The Haiku project. ", year);
1025 
1026 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1027 	fCreditsView->Insert(string);
1028 
1029 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1030 	fCreditsView->Insert(B_TRANSLATE("The copyright to the Haiku code is "
1031 		"property of Haiku, Inc. or of the respective authors where expressly "
1032 		"noted in the source. Haiku" B_UTF8_REGISTERED
1033 		" and the HAIKU logo" B_UTF8_REGISTERED
1034 		" are registered trademarks of Haiku, Inc."
1035 		"\n\n"));
1036 
1037 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kLinkBlue);
1038 	fCreditsView->InsertHyperText("http://www.haiku-os.org",
1039 		new URLAction("http://www.haiku-os.org"));
1040 	fCreditsView->Insert("\n\n");
1041 
1042 	font.SetSize(be_bold_font->Size());
1043 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
1044 
1045 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
1046 	fCreditsView->Insert(B_TRANSLATE("Current maintainers:\n"));
1047 
1048 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1049 	fCreditsView->Insert(
1050 		"Ithamar R. Adema\n"
1051 		"Bruno G. Albuquerque\n"
1052 		"Stephan Aßmus\n"
1053 		"Stefano Ceccherini\n"
1054 		"Rudolf Cornelissen\n"
1055 		"Alexandre Deckner\n"
1056 		"Adrien Destugues\n"
1057 		"Oliver Ruiz Dorantes\n"
1058 		"Axel Dörfler\n"
1059 		"Jérôme Duval\n"
1060 		"Pawel Dziepak\n"
1061 		"René Gollent\n"
1062 		"Bryce Groff\n"
1063 		"Colin Günther\n"
1064 		"Jessica Hamilton\n"
1065 		"Fredrik Holmqvist\n"
1066 		"Philippe Houdoin\n"
1067 		"Ryan Leavengood\n"
1068 		"Michael Lotz\n"
1069 		"Matt Madia\n"
1070 		"Scott McCreary\n"
1071 		"David McPaul\n"
1072 		"Fredrik Modéen\n"
1073 		"Marcus Overhagen\n"
1074 		"Michael Pfeiffer\n"
1075 		"Joseph R. Prostko\n"
1076 		"François Revol\n"
1077 		"Philippe Saint-Pierre\n"
1078 		"Jonathan Schleifer\n"
1079 		"John Scipione\n"
1080 		"Alex Smith\n"
1081 		"Oliver Tappe\n"
1082 		"Gerasim Troeglazov\n"
1083 		"Alexander von Gluck IV\n"
1084 		"Ingo Weinhold\n"
1085 		"Alex Wilson\n"
1086 		"Artur Wyszyński\n"
1087 		"Clemens Zeidler\n"
1088 		"Siarzhuk Zharski\n"
1089 		"\n");
1090 
1091 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
1092 	fCreditsView->Insert(B_TRANSLATE("Past maintainers:\n"));
1093 
1094 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1095 	fCreditsView->Insert(
1096 		"Andrew Bachmann\n"
1097 		"Salvatore Benedetto\n"
1098 		"Tyler Dauwalder\n"
1099 		"Daniel Furrer\n"
1100 		"Andre Alves Garzia\n"
1101 		"Karsten Heimrich\n"
1102 		"Erik Jaesler\n"
1103 		"Maurice Kalinowski\n"
1104 		"Euan Kirkhope\n"
1105 		"Marcin Konicki\n"
1106 		"Waldemar Kornewald\n"
1107 		"Thomas Kurschel\n"
1108 		"Brecht Machiels\n"
1109 		"Wim van der Meer\n"
1110 		"Frans Van Nispen\n"
1111 		"Adi Oanca\n"
1112 		"Michael Phipps\n"
1113 		"Niels Sascha Reedijk\n"
1114 		"David Reid\n"
1115 		"Hugo Santos\n"
1116 		"Alexander G. M. Smith\n"
1117 		"Andrej Spielmann\n"
1118 		"Jonas Sundström\n"
1119 		"Bryan Varner\n"
1120 		"Nathan Whitehorn\n"
1121 		"Michael Wilber\n"
1122 		"Jonathan Yoder\n"
1123 		"Gabe Yoder\n"
1124 		"\n");
1125 
1126 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
1127 	fCreditsView->Insert(B_TRANSLATE("Website, marketing & documentation:\n"));
1128 
1129 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1130 	fCreditsView->Insert(
1131 		"Phil Greenway\n"
1132 		"Gavin James\n"
1133 		"Urias McCullough\n"
1134 		"Niels Sascha Reedijk\n"
1135 		"Joachim Seemer - Humdinger\n"
1136 		"Jonathan Yoder\n"
1137 		"\n");
1138 
1139 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
1140 	fCreditsView->Insert(B_TRANSLATE("Contributors:\n"));
1141 
1142 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1143 	fCreditsView->Insert(
1144 		"Andrea Anzani\n"
1145 		"Sean Bartell\n"
1146 		"Hannah Boneß\n"
1147 		"Andre Braga\n"
1148 		"Michael Bulash\n"
1149 		"Bruce Cameron\n"
1150 		"Jean-Loïc Charroud\n"
1151 		"Greg Crain\n"
1152 		"Michael Davidson\n"
1153 		"David Dengg\n"
1154 		"John Drinkwater\n"
1155 		"Yongcong Du\n"
1156 		"Cian Duffy\n"
1157 		"Vincent Duvert\n"
1158 		"Mikael Eiman\n"
1159 		"Fredrik Ekdahl\n"
1160 		"Joshua R. Elsasser\n"
1161 		"Atis Elsts\n"
1162 		"Mark Erben\n"
1163 		"Christian Fasshauer\n"
1164 		"Andreas Färber\n"
1165 		"Janito Ferreira Filho\n"
1166 		"Pier Luigi Fiorini\n"
1167 		"Marc Flerackers\n"
1168 		"Michele Frau - zuMi\n"
1169 		"Landon Fuller\n"
1170 		"Deyan Genovski\n"
1171 		"Pete Goodeve\n"
1172 		"Lucian Adrian Grijincu\n"
1173 		"Sean Healy\n"
1174 		"Andreas Henriksson\n"
1175 		"Matthijs Hollemans\n"
1176 		"Mathew Hounsell\n"
1177 		"Morgan Howe\n"
1178 		"Christophe Huriaux\n"
1179 		"Jian Jiang\n"
1180 		"Ma Jie\n"
1181 		"Carwyn Jones\n"
1182 		"Prasad Joshi\n"
1183 		"Vasilis Kaoutsis\n"
1184 		"James Kim\n"
1185 		"Shintaro Kinugawa\n"
1186 		"Jan Klötzke\n"
1187 		"Kurtis Kopf\n"
1188 		"Tomáš Kučera\n"
1189 		"Luboš Kulič\n"
1190 		"Elad Lahav\n"
1191 		"Anthony Lee\n"
1192 		"Santiago Lema\n"
1193 		"Raynald Lesieur\n"
1194 		"Oscar Lesta\n"
1195 		"Jerome Leveque\n"
1196 		"Brian Luft\n"
1197 		"Christof Lutteroth\n"
1198 		"Graham MacDonald\n"
1199 		"Jorge G. Mare - Koki\n"
1200 		"Jan Matějek\n"
1201 		"Brian Matzon\n"
1202 		"Christopher ML Zumwalt May\n"
1203 		"Andrew McCall\n"
1204 		"Nathan Mentley\n"
1205 		"Marius Middelthon\n"
1206 		"Marco Minutoli\n"
1207 		"Misza\n"
1208 		"Hamish Morrison\n"
1209 		"MrSiggler\n"
1210 		"Takashi Murai\n"
1211 		"Alan Murta\n"
1212 		"Raghuram Nagireddy\n"
1213 		"Kazuho Okui\n"
1214 		"Jeroen Oortwijn - idefix\n"
1215 		"Pahtz\n"
1216 		"Michael Paine\n"
1217 		"Adrian Panasiuk\n"
1218 		"Aleksas Pantechovskis\n"
1219 		"Romain Picard\n"
1220 		"Francesco Piccinno\n"
1221 		"Peter Poláčik\n"
1222 		"David Powell\n"
1223 		"Jeremy Rand\n"
1224 		"Hartmut Reh\n"
1225 		"Daniel Reinhold\n"
1226 		"Sergei Reznikov\n"
1227 		"Chris Roberts\n"
1228 		"Samuel Rodríguez Pérez\n"
1229 		"Thomas Roell\n"
1230 		"Rafael Romo\n"
1231 		"Ralf Schülke\n"
1232 		"Zousar Shaker\n"
1233 		"Caitlin Shaw\n"
1234 		"Geoffry Song\n"
1235 		"Daniel Switkin\n"
1236 		"Atsushi Takamatsu\n"
1237 		"James Urquhart\n"
1238 		"Jason Vandermark\n"
1239 		"Sandor Vroemisse\n"
1240 		"Jürgen Wall\n"
1241 		"Denis Washington\n"
1242 		"Ulrich Wimboeck\n"
1243 		"Johannes Wischert\n"
1244 		"James Woodcock\n"
1245 		"Hong Yul Yang\n"
1246 		"Gerald Zajac\n"
1247 		"Łukasz Zemczak\n"
1248 		"JiSheng Zhang\n"
1249 		"Zhao Shuai\n");
1250 	fCreditsView->Insert(
1251 		B_TRANSLATE("\n" B_UTF8_ELLIPSIS
1252 			"and probably some more we forgot to mention (sorry!)"
1253 			"\n\n"));
1254 
1255 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
1256 	fCreditsView->Insert(B_TRANSLATE("Translations:\n"));
1257 
1258 	BLanguage* lang;
1259 	BString langName;
1260 
1261 	BList sortedTranslations;
1262 	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
1263 		const Translation* translation = &gTranslations[i];
1264 		sortedTranslations.AddItem((void*)translation);
1265 	}
1266 	sortedTranslations.SortItems(TranslationComparator);
1267 
1268 	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
1269 		const Translation& translation
1270 			= *(const Translation*)sortedTranslations.ItemAt(i);
1271 
1272 		langName.Truncate(0);
1273 		if (BLocaleRoster::Default()->GetLanguage(translation.languageCode,
1274 				&lang) == B_OK) {
1275 			lang->GetName(langName);
1276 			delete lang;
1277 		} else {
1278 			// We failed to get the localized readable name,
1279 			// go with what we have.
1280 			langName.Append(translation.languageCode);
1281 		}
1282 
1283 		fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
1284 		fCreditsView->Insert("\n");
1285 		fCreditsView->Insert(langName);
1286 		fCreditsView->Insert("\n");
1287 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1288 		fCreditsView->Insert(translation.names);
1289 	}
1290 
1291 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
1292 	fCreditsView->Insert(B_TRANSLATE("\n\nSpecial thanks to:\n"));
1293 
1294 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1295 	BString beosCredits(B_TRANSLATE(
1296 		"Be Inc. and its developer team, for having created BeOS!\n\n"));
1297 	int32 beosOffset = beosCredits.FindFirst("BeOS");
1298 	fCreditsView->Insert(beosCredits.String(),
1299 		(beosOffset < 0) ? beosCredits.Length() : beosOffset);
1300 	if (beosOffset > -1) {
1301 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kBeOSBlue);
1302 		fCreditsView->Insert("B");
1303 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kBeOSRed);
1304 		fCreditsView->Insert("e");
1305 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1306 		beosCredits.Remove(0, beosOffset + 2);
1307 		fCreditsView->Insert(beosCredits.String(), beosCredits.Length());
1308 	}
1309 	fCreditsView->Insert(
1310 		B_TRANSLATE("Travis Geiselbrecht (and his NewOS kernel)\n"));
1311 	fCreditsView->Insert(
1312 		B_TRANSLATE("Michael Phipps (project founder)\n\n"));
1313 	fCreditsView->Insert(
1314 		B_TRANSLATE("The Haiku-Ports team\n"));
1315 	fCreditsView->Insert(
1316 		B_TRANSLATE("The Haikuware team and their bounty program\n"));
1317 	fCreditsView->Insert(
1318 		B_TRANSLATE("The BeGeistert team\n"));
1319 	fCreditsView->Insert(
1320 		B_TRANSLATE("Google and their Google Summer of Code and Google Code In "
1321 			"programs\n"));
1322 	fCreditsView->Insert(
1323 		B_TRANSLATE("The University of Auckland and Christof Lutteroth\n\n"));
1324 	fCreditsView->Insert(
1325 		B_TRANSLATE(B_UTF8_ELLIPSIS "and the many people making donations!\n\n"));
1326 
1327 	// copyrights for various projects we use
1328 
1329 	BPath mitPath;
1330 	_GetLicensePath("MIT", mitPath);
1331 	BPath lgplPath;
1332 	_GetLicensePath("GNU LGPL v2.1", lgplPath);
1333 
1334 	font.SetSize(be_bold_font->Size() + 4);
1335 	font.SetFace(B_BOLD_FACE);
1336 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
1337 	fCreditsView->Insert(B_TRANSLATE("\nCopyrights\n\n"));
1338 
1339 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1340 	fCreditsView->Insert(B_TRANSLATE("[Click a license name to read the "
1341 		"respective license.]\n\n"));
1342 
1343 	// Haiku license
1344 	BString haikuLicense = B_TRANSLATE_COMMENT("The code that is unique to "
1345 		"Haiku, especially the kernel and all code that applications may link "
1346 		"against, is distributed under the terms of the <MIT license>. "
1347 		"Some system libraries contain third party code distributed under the "
1348 		"<LGPL license>. You can find the copyrights to third party code below."
1349 		"\n\n", "<MIT license> and <LGPL license> aren't variables and can be "
1350 		"translated. However, please, don't remove < and > as they're needed "
1351 		"as placeholders for proper hypertext functionality.");
1352 	int32 licensePart1 = haikuLicense.FindFirst("<");
1353 	int32 licensePart2 = haikuLicense.FindFirst(">");
1354 	int32 licensePart3 = haikuLicense.FindLast("<");
1355 	int32 licensePart4 = haikuLicense.FindLast(">");
1356 	BString part;
1357 	haikuLicense.CopyInto(part, 0, licensePart1);
1358 	fCreditsView->Insert(part);
1359 
1360 	part.Truncate(0);
1361 	haikuLicense.CopyInto(part, licensePart1 + 1, licensePart2 - 1
1362 		- licensePart1);
1363 	fCreditsView->InsertHyperText(part, new OpenFileAction(mitPath.Path()));
1364 
1365 	part.Truncate(0);
1366 	haikuLicense.CopyInto(part, licensePart2 + 1, licensePart3 - 1
1367 		- licensePart2);
1368 	fCreditsView->Insert(part);
1369 
1370 	part.Truncate(0);
1371 	haikuLicense.CopyInto(part, licensePart3 + 1, licensePart4 - 1
1372 		- licensePart3);
1373 	fCreditsView->InsertHyperText(part, new OpenFileAction(lgplPath.Path()));
1374 
1375 	part.Truncate(0);
1376 	haikuLicense.CopyInto(part, licensePart4 + 1, haikuLicense.Length() - 1
1377 		- licensePart4);
1378 	fCreditsView->Insert(part);
1379 
1380 	// GNU copyrights
1381 	AddCopyrightEntry("The GNU Project",
1382 		B_TRANSLATE("Contains software from the GNU Project, "
1383 		"released under the GPL and LGPL licenses:\n"
1384 		"GNU C Library, "
1385 		"GNU coretools, diffutils, findutils, "
1386 		"sharutils, gawk, bison, m4, make, "
1387 		"gdb, wget, ncurses, termcap, "
1388 		"Bourne Again Shell.\n"
1389 		COPYRIGHT_STRING "The Free Software Foundation."),
1390 		StringVector(kLGPLv21, kGPLv2, kGPLv3, NULL),
1391 		StringVector(),
1392 		"http://www.gnu.org");
1393 
1394 	// FreeBSD copyrights
1395 	AddCopyrightEntry("The FreeBSD Project",
1396 		B_TRANSLATE("Contains software from the FreeBSD Project, "
1397 		"released under the BSD license:\n"
1398 		"cal, ftpd, ping, telnet, "
1399 		"telnetd, traceroute\n"
1400 		COPYRIGHT_STRING "1994-2008 The FreeBSD Project. "
1401 		"All rights reserved."),
1402 		StringVector(kBSDTwoClause, kBSDThreeClause, kBSDFourClause,
1403 			NULL),
1404 		StringVector(),
1405 		"http://www.freebsd.org");
1406 
1407 	// NetBSD copyrights
1408 	AddCopyrightEntry("The NetBSD Project",
1409 		B_TRANSLATE("Contains software developed by the NetBSD "
1410 		"Foundation, Inc. and its contributors:\n"
1411 		"ftp, tput\n"
1412 		COPYRIGHT_STRING "1996-2008 The NetBSD Foundation, Inc. "
1413 		"All rights reserved."),
1414 		"http://www.netbsd.org");
1415 			// TODO: License!
1416 
1417 	// FFMpeg copyrights
1418 	_AddPackageCredit(PackageCredit("FFMpeg libavcodec")
1419 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2000-2007 Fabrice "
1420 			"Bellard, et al."))
1421 		.SetLicenses(kLGPLv21, kLGPLv2, NULL)
1422 		.SetURL("http://www.ffmpeg.org"));
1423 
1424 	// AGG copyrights
1425 	_AddPackageCredit(PackageCredit("AntiGrain Geometry")
1426 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2006 Maxim "
1427 			"Shemanarev (McSeem)."))
1428 		.SetLicenses("Anti-Grain Geometry", kBSDThreeClause, "GPC", NULL)
1429 		.SetURL("http://www.antigrain.com"));
1430 
1431 	// PDFLib copyrights
1432 	_AddPackageCredit(PackageCredit("PDFLib")
1433 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1997-2006 PDFlib GmbH and "
1434 			"Thomas Merz. All rights reserved.\n"
1435 			"PDFlib and PDFlib logo are registered trademarks of PDFlib GmbH."))
1436 		.SetLicense("PDFlib Lite")
1437 		.SetURL("http://www.pdflib.com"));
1438 
1439 	// FreeType copyrights
1440 	_AddPackageCredit(PackageCredit("FreeType2")
1441 		.SetCopyright(B_TRANSLATE("Portions of this software are under "
1442 			"copyright.\n"
1443 			COPYRIGHT_STRING "1996-2006 "
1444 			"The FreeType Project. All rights reserved."))
1445 		.SetLicense("FTL")
1446 		.SetURL("http://www.freetype.org"));
1447 
1448 	// Mesa3D (http://www.mesa3d.org) copyrights
1449 	_AddPackageCredit(PackageCredit("Mesa")
1450 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2006 Brian Paul. "
1451 			"Mesa3D Project. All rights reserved."))
1452 		.SetLicense("MIT")
1453 		.SetURL("http://www.mesa3d.org"));
1454 
1455 	// SGI's GLU implementation copyrights
1456 	_AddPackageCredit(PackageCredit("GLU")
1457 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1991-2000 "
1458 			"Silicon Graphics, Inc. All rights reserved."))
1459 		.SetLicense("SGI Free B")
1460 		.SetURL("http://www.sgi.com/products/software/opengl"));
1461 
1462 	// GLUT implementation copyrights
1463 	_AddPackageCredit(PackageCredit("GLUT")
1464 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1994-1997 Mark Kilgard. "
1465 			"All rights reserved."),
1466 			COPYRIGHT_STRING "1997 Be Inc.",
1467 			COPYRIGHT_STRING "1999 Jake Hamby.",
1468 			NULL)
1469 		.SetLicense("GLUT (Mark Kilgard)")
1470 		.SetURL("http://www.opengl.org/resources/libraries/glut"));
1471 
1472 	// OpenGroup & DEC (BRegion backend) copyright
1473 	_AddPackageCredit(PackageCredit("BRegion backend (XFree86)")
1474 		.SetCopyrights(COPYRIGHT_STRING "1987-1988, 1998 The Open Group.",
1475 			B_TRANSLATE(COPYRIGHT_STRING "1987-1988 Digital Equipment "
1476 			"Corporation, Maynard, Massachusetts.\n"
1477 			"All rights reserved."),
1478 			NULL)
1479 		.SetLicenses("OpenGroup", "DEC", NULL));
1480 			// TODO: URL
1481 
1482 	// VL-Gothic font
1483 	_AddPackageCredit(PackageCredit("VL-Gothic font")
1484 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1990-2003 Wada Laboratory,"
1485 			" the University of Tokyo."), COPYRIGHT_STRING
1486 			"2003-2004 Electronic Font Open Laboratory (/efont/).",
1487 			COPYRIGHT_STRING "2003-2012 M+ FONTS PROJECT.",
1488 			COPYRIGHT_STRING "2006-2012 Daisuke SUZUKI.",
1489 			COPYRIGHT_STRING "2006-2012 Project Vine.",
1490 			B_TRANSLATE("MIT license. All rights reserved."),
1491 			NULL)
1492 		.SetLicense(kBSDThreeClause)
1493 		.SetURL("http://vlgothic.dicey.org/"));
1494 
1495 	// expat copyrights
1496 	_AddPackageCredit(PackageCredit("expat")
1497 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1998-2000 Thai "
1498 			"Open Source Software Center Ltd and Clark Cooper."),
1499 			B_TRANSLATE(COPYRIGHT_STRING "2001-2003 Expat maintainers."),
1500 			NULL)
1501 		.SetLicense("Expat")
1502 		.SetURL("http://expat.sourceforge.net"));
1503 
1504 	// zlib copyrights
1505 	_AddPackageCredit(PackageCredit("zlib")
1506 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2004 Jean-loup "
1507 			"Gailly and Mark Adler."))
1508 		.SetLicense("Zlib")
1509 		.SetURL("http://www.zlib.net"));
1510 
1511 	// zip copyrights
1512 	_AddPackageCredit(PackageCredit("Info-ZIP")
1513 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1990-2002 Info-ZIP. "
1514 			"All rights reserved."))
1515 		.SetLicense("Info-ZIP")
1516 		.SetURL("http://www.info-zip.org"));
1517 
1518 	// bzip2 copyrights
1519 	_AddPackageCredit(PackageCredit("bzip2")
1520 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-2005 Julian R "
1521 			"Seward. All rights reserved."))
1522 		.SetLicense(kBSDFourClause)
1523 		.SetURL("http://bzip.org"));
1524 
1525 	// lp_solve copyrights
1526 	_AddPackageCredit(PackageCredit("lp_solve")
1527 		.SetCopyright(COPYRIGHT_STRING
1528 			"Michel Berkelaar, Kjell Eikland, Peter Notebaert")
1529 		.SetLicense(kLGPLv21)
1530 		.SetURL("http://lpsolve.sourceforge.net/"));
1531 
1532 	// OpenEXR copyrights
1533 	_AddPackageCredit(PackageCredit("OpenEXR")
1534 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2005 Industrial "
1535 			"Light & Magic, a division of Lucas Digital Ltd. LLC."))
1536 		.SetLicense(kBSDThreeClause)
1537 		.SetURL("http://www.openexr.com"));
1538 
1539 	// Bullet copyrights
1540 	_AddPackageCredit(PackageCredit("Bullet")
1541 		.SetCopyright(COPYRIGHT_STRING "2003-2008 Erwin Coumans")
1542 		.SetLicense("Bullet")
1543 		.SetURL("http://www.bulletphysics.com"));
1544 
1545 	// atftp copyrights
1546 	_AddPackageCredit(PackageCredit("atftp")
1547 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2000 Jean-Pierre "
1548 			"ervbefeL and Remi Lefebvre."))
1549 		.SetLicense(kGPLv2)
1550 		.SetURL("http://freecode.com/projects/atftp"));
1551 
1552 	// Netcat copyrights
1553 	_AddPackageCredit(PackageCredit("Netcat")
1554 		.SetCopyright(COPYRIGHT_STRING "1996 Hobbit.")
1555 		.SetLicense(kPublicDomain)
1556 		.SetURL("http://nc110.sourceforge.net/"));
1557 
1558 	// acpica copyrights
1559 	_AddPackageCredit(PackageCredit("acpica")
1560 		.SetCopyright(COPYRIGHT_STRING "1999-2006 Intel Corp.")
1561 		.SetLicense("Intel (ACPICA)")
1562 		.SetURL("http://www.acpica.org"));
1563 
1564 	// unrar copyrights
1565 	_AddPackageCredit(PackageCredit("unrar")
1566 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2008 Alexander "
1567 			"L. Roshal. All rights reserved."))
1568 		.SetLicense("UnRAR")
1569 		.SetURL("http://www.rarlab.com"));
1570 
1571 	// libpng copyrights
1572 	_AddPackageCredit(PackageCredit("libpng")
1573 		.SetCopyright(COPYRIGHT_STRING "2004, 2006-2008 Glenn "
1574 			"Randers-Pehrson.")
1575 		.SetLicense("LibPNG")
1576 		.SetURL("http://www.libpng.org"));
1577 
1578 	// libjpeg copyrights
1579 	_AddPackageCredit(PackageCredit("libjpeg")
1580 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1994-2009, Thomas G. "
1581 			"Lane, Guido Vollbeding. This software is based in part on the "
1582 			"work of the Independent JPEG Group."))
1583 		.SetLicense("LibJPEG")
1584 		.SetURL("http://www.ijg.org"));
1585 
1586 	// libprint copyrights
1587 	_AddPackageCredit(PackageCredit("libprint")
1588 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2000 Y.Takagi. "
1589 			"All rights reserved.")));
1590 			// TODO: License!
1591 
1592 	// cortex copyrights
1593 	_AddPackageCredit(PackageCredit("Cortex")
1594 		.SetCopyright(COPYRIGHT_STRING "1999-2000 Eric Moon.")
1595 		.SetLicense(kBSDThreeClause)
1596 		.SetURL("http://cortex.sourceforge.net/documentation"));
1597 
1598 	// FluidSynth copyrights
1599 	_AddPackageCredit(PackageCredit("FluidSynth")
1600 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003 Peter Hanappe "
1601 			"and others."))
1602 		.SetLicense(kLGPLv2)
1603 		.SetURL("http://www.fluidsynth.org"));
1604 
1605 	// CannaIM copyrights
1606 	_AddPackageCredit(PackageCredit("CannaIM")
1607 		.SetCopyright(COPYRIGHT_STRING "1999 Masao Kawamura.")
1608 		.SetLicense("MIT"));
1609 
1610 	// libxml2, libxslt, libexslt copyrights
1611 	_AddPackageCredit(PackageCredit("libxml2, libxslt")
1612 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1998-2003 Daniel Veillard. "
1613 			"All rights reserved."))
1614 		.SetLicense(kMITNoPromotion)
1615 		.SetURL("http://xmlsoft.org"));
1616 
1617 	_AddPackageCredit(PackageCredit("libexslt")
1618 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2001-2002 Thomas Broyer, "
1619 			"Charlie Bozeman and Daniel Veillard. All rights reserved."))
1620 		.SetLicense(kMITNoPromotion)
1621 		.SetURL("http://xmlsoft.org"));
1622 
1623 	// Xiph.org Foundation copyrights
1624 	_AddPackageCredit(PackageCredit("Xiph.org Foundation")
1625 		.SetCopyrights("libvorbis, libogg, libtheora, libspeex",
1626 			B_TRANSLATE(COPYRIGHT_STRING "1994-2008 Xiph.Org. "
1627 			"All rights reserved."), NULL)
1628 		.SetLicense(kBSDThreeClause)
1629 		.SetURL("http://www.xiph.org"));
1630 
1631 	// The Tcpdump Group
1632 	_AddPackageCredit(PackageCredit("The Tcpdump Group")
1633 		.SetCopyright("tcpdump, libpcap")
1634 		.SetLicense(kBSDThreeClause)
1635 		.SetURL("http://www.tcpdump.org"));
1636 
1637 	// Matroska
1638 	_AddPackageCredit(PackageCredit("libmatroska")
1639 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2003 Steve Lhomme. "
1640 			"All rights reserved."))
1641 		.SetLicense(kLGPLv21)
1642 		.SetURL("http://www.matroska.org"));
1643 
1644 	// BColorQuantizer (originally CQuantizer code)
1645 	_AddPackageCredit(PackageCredit("CQuantizer")
1646 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-1997 Jeff Prosise. "
1647 			"All rights reserved."))
1648 		.SetLicense("CQuantizer")
1649 		.SetURL("http://www.xdp.it"));
1650 
1651 	// MAPM (Mike's Arbitrary Precision Math Library) used by DeskCalc
1652 	_AddPackageCredit(PackageCredit("MAPM")
1653 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2007 Michael C. "
1654 			"Ring. All rights reserved."))
1655 		.SetLicense("MAPM")
1656 		.SetURL("http://tc.umn.edu/~ringx004"));
1657 
1658 	// MkDepend 1.7 copyright (Makefile dependency generator)
1659 	_AddPackageCredit(PackageCredit("MkDepend")
1660 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2001 Lars Düning. "
1661 			"All rights reserved."))
1662 		.SetLicense("MkDepend")
1663 		.SetURL("http://bearnip.com/lars/be"));
1664 
1665 	// libhttpd copyright (used as Poorman backend)
1666 	_AddPackageCredit(PackageCredit("libhttpd")
1667 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995, 1998-2001 "
1668 			"Jef Poskanzer. All rights reserved."))
1669 		.SetLicense("LibHTTPd")
1670 		.SetURL("http://www.acme.com/software/thttpd/"));
1671 
1672 #ifdef __INTEL__
1673 	// Udis86 copyrights
1674 	_AddPackageCredit(PackageCredit("Udis86")
1675 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2004 "
1676 			"Vivek Mohan. All rights reserved."))
1677 		.SetLicense(kBSDTwoClause)
1678 		.SetURL("http://udis86.sourceforge.net"));
1679 #endif
1680 
1681 #ifdef __INTEL__
1682 	// Intel PRO/Wireless 2100 Firmware
1683 	_AddPackageCredit(PackageCredit("Intel PRO/Wireless 2100 Firmware")
1684 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003-2006 "
1685 			"Intel Corporation. All rights reserved."))
1686 		.SetLicense(kIntel2xxxFirmware)
1687 		.SetURL("http://ipw2100.sourceforge.net/"));
1688 #endif
1689 
1690 #ifdef __INTEL__
1691 	// Intel PRO/Wireless 2200BG Firmware
1692 	_AddPackageCredit(PackageCredit("Intel PRO/Wireless 2200BG Firmware")
1693 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2004-2005 "
1694 			"Intel Corporation. All rights reserved."))
1695 		.SetLicense(kIntel2xxxFirmware)
1696 		.SetURL("http://ipw2200.sourceforge.net/"));
1697 #endif
1698 
1699 #ifdef __INTEL__
1700 	// Intel PRO/Wireless 3945ABG/BG Network Connection Adapter Firmware
1701 	_AddPackageCredit(
1702 		PackageCredit(
1703 			"Intel PRO/Wireless 3945ABG/BG Network Connection Adapter Firmware")
1704 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2007 "
1705 			"Intel Corporation. All rights reserved."))
1706 		.SetLicense(kIntelFirmware)
1707 		.SetURL("http://www.intellinuxwireless.org/"));
1708 #endif
1709 #ifdef __INTEL__
1710 	// Intel Wireless WiFi Link 4965AGN Adapter Firmware
1711 	_AddPackageCredit(
1712 		PackageCredit("Intel Wireless WiFi Link 4965AGN Adapter Firmware")
1713 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2007 "
1714 			"Intel Corporation. All rights reserved."))
1715 		.SetLicense(kIntelFirmware)
1716 		.SetURL("http://www.intellinuxwireless.org/"));
1717 #endif
1718 
1719 #ifdef __INTEL__
1720 	// Marvell 88w8363
1721 	_AddPackageCredit(PackageCredit("Marvell 88w8363")
1722 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007-2009 "
1723 			"Marvell Semiconductor, Inc. All rights reserved."))
1724 		.SetLicense(kMarvellFirmware)
1725 		.SetURL("http://www.marvell.com/"));
1726 #endif
1727 
1728 #ifdef __INTEL__
1729 	// Ralink Firmware RT2501/RT2561/RT2661
1730 	_AddPackageCredit(PackageCredit("Ralink Firmware RT2501/RT2561/RT2661")
1731 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007 "
1732 			"Ralink Technology Corporation. All rights reserved."))
1733 		.SetLicense(kRalinkFirmware)
1734 		.SetURL("http://www.ralinktech.com/"));
1735 #endif
1736 
1737 	// Gutenprint
1738 	_AddPackageCredit(PackageCredit("Gutenprint")
1739 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
1740 			"1999-2010 by the authors of Gutenprint. All rights reserved."))
1741 		.SetLicense(kGPLv2)
1742 		.SetURL("http://gutenprint.sourceforge.net/"));
1743 
1744 	// libwebp
1745 	_AddPackageCredit(PackageCredit("libwebp")
1746 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
1747 			"2010-2011 Google Inc. All rights reserved."))
1748 		.SetLicense(kBSDThreeClause)
1749 		.SetURL("http://www.webmproject.org/code/#libwebp_webp_image_library"));
1750 
1751 	// GTF
1752 	_AddPackageCredit(PackageCredit("GTF")
1753 		.SetCopyright(B_TRANSLATE("2001 by Andy Ritger based on the "
1754 			"Generalized Timing Formula"))
1755 		.SetLicense(kBSDThreeClause)
1756 		.SetURL("http://gtf.sourceforge.net/"));
1757 
1758 	// libqrencode
1759 	_AddPackageCredit(PackageCredit("libqrencode")
1760 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2012 Kentaro Fukuchi"))
1761 		.SetLicense(kLGPLv21)
1762 		.SetURL("http://fukuchi.org/works/qrencode/"));
1763 
1764 	_AddCopyrightsFromAttribute();
1765 	_AddPackageCreditEntries();
1766 
1767 	return new CropView(creditsScroller, 0, 1, 1, 1);
1768 }
1769 
1770 
1771 status_t
1772 AboutView::_GetLicensePath(const char* license, BPath& path)
1773 {
1774 	BPathFinder pathFinder;
1775 	BStringList paths;
1776 	struct stat st;
1777 
1778 	status_t error = pathFinder.FindPaths(B_FIND_PATH_DATA_DIRECTORY,
1779 		"licenses", paths);
1780 
1781 	for (int i = 0; i < paths.CountStrings(); ++i) {
1782 		if (error == B_OK && path.SetTo(paths.StringAt(i)) == B_OK
1783 			&& path.Append(license) == B_OK
1784 			&& lstat(path.Path(), &st) == 0) {
1785 			return B_OK;
1786 		}
1787 	}
1788 
1789 	path.Unset();
1790 	return B_ENTRY_NOT_FOUND;
1791 }
1792 
1793 
1794 void
1795 AboutView::_AddCopyrightsFromAttribute()
1796 {
1797 #ifdef __HAIKU__
1798 	// open the app executable file
1799 	char appPath[B_PATH_NAME_LENGTH];
1800 	int appFD;
1801 	if (BPrivate::get_app_path(appPath) != B_OK
1802 		|| (appFD = open(appPath, O_RDONLY)) < 0) {
1803 		return;
1804 	}
1805 
1806 	// open the attribute
1807 	int attrFD = fs_fopen_attr(appFD, "COPYRIGHTS", B_STRING_TYPE, O_RDONLY);
1808 	close(appFD);
1809 	if (attrFD < 0)
1810 		return;
1811 
1812 	// attach it to a FILE
1813 	FILE* attrFile = fdopen(attrFD, "r");
1814 	if (attrFile == NULL) {
1815 		close(attrFD);
1816 		return;
1817 	}
1818 	CObjectDeleter<FILE, int> _(attrFile, fclose);
1819 
1820 	// read and parse the copyrights
1821 	BMessage package;
1822 	BString fieldName;
1823 	BString fieldValue;
1824 	char lineBuffer[LINE_MAX];
1825 	while (char* line = fgets(lineBuffer, sizeof(lineBuffer), attrFile)) {
1826 		// chop off line break
1827 		size_t lineLen = strlen(line);
1828 		if (lineLen > 0 && line[lineLen - 1] == '\n')
1829 			line[--lineLen] = '\0';
1830 
1831 		// flush previous field, if a new field begins, otherwise append
1832 		if (lineLen == 0 || !isspace(line[0])) {
1833 			// new field -- flush the previous one
1834 			if (fieldName.Length() > 0) {
1835 				fieldValue = trim_string(fieldValue.String(),
1836 					fieldValue.Length());
1837 				package.AddString(fieldName.String(), fieldValue);
1838 				fieldName = "";
1839 			}
1840 		} else if (fieldName.Length() > 0) {
1841 			// append to current field
1842 			fieldValue += line;
1843 			continue;
1844 		} else {
1845 			// bogus line -- ignore
1846 			continue;
1847 		}
1848 
1849 		if (lineLen == 0)
1850 			continue;
1851 
1852 		// parse new field
1853 		char* colon = strchr(line, ':');
1854 		if (colon == NULL) {
1855 			// bogus line -- ignore
1856 			continue;
1857 		}
1858 
1859 		fieldName.SetTo(line, colon - line);
1860 		fieldName = trim_string(line, colon - line);
1861 		if (fieldName.Length() == 0) {
1862 			// invalid field name
1863 			continue;
1864 		}
1865 
1866 		fieldValue = colon + 1;
1867 
1868 		if (fieldName == "Package") {
1869 			// flush the current package
1870 			_AddPackageCredit(PackageCredit(package));
1871 			package.MakeEmpty();
1872 		}
1873 	}
1874 
1875 	// flush current package
1876 	_AddPackageCredit(PackageCredit(package));
1877 #endif
1878 }
1879 
1880 
1881 void
1882 AboutView::_AddPackageCreditEntries()
1883 {
1884 	// sort the packages case-insensitively
1885 	PackageCredit* packages[fPackageCredits.size()];
1886 	int32 count = 0;
1887 	for (PackageCreditMap::iterator it = fPackageCredits.begin();
1888 			it != fPackageCredits.end(); ++it) {
1889 		packages[count++] = it->second;
1890 	}
1891 
1892 	if (count > 1) {
1893 		std::sort(packages, packages + count,
1894 			&PackageCredit::NameLessInsensitive);
1895 	}
1896 
1897 	// add the credits
1898 	for (int32 i = 0; i < count; i++) {
1899 		PackageCredit* package = packages[i];
1900 
1901 		BString text(package->CopyrightAt(0));
1902 		int32 count = package->CountCopyrights();
1903 		for (int32 i = 1; i < count; i++)
1904 			text << "\n" << package->CopyrightAt(i);
1905 
1906 		AddCopyrightEntry(package->PackageName(), text.String(),
1907 			package->Licenses(), package->Sources(), package->URL());
1908 	}
1909 }
1910 
1911 
1912 void
1913 AboutView::_AddPackageCredit(const PackageCredit& package)
1914 {
1915 	if (!package.IsValid())
1916 		return;
1917 
1918 	PackageCreditMap::iterator it = fPackageCredits.find(package.PackageName());
1919 	if (it != fPackageCredits.end()) {
1920 		// If the new package credit isn't "better" than the old one, ignore it.
1921 		PackageCredit* oldPackage = it->second;
1922 		if (!package.IsBetterThan(*oldPackage))
1923 			return;
1924 
1925 		// replace the old credit
1926 		fPackageCredits.erase(it);
1927 		delete oldPackage;
1928 	}
1929 
1930 	fPackageCredits[package.PackageName()] = new PackageCredit(package);
1931 }
1932 
1933 
1934 //	#pragma mark -
1935 
1936 
1937 static const char*
1938 MemSizeToString(char string[], size_t size, system_info* info)
1939 {
1940 	int inaccessibleMemory = int(info->ignored_pages
1941 		* (B_PAGE_SIZE / 1048576.0f) + 0.5f);
1942 	if (inaccessibleMemory > 0) {
1943 		BString message(B_TRANSLATE("%total MiB total, %inaccessible MiB "
1944 			"inaccessible"));
1945 
1946 		snprintf(string, size, "%d", int((info->max_pages
1947 			+ info->ignored_pages) * (B_PAGE_SIZE / 1048576.0f) + 0.5f));
1948 		message.ReplaceFirst("%total", string);
1949 
1950 		snprintf(string, size, "%d", inaccessibleMemory);
1951 		message.ReplaceFirst("%inaccessible", string);
1952 		strncpy(string, message.String(), size);
1953 	} else {
1954 		snprintf(string, size, B_TRANSLATE("%d MiB total"),
1955 			int(info->max_pages * (B_PAGE_SIZE / 1048576.0f) + 0.5f));
1956 	}
1957 
1958 	return string;
1959 }
1960 
1961 
1962 static const char*
1963 MemUsageToString(char string[], size_t size, system_info* info)
1964 {
1965 	snprintf(string, size, B_TRANSLATE("%d MiB used (%d%%)"),
1966 		int(info->used_pages * (B_PAGE_SIZE / 1048576.0f) + 0.5f),
1967 		int(100 * info->used_pages / info->max_pages));
1968 
1969 	return string;
1970 }
1971 
1972 
1973 static const char*
1974 UptimeToString(char string[], size_t size)
1975 {
1976 	BDurationFormat formatter;
1977 	BString str;
1978 
1979 	bigtime_t uptime = system_time();
1980 	bigtime_t now = (bigtime_t)time(NULL) * 1000000;
1981 	formatter.Format(now - uptime, now, &str);
1982 	str.CopyInto(string, 0, size);
1983 	string[std::min((size_t)str.Length(), size)] = '\0';
1984 
1985 	return string;
1986 }
1987 
1988 
1989 int
1990 main()
1991 {
1992 	AboutApp app;
1993 	app.Run();
1994 	return 0;
1995 }
1996 
1997