xref: /haiku/src/apps/aboutsystem/AboutSystem.cpp (revision 893988af824e65e49e55f517b157db8386e8002b)
1 /*
2  * Copyright (c) 2005-2009, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		René Gollent
8  */
9 
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <sys/utsname.h>
13 #include <time.h>
14 #include <unistd.h>
15 
16 #include <map>
17 #include <string>
18 
19 #include <AppFileInfo.h>
20 #include <Application.h>
21 #include <Bitmap.h>
22 #include <File.h>
23 #include <FindDirectory.h>
24 #include <Font.h>
25 #include <fs_attr.h>
26 #include <LayoutBuilder.h>
27 #include <MessageRunner.h>
28 #include <Messenger.h>
29 #include <OS.h>
30 #include <Path.h>
31 #include <Resources.h>
32 #include <Screen.h>
33 #include <ScrollView.h>
34 #include <String.h>
35 #include <StringView.h>
36 #include <TranslationUtils.h>
37 #include <TranslatorFormats.h>
38 #include <View.h>
39 #include <Volume.h>
40 #include <VolumeRoster.h>
41 #include <Window.h>
42 
43 #include <AppMisc.h>
44 #include <AutoDeleter.h>
45 #include <cpu_type.h>
46 
47 #include "HyperTextActions.h"
48 #include "HyperTextView.h"
49 #include "Utilities.h"
50 
51 
52 #ifndef LINE_MAX
53 #define LINE_MAX 2048
54 #endif
55 
56 #define SCROLL_CREDITS_VIEW 'mviv'
57 
58 
59 static const char *UptimeToString(char string[], size_t size);
60 static const char *MemUsageToString(char string[], size_t size,
61 	system_info *info);
62 
63 static const rgb_color kDarkGrey = { 100, 100, 100, 255 };
64 static const rgb_color kHaikuGreen = { 42, 131, 36, 255 };
65 static const rgb_color kHaikuOrange = { 255, 69, 0, 255 };
66 static const rgb_color kHaikuYellow = { 255, 176, 0, 255 };
67 static const rgb_color kLinkBlue = { 80, 80, 200, 255 };
68 
69 
70 class AboutApp : public BApplication {
71 public:
72 								AboutApp();
73 };
74 
75 class AboutWindow : public BWindow {
76 public:
77 							AboutWindow();
78 
79 	virtual	bool			QuitRequested();
80 };
81 
82 class LogoView : public BView {
83 public:
84 							LogoView();
85 	virtual					~LogoView();
86 
87 	virtual	BSize			MinSize();
88 	virtual	BSize			MaxSize();
89 
90 	virtual void			Draw(BRect updateRect);
91 
92 private:
93 			BBitmap*		fLogo;
94 };
95 
96 class CropView : public BView {
97 public:
98 							CropView(BView* target, int32 left, int32 top,
99 								int32 right, int32 bottom);
100 	virtual					~CropView();
101 
102 	virtual	BSize			MinSize();
103 	virtual	BSize			MaxSize();
104 
105 	virtual void			DoLayout();
106 
107 private:
108 			BView*			fTarget;
109 			int32			fCropLeft;
110 			int32			fCropTop;
111 			int32			fCropRight;
112 			int32			fCropBottom;
113 };
114 
115 class AboutView : public BView {
116 public:
117 							AboutView();
118 							~AboutView();
119 
120 	virtual void			AttachedToWindow();
121 	virtual void			Pulse();
122 
123 	virtual void			MessageReceived(BMessage* msg);
124 	virtual void			MouseDown(BPoint point);
125 
126 			void			AddCopyrightEntry(const char* name,
127 								const char* text,
128 								const StringVector& licenses,
129 								const char* url);
130 			void			AddCopyrightEntry(const char* name,
131 								const char* text, const char* url = NULL);
132 			void			PickRandomHaiku();
133 
134 
135 private:
136 	typedef std::map<std::string, PackageCredit*> PackageCreditMap;
137 
138 private:
139 			BView*			_CreateLabel(const char* name, const char* label);
140 			BView*			_CreateCreditsView();
141 			status_t		_GetLicensePath(const char* license,
142 								BPath& path);
143 			void			_AddCopyrightsFromAttribute();
144 			void			_AddPackageCredit(const PackageCredit& package);
145 			void			_AddPackageCreditEntries();
146 
147 			BStringView*	fMemView;
148 			BTextView*		fUptimeView;
149 			BView*			fInfoView;
150 			HyperTextView*	fCreditsView;
151 
152 			BBitmap*		fLogo;
153 
154 			bigtime_t		fLastActionTime;
155 			BMessageRunner*	fScrollRunner;
156 			PackageCreditMap fPackageCredits;
157 };
158 
159 
160 //	#pragma mark -
161 
162 
163 AboutApp::AboutApp()
164 	: BApplication("application/x-vnd.Haiku-About")
165 {
166 	AboutWindow* window = new AboutWindow();
167 	window->Show();
168 }
169 
170 
171 //	#pragma mark -
172 
173 
174 AboutWindow::AboutWindow()
175 	: BWindow(BRect(0, 0, 500, 300), "About This System", B_TITLED_WINDOW,
176 			B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE)
177 {
178 	SetLayout(new BGroupLayout(B_VERTICAL));
179 	AddChild(new AboutView());
180 
181 	// Make sure we take the minimal window size into account when centering
182 	BSize size = GetLayout()->MinSize();
183 	ResizeTo(max_c(size.width, Bounds().Width()),
184 		max_c(size.height, Bounds().Height()));
185 
186 	MoveTo((BScreen().Frame().Width() - Bounds().Width()) / 2,
187 		(BScreen().Frame().Height() - Bounds().Height()) / 2 );
188 }
189 
190 
191 bool
192 AboutWindow::QuitRequested()
193 {
194 	be_app->PostMessage(B_QUIT_REQUESTED);
195 	return true;
196 }
197 
198 
199 //	#pragma mark - LogoView
200 
201 
202 LogoView::LogoView()
203 	: BView("logo", B_WILL_DRAW)
204 {
205 	fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "haikulogo.png");
206 	SetViewColor(255, 255, 255);
207 }
208 
209 
210 LogoView::~LogoView()
211 {
212 	delete fLogo;
213 }
214 
215 
216 BSize
217 LogoView::MinSize()
218 {
219 	if (fLogo == NULL)
220 		return BSize(0, 0);
221 
222 	return BSize(fLogo->Bounds().Width(), fLogo->Bounds().Height());
223 }
224 
225 
226 BSize
227 LogoView::MaxSize()
228 {
229 	if (fLogo == NULL)
230 		return BSize(0, 0);
231 
232 	return BSize(B_SIZE_UNLIMITED, fLogo->Bounds().Height());
233 }
234 
235 
236 void
237 LogoView::Draw(BRect updateRect)
238 {
239 	if (fLogo != NULL) {
240 		DrawBitmap(fLogo,
241 			BPoint((Bounds().Width() - fLogo->Bounds().Width()) / 2, 0));
242 	}
243 }
244 
245 
246 //	#pragma mark - CropView
247 
248 
249 CropView::CropView(BView* target, int32 left, int32 top, int32 right,
250 		int32 bottom)
251 	: BView("crop view", 0),
252 	fTarget(target),
253 	fCropLeft(left),
254 	fCropTop(top),
255 	fCropRight(right),
256 	fCropBottom(bottom)
257 {
258 	AddChild(target);
259 }
260 
261 
262 CropView::~CropView()
263 {
264 }
265 
266 
267 BSize
268 CropView::MinSize()
269 {
270 	if (fTarget == NULL)
271 		return BSize();
272 
273 	BSize size = fTarget->MinSize();
274 	if (size.width != B_SIZE_UNSET)
275 		size.width -= fCropLeft + fCropRight;
276 	if (size.height != B_SIZE_UNSET)
277 		size.height -= fCropTop + fCropBottom;
278 
279 	return size;
280 }
281 
282 
283 BSize
284 CropView::MaxSize()
285 {
286 	if (fTarget == NULL)
287 		return BSize();
288 
289 	BSize size = fTarget->MaxSize();
290 	if (size.width != B_SIZE_UNSET)
291 		size.width -= fCropLeft + fCropRight;
292 	if (size.height != B_SIZE_UNSET)
293 		size.height -= fCropTop + fCropBottom;
294 
295 	return size;
296 }
297 
298 
299 void
300 CropView::DoLayout()
301 {
302 	BView::DoLayout();
303 
304 	if (fTarget == NULL)
305 		return;
306 
307 	fTarget->MoveTo(-fCropLeft, -fCropTop);
308 	fTarget->ResizeTo(Bounds().Width() + fCropLeft + fCropRight,
309 		Bounds().Height() + fCropTop + fCropBottom);
310 }
311 
312 
313 //	#pragma mark - AboutView
314 
315 
316 AboutView::AboutView()
317 	: BView("aboutview", B_WILL_DRAW | B_PULSE_NEEDED),
318 	fLastActionTime(system_time()),
319 	fScrollRunner(NULL)
320 {
321 	// Begin Construction of System Information controls
322 
323 	system_info systemInfo;
324 	get_system_info(&systemInfo);
325 
326 	// Create all the various labels for system infomation
327 
328 	// OS Version
329 
330 	char string[1024];
331 	strcpy(string, "Unknown");
332 
333 	// the version is stored in the BEOS:APP_VERSION attribute of libbe.so
334 	BPath path;
335 	if (find_directory(B_BEOS_LIB_DIRECTORY, &path) == B_OK) {
336 		path.Append("libbe.so");
337 
338 		BAppFileInfo appFileInfo;
339 		version_info versionInfo;
340 		BFile file;
341 		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
342 			&& appFileInfo.SetTo(&file) == B_OK
343 			&& appFileInfo.GetVersionInfo(&versionInfo,
344 				B_APP_VERSION_KIND) == B_OK
345 			&& versionInfo.short_info[0] != '\0')
346 			strcpy(string, versionInfo.short_info);
347 	}
348 
349 	// Add revision from uname() info
350 	utsname unameInfo;
351 	if (uname(&unameInfo) == 0) {
352 		long revision;
353 		if (sscanf(unameInfo.version, "r%ld", &revision) == 1) {
354 			char version[16];
355 			snprintf(version, sizeof(version), "%ld", revision);
356 			strlcat(string, " (Revision ", sizeof(string));
357 			strlcat(string, version, sizeof(string));
358 			strlcat(string, ")", sizeof(string));
359 		}
360 	}
361 
362 	BStringView* versionView = new BStringView("ostext", string);
363 	versionView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
364 		B_ALIGN_VERTICAL_UNSET));
365 
366 	// GCC version
367 #if __GNUC__ != 2
368 	snprintf(string, sizeof(string), "GCC %d", __GNUC__);
369 
370 	BStringView* gccView = new BStringView("gcctext", string);
371 	gccView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
372 		B_ALIGN_VERTICAL_UNSET));
373 #endif
374 
375 	// CPU count, type and clock speed
376 	char processorLabel[256];
377 	if (systemInfo.cpu_count > 1) {
378 		snprintf(processorLabel, sizeof(processorLabel), "%ld Processors:",
379 			systemInfo.cpu_count);
380 	} else
381 		strlcpy(processorLabel, "Processor:", sizeof(processorLabel));
382 
383 	BString cpuType;
384 	cpuType << get_cpu_vendor_string(systemInfo.cpu_type)
385 		<< " " << get_cpu_model_string(&systemInfo);
386 
387 	BStringView* cpuView = new BStringView("cputext", cpuType.String());
388 	cpuView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
389 		B_ALIGN_VERTICAL_UNSET));
390 
391 	int32 clockSpeed = get_rounded_cpu_speed();
392 	if (clockSpeed < 1000)
393 		sprintf(string,"%ld MHz", clockSpeed);
394 	else
395 		sprintf(string,"%.2f GHz", clockSpeed / 1000.0f);
396 
397 	BStringView* frequencyView = new BStringView("frequencytext", string);
398 	frequencyView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
399 		B_ALIGN_VERTICAL_UNSET));
400 
401 	// RAM
402 	fMemView = new BStringView("ramtext",
403 		MemUsageToString(string, sizeof(string), &systemInfo));
404 	fMemView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
405 		B_ALIGN_VERTICAL_UNSET));
406 
407 	// Kernel build time/date
408 	snprintf(string, sizeof(string), "%s %s",
409 		systemInfo.kernel_build_date, systemInfo.kernel_build_time);
410 
411 	BStringView* kernelView = new BStringView("kerneltext", string);
412 	kernelView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
413 		B_ALIGN_VERTICAL_UNSET));
414 
415 	// Uptime
416 	fUptimeView = new BTextView("uptimetext");
417 	fUptimeView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
418 	fUptimeView->MakeEditable(false);
419 	fUptimeView->MakeSelectable(false);
420 	fUptimeView->SetWordWrap(true);
421 
422 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
423 
424 	const float offset = 5;
425 
426 	SetLayout(new BGroupLayout(B_HORIZONTAL));
427 
428 	BLayoutBuilder::Group<>((BGroupLayout*)GetLayout())
429 		.AddGroup(B_VERTICAL)
430 			.Add(new LogoView())
431 			.AddGroup(B_VERTICAL)
432 				.Add(_CreateLabel("oslabel", "Version:"))
433 				.Add(versionView)
434 #if __GNUC__ != 2
435 				.Add(gccView)
436 #endif
437 				.AddStrut(offset)
438 				.Add(_CreateLabel("cpulabel", processorLabel))
439 				.Add(cpuView)
440 				.Add(frequencyView)
441 				.AddStrut(offset)
442 				.Add(_CreateLabel("memlabel", "Memory:"))
443 				.Add(fMemView)
444 				.AddStrut(offset)
445 				.Add(_CreateLabel("kernellabel", "Kernel:"))
446 				.Add(kernelView)
447 				.AddStrut(offset)
448 				.Add(_CreateLabel("uptimelabel", "Time Running:"))
449 				.Add(fUptimeView)
450 				.SetInsets(5, 5, 5, 5)
451 			.End()
452 			// TODO: investigate: adding this causes the time to be cut
453 			//.AddGlue()
454 		.End()
455 		.Add(_CreateCreditsView());
456 
457 	float min = fMemView->MinSize().width * 1.1f;
458 	fCreditsView->SetExplicitMinSize(BSize(min, min));
459 }
460 
461 
462 AboutView::~AboutView()
463 {
464 	delete fScrollRunner;
465 }
466 
467 
468 void
469 AboutView::AttachedToWindow()
470 {
471 	BView::AttachedToWindow();
472 	Window()->SetPulseRate(500000);
473 	SetEventMask(B_POINTER_EVENTS);
474 }
475 
476 
477 void
478 AboutView::MouseDown(BPoint point)
479 {
480 	BRect r(92, 26, 105, 31);
481 	if (r.Contains(point)) {
482 		printf("Easter Egg\n");
483 		PickRandomHaiku();
484 	}
485 
486 	if (Bounds().Contains(point)) {
487 		fLastActionTime = system_time();
488 		delete fScrollRunner;
489 		fScrollRunner = NULL;
490 	}
491 }
492 
493 
494 void
495 AboutView::Pulse()
496 {
497 	char string[255];
498 	system_info info;
499 	get_system_info(&info);
500 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
501 	fMemView->SetText(MemUsageToString(string, sizeof(string), &info));
502 
503 	if (fScrollRunner == NULL && system_time() > fLastActionTime + 10000000) {
504 		BMessage message(SCROLL_CREDITS_VIEW);
505 		//fScrollRunner = new BMessageRunner(this, &message, 25000, -1);
506 	}
507 }
508 
509 
510 void
511 AboutView::MessageReceived(BMessage *msg)
512 {
513 	switch (msg->what) {
514 		case SCROLL_CREDITS_VIEW:
515 		{
516 			BScrollBar *scrollBar = fCreditsView->ScrollBar(B_VERTICAL);
517 			if (scrollBar == NULL)
518 				break;
519 			float max, min;
520 			scrollBar->GetRange(&min, &max);
521 			if (scrollBar->Value() < max)
522 				fCreditsView->ScrollBy(0, 1);
523 
524 			break;
525 		}
526 
527 		default:
528 			BView::MessageReceived(msg);
529 			break;
530 	}
531 }
532 
533 
534 void
535 AboutView::AddCopyrightEntry(const char *name, const char *text,
536 	const char *url)
537 {
538 	AddCopyrightEntry(name, text, StringVector(), url);
539 }
540 
541 
542 void
543 AboutView::AddCopyrightEntry(const char *name, const char *text,
544 	const StringVector& licenses, const char *url)
545 {
546 	BFont font(be_bold_font);
547 	//font.SetSize(be_bold_font->Size());
548 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
549 
550 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuYellow);
551 	fCreditsView->Insert(name);
552 	fCreditsView->Insert("\n");
553 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
554 	fCreditsView->Insert(text);
555 	fCreditsView->Insert("\n");
556 
557 	if (licenses.CountStrings() > 0) {
558 		if (licenses.CountStrings() > 1)
559 			fCreditsView->Insert("Licenses: ");
560 		else
561 			fCreditsView->Insert("License: ");
562 
563 		for (int32 i = 0; i < licenses.CountStrings(); i++) {
564 			const char* license = licenses.StringAt(i);
565 
566 			if (i > 0)
567 				fCreditsView->Insert(", ");
568 
569 			BPath licensePath;
570 			if (_GetLicensePath(license, licensePath) == B_OK) {
571 				fCreditsView->InsertHyperText(license,
572 					new OpenFileAction(licensePath.Path()));
573 			} else
574 				fCreditsView->Insert(license);
575 		}
576 
577 		fCreditsView->Insert("\n");
578 	}
579 
580 	if (url) {
581 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kLinkBlue);
582 		fCreditsView->InsertHyperText(url, new URLAction(url));
583 		fCreditsView->Insert("\n");
584 	}
585 	fCreditsView->Insert("\n");
586 }
587 
588 
589 void
590 AboutView::PickRandomHaiku()
591 {
592 	BFile fortunes(
593 #ifdef __HAIKU__
594 		"/etc/fortunes/Haiku",
595 #else
596 		"data/etc/fortunes/Haiku",
597 #endif
598 		B_READ_ONLY);
599 	struct stat st;
600 	if (fortunes.InitCheck() < B_OK)
601 		return;
602 	if (fortunes.GetStat(&st) < B_OK)
603 		return;
604 	char *buff = (char *)malloc((size_t)st.st_size + 1);
605 	if (!buff)
606 		return;
607 	buff[(size_t)st.st_size] = '\0';
608 	BList haikuList;
609 	if (fortunes.Read(buff, (size_t)st.st_size) == (ssize_t)st.st_size) {
610 		char *p = buff;
611 		while (p && *p) {
612 			char *e = strchr(p, '%');
613 			BString *s = new BString(p, e ? (e - p) : -1);
614 			haikuList.AddItem(s);
615 			p = e;
616 			if (p && (*p == '%'))
617 				p++;
618 			if (p && (*p == '\n'))
619 				p++;
620 		}
621 	}
622 	free(buff);
623 	if (haikuList.CountItems() < 1)
624 		return;
625 	BString *s = (BString *)haikuList.ItemAt(rand() % haikuList.CountItems());
626 	BFont font(be_bold_font);
627 	font.SetSize(be_bold_font->Size());
628 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
629 	fCreditsView->SelectAll();
630 	fCreditsView->Delete();
631 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kDarkGrey);
632 	fCreditsView->Insert(s->String());
633 	fCreditsView->Insert("\n");
634 	while ((s = (BString *)haikuList.RemoveItem((int32)0))) {
635 		delete s;
636 	}
637 }
638 
639 
640 BView*
641 AboutView::_CreateLabel(const char* name, const char* label)
642 {
643 	BStringView* labelView = new BStringView(name, label);
644 	labelView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
645 		B_ALIGN_VERTICAL_UNSET));
646 	labelView->SetFont(be_bold_font);
647 	return labelView;
648 }
649 
650 
651 BView*
652 AboutView::_CreateCreditsView()
653 {
654 	// Begin construction of the credits view
655 	fCreditsView = new HyperTextView("credits");
656 	fCreditsView->SetFlags(fCreditsView->Flags() | B_FRAME_EVENTS);
657 	fCreditsView->SetStylable(true);
658 	fCreditsView->MakeEditable(false);
659 	fCreditsView->SetWordWrap(true);
660 	fCreditsView->SetInsets(5, 5, 5, 5);
661 
662 	BScrollView* creditsScroller = new BScrollView("creditsScroller",
663 		fCreditsView, B_WILL_DRAW | B_FRAME_EVENTS, false, true,
664 		B_PLAIN_BORDER);
665 
666 	// Haiku copyright
667 	BFont font(be_bold_font);
668 	font.SetSize(font.Size() + 4);
669 
670 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
671 	fCreditsView->Insert("Haiku\n");
672 
673 	char string[1024];
674 	time_t time = ::time(NULL);
675 	struct tm* tm = localtime(&time);
676 	int32 year = tm->tm_year + 1900;
677 	if (year < 2008)
678 		year = 2008;
679 	snprintf(string, sizeof(string),
680 		COPYRIGHT_STRING "2001-%ld The Haiku project. ", year);
681 
682 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
683 	fCreditsView->Insert(string);
684 
685 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
686 	fCreditsView->Insert("The copyright to the Haiku code is property of "
687 		"Haiku, Inc. or of the respective authors where expressly noted "
688 		"in the source."
689 		"\n\n");
690 
691 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kLinkBlue);
692 	fCreditsView->InsertHyperText("http://www.haiku-os.org",
693 		new URLAction("http://www.haiku-os.org"));
694 	fCreditsView->Insert("\n\n");
695 
696 	font.SetSize(be_bold_font->Size());
697 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
698 
699 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
700 	fCreditsView->Insert("Current Maintainers:\n");
701 
702 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
703 	fCreditsView->Insert(
704 		"Ithamar R. Adema\n"
705 		"Bruno G. Albuquerque\n"
706 		"Stephan Aßmus\n"
707 		"Salvatore Benedetto\n"
708 		"Stefano Ceccherini\n"
709 		"Rudolf Cornelissen\n"
710 		"Alexandre Deckner\n"
711 		"Adrien Destugues\n"
712 		"Oliver Ruiz Dorantes\n"
713 		"Axel Dörfler\n"
714 		"Jérôme Duval\n"
715 		"René Gollent\n"
716 		"Bryce Groff\n"
717 		"Karsten Heimrich\n"
718 		"Philippe Houdoin\n"
719 		"Maurice Kalinowski\n"
720 		"Euan Kirkhope\n"
721 		"Ryan Leavengood\n"
722 		"Michael Lotz\n"
723 		"David McPaul\n"
724 		"Fredrik Modéen\n"
725 		"Marcus Overhagen\n"
726 		"Michael Pfeiffer\n"
727 		"François Revol\n"
728 		"Philippe Saint-Pierre\n"
729 		"Andrej Spielmann\n"
730 		"Jonas Sundström\n"
731 		"Oliver Tappe\n"
732 		"Gerasim Troeglazov\n"
733 		"Ingo Weinhold\n"
734 		"Artur Wyszynski\n"
735 		"Clemens Zeidler\n"
736 		"Siarzhuk Zharski\n"
737 		"\n");
738 
739 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
740 	fCreditsView->Insert("Past Maintainers:\n");
741 
742 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
743 	fCreditsView->Insert(
744 		"Andrew Bachmann\n"
745 		"Tyler Dauwalder\n"
746 		"Daniel Furrer\n"
747 		"Andre Alves Garzia\n"
748 		"Erik Jaesler\n"
749 		"Marcin Konicki\n"
750 		"Waldemar Kornewald\n"
751 		"Thomas Kurschel\n"
752 		"Frans Van Nispen\n"
753 		"Adi Oanca\n"
754 		"Michael Phipps\n"
755 		"Niels Sascha Reedijk\n"
756 		"David Reid\n"
757 		"Hugo Santos\n"
758 		"Alexander G. M. Smith\n"
759 		"Bryan Varner\n"
760 		"Nathan Whitehorn\n"
761 		"Michael Wilber\n"
762 		"Jonathan Yoder\n"
763 		"Gabe Yoder\n"
764 		"\n");
765 
766 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
767 	fCreditsView->Insert("Website, Marketing & Documentation:\n");
768 
769 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
770 	fCreditsView->Insert(
771 		"Phil Greenway\n"
772 		"Gavin James\n"
773 		"Matt Madia\n"
774 		"Jorge G. Mare (aka Koki)\n"
775 		"Urias McCullough\n"
776 		"Niels Sascha Reedijk\n"
777 		"Joachim Seemer (Humdinger)\n"
778 		"Jonathan Yoder\n"
779 		"\n");
780 
781 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
782 	fCreditsView->Insert("Contributors:\n");
783 
784 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
785 	fCreditsView->Insert(
786 		"Andrea Anzani\n"
787 		"Andre Braga\n"
788 		"Bruce Cameron\n"
789 		"Greg Crain\n"
790 		"David Dengg\n"
791 		"John Drinkwater\n"
792 		"Cian Duffy\n"
793 		"Mark Erben\n"
794 		"Christian Fasshauer\n"
795 		"Andreas Färber\n"
796 		"Marc Flerackers\n"
797 		"Michele Frau (zuMi)\n"
798 		"Matthijs Hollemans\n"
799 		"Mathew Hounsell\n"
800 		"Morgan Howe\n"
801 		"Ma Jie\n"
802 		"Carwyn Jones\n"
803 		"Vasilis Kaoutsis\n"
804 		"James Kim\n"
805 		"Shintaro Kinugawa\n"
806 		"Jan Klötzke\n"
807 		"Kurtis Kopf\n"
808 		"Tomáš Kučera\n"
809 		"Luboš Kulič\n"
810 		"Elad Lahav\n"
811 		"Anthony Lee\n"
812 		"Santiago Lema\n"
813 		"Raynald Lesieur\n"
814 		"Oscar Lesta\n"
815 		"Jerome Leveque\n"
816 		"Christof Lutteroth\n"
817 		"Graham MacDonald\n"
818 		"Brecht Machiels\n"
819 		"Jan Matějek\n"
820 		"Brian Matzon\n"
821 		"Christopher ML Zumwalt May\n"
822 		"Andrew McCall\n"
823 		"Scott McCreary\n"
824 		"Marius Middelthon\n"
825 		"Marco Minutoli\n"
826 		"Misza\n"
827 		"MrSiggler\n"
828 		"Alan Murta\n"
829 		"Raghuram Nagireddy\n"
830 		"Jeroen Oortwijn (idefix)\n"
831 		"Pahtz\n"
832 		"Michael Paine\n"
833 		"Adrian Panasiuk\n"
834 		"Francesco Piccinno\n"
835 		"David Powell\n"
836 		"Jeremy Rand\n"
837 		"Hartmut Reh\n"
838 		"Daniel Reinhold\n"
839 		"Chris Roberts\n"
840 		"Samuel Rodriguez Perez\n"
841 		"Thomas Roell\n"
842 		"Rafael Romo\n"
843 		"Ralf Schülke\n"
844 		"Reznikov Sergei\n"
845 		"Zousar Shaker\n"
846 		"Daniel Switkin\n"
847 		"Atsushi Takamatsu\n"
848 		"James Urquhart\n"
849 		"Jason Vandermark\n"
850 		"Sandor Vroemisse\n"
851 		"Denis Washington\n"
852 		"Ulrich Wimboeck\n"
853 		"Johannes Wischert\n"
854 		"James Woodcock\n"
855 		"Gerald Zajac\n"
856 		"Łukasz Zemczak\n"
857 		"JiSheng Zhang\n"
858 		"Zhao Shuai\n"
859 		"\n" B_UTF8_ELLIPSIS " and probably some more we forgot to mention "
860 		"(sorry!)"
861 		"\n\n");
862 
863 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
864 	fCreditsView->Insert("Special Thanks To:\n");
865 
866 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
867 	fCreditsView->Insert("Travis Geiselbrecht (and his NewOS kernel)\n");
868 	fCreditsView->Insert("Michael Phipps (project founder)\n\n");
869 	fCreditsView->Insert("The Haiku-Ports Team\n");
870 	fCreditsView->Insert("The Haikuware Team and their Bounty Program\n");
871 	fCreditsView->Insert("The BeGeistert Team\n\n");
872 	fCreditsView->Insert("... and the many community members making "
873 		"donations!\n\n");
874 
875 	// copyrights for various projects we use
876 
877 	BPath mitPath;
878 	_GetLicensePath("MIT", mitPath);
879 
880 	font.SetSize(be_bold_font->Size() + 4);
881 	font.SetFace(B_BOLD_FACE);
882 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
883 	fCreditsView->Insert("\nCopyrights\n\n");
884 
885 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
886 	fCreditsView->Insert("[Click a license name to read the respective "
887 		"license.]\n\n");
888 
889 	// Haiku license
890 	fCreditsView->Insert("The code that is unique to Haiku, especially the "
891 		"kernel and all code that applications may link against, is "
892 		"distributed under the terms of the ");
893 	fCreditsView->InsertHyperText("MIT license",
894 		new OpenFileAction(mitPath.Path()));
895 	fCreditsView->Insert(". Some system libraries contain third party code "
896 		"distributed under the LGPL license. You can find the copyrights "
897 		"to third party code below.\n\n");
898 
899 	// GNU copyrights
900 	AddCopyrightEntry("The GNU Project",
901 		"Contains software from the GNU Project, "
902 		"released under the GPL and LGPL licences:\n"
903 		"GNU C Library, "
904 		"GNU coretools, diffutils, findutils, "
905 		"sharutils, gawk, bison, m4, make, "
906 		"gdb, wget, ncurses, termcap, "
907 		"Bourne Again Shell.\n"
908 		COPYRIGHT_STRING "The Free Software Foundation.",
909 		StringVector("GNU LGPL v2.1", "GNU GPL v2", "GNU GPL v3", NULL),
910 		"http://www.gnu.org");
911 
912 	// FreeBSD copyrights
913 	AddCopyrightEntry("The FreeBSD Project",
914 		"Contains software from the FreeBSD Project, "
915 		"released under the BSD licence:\n"
916 		"cal, ftpd, ping, telnet, "
917 		"telnetd, traceroute\n"
918 		COPYRIGHT_STRING "1994-2008 The FreeBSD Project.  "
919 		"All rights reserved.",
920 		"http://www.freebsd.org");
921 			// TODO: License!
922 
923 	// NetBSD copyrights
924 	AddCopyrightEntry("The NetBSD Project",
925 		"Contains software developed by the NetBSD, "
926 		"Foundation, Inc. and its contributors:\n"
927 		"ftp, tput\n"
928 		COPYRIGHT_STRING "1996-2008 The NetBSD Foundation, Inc.  "
929 		"All rights reserved.",
930 		"http://www.netbsd.org");
931 			// TODO: License!
932 
933 	// FFMpeg copyrights
934 	_AddPackageCredit(PackageCredit("FFMpeg libavcodec")
935 		.SetCopyright(COPYRIGHT_STRING "2000-2007 Fabrice Bellard, et al.")
936 		.SetURL("http://www.ffmpeg.org"));
937 			// TODO: License!
938 
939 	// AGG copyrights
940 	_AddPackageCredit(PackageCredit("AntiGrain Geometry")
941 		.SetCopyright(COPYRIGHT_STRING "2002-2006 Maxim Shemanarev (McSeem).")
942 		.SetURL("http://www.antigrain.com"));
943 			// TODO: License!
944 
945 	// PDFLib copyrights
946 	_AddPackageCredit(PackageCredit("PDFLib")
947 		.SetCopyright(COPYRIGHT_STRING "1997-2006 PDFlib GmbH and Thomas Merz. "
948 			"All rights reserved.\n"
949 			"PDFlib and PDFlib logo are registered trademarks of PDFlib GmbH.")
950 		.SetURL("http://www.pdflib.com"));
951 			// TODO: License!
952 
953 	// FreeType copyrights
954 	_AddPackageCredit(PackageCredit("FreeType2")
955 		.SetCopyright("Portions of this software are copyright "
956 			B_UTF8_COPYRIGHT " 1996-2006 "
957 			"The FreeType Project.  All rights reserved.")
958 		.SetURL("http://www.freetype.org"));
959 			// TODO: License!
960 
961 	// Mesa3D (http://www.mesa3d.org) copyrights
962 	_AddPackageCredit(PackageCredit("Mesa")
963 		.SetCopyright(COPYRIGHT_STRING "1999-2006 Brian Paul. "
964 			"Mesa3D project.  All rights reserved.")
965 		.SetURL("http://www.mesa3d.org"));
966 			// TODO: License!
967 
968 	// SGI's GLU implementation copyrights
969 	_AddPackageCredit(PackageCredit("GLU")
970 		.SetCopyright(COPYRIGHT_STRING
971 			"1991-2000 Silicon Graphics, Inc. "
972 			"SGI's Software FreeB license.  All rights reserved."));
973 			// TODO: License!
974 
975 	// GLUT implementation copyrights
976 	_AddPackageCredit(PackageCredit("GLUT")
977 		.SetCopyrights(COPYRIGHT_STRING "1994-1997 Mark Kilgard. "
978 				"All rights reserved.",
979 			COPYRIGHT_STRING "1997 Be Inc.",
980 			COPYRIGHT_STRING "1999 Jake Hamby.",
981 			NULL));
982 			// TODO: License!
983 
984 	// OpenGroup & DEC (BRegion backend) copyright
985 	_AddPackageCredit(PackageCredit("BRegion backend (XFree86)")
986 		.SetCopyrights(COPYRIGHT_STRING "1987, 1988, 1998 The Open Group.",
987 			COPYRIGHT_STRING "1987, 1988 Digital Equipment "
988 				"Corporation, Maynard, Massachusetts.\n"
989 				"All rights reserved.",
990 			NULL));
991 			// TODO: License!
992 
993 	// Konatu font
994 	_AddPackageCredit(PackageCredit("Konatu font")
995 		.SetCopyright(COPYRIGHT_STRING "2002- MASUDA mitiya.\n"
996 			"MIT license. All rights reserved."));
997 			// TODO: License!
998 
999 	// expat copyrights
1000 	_AddPackageCredit(PackageCredit("expat")
1001 		.SetCopyrights(COPYRIGHT_STRING
1002 				"1998, 1999, 2000 Thai Open Source "
1003 				"Software Center Ltd and Clark Cooper.",
1004 			COPYRIGHT_STRING "2001, 2002, 2003 Expat maintainers.",
1005 			NULL));
1006 			// TODO: License!
1007 
1008 	// zlib copyrights
1009 	_AddPackageCredit(PackageCredit("zlib")
1010 		.SetCopyright(COPYRIGHT_STRING
1011 			"1995-2004 Jean-loup Gailly and Mark Adler."));
1012 			// TODO: License!
1013 
1014 	// zip copyrights
1015 	_AddPackageCredit(PackageCredit("Info-ZIP")
1016 		.SetCopyright(COPYRIGHT_STRING
1017 			"1990-2002 Info-ZIP. All rights reserved."));
1018 			// TODO: License!
1019 
1020 	// bzip2 copyrights
1021 	_AddPackageCredit(PackageCredit("bzip2")
1022 		.SetCopyright(COPYRIGHT_STRING
1023 			"1996-2005 Julian R Seward. All rights reserved."));
1024 			// TODO: License!
1025 
1026 	// VIM copyrights
1027 	_AddPackageCredit(PackageCredit("Vi IMproved")
1028 		.SetCopyright(COPYRIGHT_STRING "Bram Moolenaar et al."));
1029 			// TODO: License!
1030 
1031 	// lp_solve copyrights
1032 	_AddPackageCredit(PackageCredit("lp_solve")
1033 		.SetCopyright(COPYRIGHT_STRING
1034 			"Michel Berkelaar, Kjell Eikland, Peter Notebaert")
1035 		.SetLicense("GNU LGPL v2.1")
1036 		.SetURL("http://lpsolve.sourceforge.net/"));
1037 
1038 	// OpenEXR copyrights
1039 	_AddPackageCredit(PackageCredit("OpenEXR")
1040 		.SetCopyright(COPYRIGHT_STRING "2002-2005 Industrial Light & Magic, "
1041 			"a division of Lucas Digital Ltd. LLC."));
1042 			// TODO: License!
1043 
1044 	// Bullet copyrights
1045 	_AddPackageCredit(PackageCredit("Bullet")
1046 		.SetCopyright(COPYRIGHT_STRING "2003-2008 Erwin Coumans")
1047 		.SetURL("http://www.bulletphysics.com"));
1048 			// TODO: License!
1049 
1050 	// atftp copyrights
1051 	_AddPackageCredit(PackageCredit("atftp")
1052 		.SetCopyright(COPYRIGHT_STRING
1053 			"2000 Jean-Pierre Lefebvre and Remi Lefebvre"));
1054 			// TODO: License!
1055 
1056 	// Netcat copyrights
1057 	_AddPackageCredit(PackageCredit("Netcat")
1058 		.SetCopyright(COPYRIGHT_STRING "1996 Hobbit"));
1059 			// TODO: License!
1060 
1061 	// acpica copyrights
1062 	_AddPackageCredit(PackageCredit("acpica")
1063 		.SetCopyright(COPYRIGHT_STRING "1999-2006 Intel Corp."));
1064 			// TODO: License!
1065 
1066 	// unrar copyrights
1067 	_AddPackageCredit(PackageCredit("unrar")
1068 		.SetCopyright(COPYRIGHT_STRING "2002-2008 Alexander L. Roshal. "
1069 			"All rights reserved.")
1070 		.SetURL("http://www.rarlab.com"));
1071 			// TODO: License!
1072 
1073 	// libpng copyrights
1074 	_AddPackageCredit(PackageCredit("libpng")
1075 		.SetCopyright(COPYRIGHT_STRING "2004, 2006-2008 Glenn "
1076 			"Randers-Pehrson."));
1077 			// TODO: License!
1078 
1079 	// libprint copyrights
1080 	_AddPackageCredit(PackageCredit("libprint")
1081 		.SetCopyright(COPYRIGHT_STRING
1082 			"1999-2000 Y.Takagi. All rights reserved."));
1083 			// TODO: License!
1084 
1085 	// cortex copyrights
1086 	_AddPackageCredit(PackageCredit("Cortex")
1087 		.SetCopyright(COPYRIGHT_STRING "1999-2000 Eric Moon."));
1088 			// TODO: License!
1089 
1090 	// FluidSynth copyrights
1091 	_AddPackageCredit(PackageCredit("FluidSynth")
1092 		.SetCopyright(COPYRIGHT_STRING "2003 Peter Hanappe and others."));
1093 			// TODO: License!
1094 
1095 	// CannaIM copyrights
1096 	_AddPackageCredit(PackageCredit("CannaIM")
1097 		.SetCopyright(COPYRIGHT_STRING "1999 Masao Kawamura."));
1098 			// TODO: License!
1099 
1100 	// libxml2, libxslt, libexslt copyrights
1101 	_AddPackageCredit(PackageCredit("libxml2, libxslt")
1102 		.SetCopyright(COPYRIGHT_STRING
1103 			"1998-2003 Daniel Veillard. All rights reserved."));
1104 			// TODO: License!
1105 
1106 	_AddPackageCredit(PackageCredit("libexslt")
1107 		.SetCopyright(COPYRIGHT_STRING
1108 			"2001-2002 Thomas Broyer, Charlie "
1109 			"Bozeman and Daniel Veillard.  All rights reserved."));
1110 			// TODO: License!
1111 
1112 	// Xiph.org Foundation copyrights
1113 	_AddPackageCredit(PackageCredit("Xiph.org Foundation")
1114 		.SetCopyrights("libvorbis, libogg, libtheora, libspeex",
1115 			COPYRIGHT_STRING "1994-2008 Xiph.Org. "
1116 				"All rights reserved.",
1117 			NULL)
1118 		.SetURL("http://www.xiph.org"));
1119 			// TODO: License!
1120 
1121 	// The Tcpdump Group
1122 	_AddPackageCredit(PackageCredit("The Tcpdump Group")
1123 		.SetCopyright("tcpdump, libpcap")
1124 		.SetURL("http://www.tcpdump.org"));
1125 			// TODO: License!
1126 
1127 	// Matroska
1128 	_AddPackageCredit(PackageCredit("libmatroska")
1129 		.SetCopyright(COPYRIGHT_STRING "2002-2003 Steve Lhomme. "
1130 			"All rights reserved.")
1131 		.SetURL("http://www.matroska.org"));
1132 			// TODO: License!
1133 
1134 	// BColorQuantizer (originally CQuantizer code)
1135 	_AddPackageCredit(PackageCredit("CQuantizer")
1136 		.SetCopyright(COPYRIGHT_STRING "1996-1997 Jeff Prosise. "
1137 			"All rights reserved."));
1138 			// TODO: License!
1139 
1140 	// MAPM (Mike's Arbitrary Precision Math Library) used by DeskCalc
1141 	_AddPackageCredit(PackageCredit("MAPM")
1142 		.SetCopyright(COPYRIGHT_STRING
1143 			"1999-2007 Michael C. Ring. All rights reserved.")
1144 		.SetURL("http://tc.umn.edu/~ringx004"));
1145 			// TODO: License!
1146 
1147 	// MkDepend 1.7 copyright (Makefile dependency generator)
1148 	_AddPackageCredit(PackageCredit("MkDepend")
1149 		.SetCopyright(COPYRIGHT_STRING "1995-2001 Lars Düning. "
1150 			"All rights reserved."));
1151 			// TODO: License!
1152 
1153 	// libhttpd copyright (used as Poorman backend)
1154 	_AddPackageCredit(PackageCredit("libhttpd")
1155 		.SetCopyright(COPYRIGHT_STRING
1156 			"1995,1998,1999,2000,2001 by "
1157 			"Jef Poskanzer. All rights reserved.")
1158 		.SetLicense("LibHTTPd")
1159 		.SetURL("http://www.acme.com/software/thttpd/"));
1160 
1161 #ifdef __INTEL__
1162 	// Udis86 copyrights
1163 	_AddPackageCredit(PackageCredit("Udis86")
1164 		.SetCopyright(COPYRIGHT_STRING "2002, 2003, 2004 Vivek Mohan. "
1165 			"All rights reserved.")
1166 		.SetURL("http://udis86.sourceforge.net"));
1167 			// TODO: License!
1168 #endif
1169 
1170 	_AddCopyrightsFromAttribute();
1171 	_AddPackageCreditEntries();
1172 
1173 	return new CropView(creditsScroller, 0, 1, 1, 1);
1174 }
1175 
1176 
1177 status_t
1178 AboutView::_GetLicensePath(const char* license, BPath& path)
1179 {
1180 	static const directory_which directoryConstants[] = {
1181 		B_USER_DATA_DIRECTORY,
1182 		B_COMMON_DATA_DIRECTORY,
1183 		B_SYSTEM_DATA_DIRECTORY
1184 	};
1185 	static const int dirCount = 3;
1186 
1187 	for (int i = 0; i < dirCount; i++) {
1188 		struct stat st;
1189 		status_t error = find_directory(directoryConstants[i], &path);
1190 		if (error == B_OK && path.Append("licenses") == B_OK
1191 			&& path.Append(license) == B_OK
1192 			&& lstat(path.Path(), &st) == 0) {
1193 			return B_OK;
1194 		}
1195 	}
1196 
1197 	path.Unset();
1198 	return B_ENTRY_NOT_FOUND;
1199 }
1200 
1201 
1202 void
1203 AboutView::_AddCopyrightsFromAttribute()
1204 {
1205 #ifdef __HAIKU__
1206 	// open the app executable file
1207 	char appPath[B_PATH_NAME_LENGTH];
1208 	int appFD;
1209 	if (BPrivate::get_app_path(appPath) != B_OK
1210 		|| (appFD = open(appPath, O_RDONLY)) < 0) {
1211 		return;
1212 	}
1213 
1214 	// open the attribute
1215 	int attrFD = fs_fopen_attr(appFD, "COPYRIGHTS", B_STRING_TYPE, O_RDONLY);
1216 	close(appFD);
1217 	if (attrFD < 0)
1218 		return;
1219 
1220 	// attach it to a FILE
1221 	FILE* attrFile = fdopen(attrFD, "r");
1222 	if (attrFile == NULL) {
1223 		close(attrFD);
1224 		return;
1225 	}
1226 	CObjectDeleter<FILE, int> _(attrFile, fclose);
1227 
1228 	// read and parse the copyrights
1229 	BMessage package;
1230 	BString fieldName;
1231 	BString fieldValue;
1232 	char lineBuffer[LINE_MAX];
1233 	while (char* line = fgets(lineBuffer, sizeof(lineBuffer), attrFile)) {
1234 		// chop off line break
1235 		size_t lineLen = strlen(line);
1236 		if (lineLen > 0 && line[lineLen - 1] == '\n')
1237 			line[--lineLen] = '\0';
1238 
1239 		// flush previous field, if a new field begins, otherwise append
1240 		if (lineLen == 0 || !isspace(line[0])) {
1241 			// new field -- flush the previous one
1242 			if (fieldName.Length() > 0) {
1243 				fieldValue = trim_string(fieldValue.String(),
1244 					fieldValue.Length());
1245 				package.AddString(fieldName.String(), fieldValue);
1246 				fieldName = "";
1247 			}
1248 		} else if (fieldName.Length() > 0) {
1249 			// append to current field
1250 			fieldValue += line;
1251 			continue;
1252 		} else {
1253 			// bogus line -- ignore
1254 			continue;
1255 		}
1256 
1257 		if (lineLen == 0)
1258 			continue;
1259 
1260 		// parse new field
1261 		char* colon = strchr(line, ':');
1262 		if (colon == NULL) {
1263 			// bogus line -- ignore
1264 			continue;
1265 		}
1266 
1267 		fieldName.SetTo(line, colon - line);
1268 		fieldName = trim_string(line, colon - line);
1269 		if (fieldName.Length() == 0) {
1270 			// invalid field name
1271 			continue;
1272 		}
1273 
1274 		fieldValue = colon + 1;
1275 
1276 		if (fieldName == "Package") {
1277 			// flush the current package
1278 			_AddPackageCredit(PackageCredit(package));
1279 			package.MakeEmpty();
1280 		}
1281 	}
1282 
1283 	// flush current package
1284 	_AddPackageCredit(PackageCredit(package));
1285 #endif
1286 }
1287 
1288 
1289 void
1290 AboutView::_AddPackageCreditEntries()
1291 {
1292 	for (PackageCreditMap::iterator it = fPackageCredits.begin();
1293 		it != fPackageCredits.end(); ++it) {
1294 		PackageCredit* package = it->second;
1295 
1296 		BString text(package->CopyrightAt(0));
1297 		int32 count = package->CountCopyrights();
1298 		for (int32 i = 1; i < count; i++)
1299 			text << "\n" << package->CopyrightAt(i);
1300 
1301 		AddCopyrightEntry(package->PackageName(), text.String(),
1302 			package->Licenses(), package->URL());
1303 	}
1304 }
1305 
1306 
1307 void
1308 AboutView::_AddPackageCredit(const PackageCredit& package)
1309 {
1310 	if (!package.IsValid())
1311 		return;
1312 
1313 	PackageCreditMap::iterator it = fPackageCredits.find(package.PackageName());
1314 	if (it != fPackageCredits.end()) {
1315 		// If the new package credit isn't "better" than the old one, ignore it.
1316 		PackageCredit* oldPackage = it->second;
1317 		if (!package.IsBetterThan(*oldPackage))
1318 			return;
1319 
1320 		// replace the old credit
1321 		fPackageCredits.erase(it);
1322 		delete oldPackage;
1323 	}
1324 
1325 	fPackageCredits[package.PackageName()] = new PackageCredit(package);
1326 }
1327 
1328 
1329 //	#pragma mark -
1330 
1331 
1332 static const char *
1333 MemUsageToString(char string[], size_t size, system_info *info)
1334 {
1335 	snprintf(string, size, "%d MB total, %d MB used (%d%%)",
1336 			int(info->max_pages / 256.0f + 0.5f),
1337 			int(info->used_pages / 256.0f + 0.5f),
1338 			int(100 * info->used_pages / info->max_pages));
1339 
1340 	return string;
1341 }
1342 
1343 
1344 static const char *
1345 UptimeToString(char string[], size_t size)
1346 {
1347 	int64 days, hours, minutes, seconds, remainder;
1348 	int64 systime = system_time();
1349 
1350 	days = systime / 86400000000LL;
1351 	remainder = systime % 86400000000LL;
1352 
1353 	hours = remainder / 3600000000LL;
1354 	remainder = remainder % 3600000000LL;
1355 
1356 	minutes = remainder / 60000000;
1357 	remainder = remainder % 60000000;
1358 
1359 	seconds = remainder / 1000000;
1360 
1361 	char *str = string;
1362 	if (days) {
1363 		str += snprintf(str, size, "%lld day%s",days, days > 1 ? "s" : "");
1364 	}
1365 	if (hours) {
1366 		str += snprintf(str, size - strlen(string), "%s%lld hour%s",
1367 				str != string ? ", " : "",
1368 				hours, hours > 1 ? "s" : "");
1369 	}
1370 	if (minutes) {
1371 		str += snprintf(str, size - strlen(string), "%s%lld minute%s",
1372 				str != string ? ", " : "",
1373 				minutes, minutes > 1 ? "s" : "");
1374 	}
1375 
1376 	if (seconds || str == string) {
1377 		// Haiku would be well-known to boot very fast.
1378 		// Let's be ready to handle below minute uptime, zero second included ;-)
1379 		str += snprintf(str, size - strlen(string), "%s%lld second%s",
1380 				str != string ? ", " : "",
1381 				seconds, seconds > 1 ? "s" : "");
1382 	}
1383 
1384 	return string;
1385 }
1386 
1387 
1388 int
1389 main()
1390 {
1391 	AboutApp app;
1392 	app.Run();
1393 	return 0;
1394 }
1395 
1396