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