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