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