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