xref: /haiku/src/apps/aboutsystem/AboutSystem.cpp (revision 49546fa993e8de87ddebffd56f890aec71aa42d3)
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 		"Vincent Duvert\n"
794 		"Fredrik Ekdahl\n"
795 		"Mark Erben\n"
796 		"Christian Fasshauer\n"
797 		"Andreas Färber\n"
798 		"Marc Flerackers\n"
799 		"Michele Frau (zuMi)\n"
800 		"Matthijs Hollemans\n"
801 		"Mathew Hounsell\n"
802 		"Morgan Howe\n"
803 		"Ma Jie\n"
804 		"Carwyn Jones\n"
805 		"Vasilis Kaoutsis\n"
806 		"James Kim\n"
807 		"Shintaro Kinugawa\n"
808 		"Jan Klötzke\n"
809 		"Kurtis Kopf\n"
810 		"Tomáš Kučera\n"
811 		"Luboš Kulič\n"
812 		"Elad Lahav\n"
813 		"Anthony Lee\n"
814 		"Santiago Lema\n"
815 		"Raynald Lesieur\n"
816 		"Oscar Lesta\n"
817 		"Jerome Leveque\n"
818 		"Christof Lutteroth\n"
819 		"Graham MacDonald\n"
820 		"Brecht Machiels\n"
821 		"Jan Matějek\n"
822 		"Brian Matzon\n"
823 		"Christopher ML Zumwalt May\n"
824 		"Andrew McCall\n"
825 		"Scott McCreary\n"
826 		"Marius Middelthon\n"
827 		"Marco Minutoli\n"
828 		"Misza\n"
829 		"MrSiggler\n"
830 		"Alan Murta\n"
831 		"Raghuram Nagireddy\n"
832 		"Jeroen Oortwijn (idefix)\n"
833 		"Pahtz\n"
834 		"Michael Paine\n"
835 		"Adrian Panasiuk\n"
836 		"Francesco Piccinno\n"
837 		"David Powell\n"
838 		"Jeremy Rand\n"
839 		"Hartmut Reh\n"
840 		"Daniel Reinhold\n"
841 		"Chris Roberts\n"
842 		"Samuel Rodriguez Perez\n"
843 		"Thomas Roell\n"
844 		"Rafael Romo\n"
845 		"Ralf Schülke\n"
846 		"Reznikov Sergei\n"
847 		"Zousar Shaker\n"
848 		"Daniel Switkin\n"
849 		"Atsushi Takamatsu\n"
850 		"James Urquhart\n"
851 		"Jason Vandermark\n"
852 		"Sandor Vroemisse\n"
853 		"Denis Washington\n"
854 		"Ulrich Wimboeck\n"
855 		"Johannes Wischert\n"
856 		"James Woodcock\n"
857 		"Gerald Zajac\n"
858 		"Łukasz Zemczak\n"
859 		"JiSheng Zhang\n"
860 		"Zhao Shuai\n"
861 		"\n" B_UTF8_ELLIPSIS " and probably some more we forgot to mention "
862 		"(sorry!)"
863 		"\n\n");
864 
865 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
866 	fCreditsView->Insert("Special Thanks To:\n");
867 
868 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
869 	fCreditsView->Insert("Travis Geiselbrecht (and his NewOS kernel)\n");
870 	fCreditsView->Insert("Michael Phipps (project founder)\n\n");
871 	fCreditsView->Insert("The Haiku-Ports Team\n");
872 	fCreditsView->Insert("The Haikuware Team and their Bounty Program\n");
873 	fCreditsView->Insert("The BeGeistert Team\n\n");
874 	fCreditsView->Insert("... and the many community members making "
875 		"donations!\n\n");
876 
877 	// copyrights for various projects we use
878 
879 	BPath mitPath;
880 	_GetLicensePath("MIT", mitPath);
881 
882 	font.SetSize(be_bold_font->Size() + 4);
883 	font.SetFace(B_BOLD_FACE);
884 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
885 	fCreditsView->Insert("\nCopyrights\n\n");
886 
887 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
888 	fCreditsView->Insert("[Click a license name to read the respective "
889 		"license.]\n\n");
890 
891 	// Haiku license
892 	fCreditsView->Insert("The code that is unique to Haiku, especially the "
893 		"kernel and all code that applications may link against, is "
894 		"distributed under the terms of the ");
895 	fCreditsView->InsertHyperText("MIT license",
896 		new OpenFileAction(mitPath.Path()));
897 	fCreditsView->Insert(". Some system libraries contain third party code "
898 		"distributed under the LGPL license. You can find the copyrights "
899 		"to third party code below.\n\n");
900 
901 	// GNU copyrights
902 	AddCopyrightEntry("The GNU Project",
903 		"Contains software from the GNU Project, "
904 		"released under the GPL and LGPL licences:\n"
905 		"GNU C Library, "
906 		"GNU coretools, diffutils, findutils, "
907 		"sharutils, gawk, bison, m4, make, "
908 		"gdb, wget, ncurses, termcap, "
909 		"Bourne Again Shell.\n"
910 		COPYRIGHT_STRING "The Free Software Foundation.",
911 		StringVector("GNU LGPL v2.1", "GNU GPL v2", "GNU GPL v3", NULL),
912 		"http://www.gnu.org");
913 
914 	// FreeBSD copyrights
915 	AddCopyrightEntry("The FreeBSD Project",
916 		"Contains software from the FreeBSD Project, "
917 		"released under the BSD licence:\n"
918 		"cal, ftpd, ping, telnet, "
919 		"telnetd, traceroute\n"
920 		COPYRIGHT_STRING "1994-2008 The FreeBSD Project.  "
921 		"All rights reserved.",
922 		"http://www.freebsd.org");
923 			// TODO: License!
924 
925 	// NetBSD copyrights
926 	AddCopyrightEntry("The NetBSD Project",
927 		"Contains software developed by the NetBSD, "
928 		"Foundation, Inc. and its contributors:\n"
929 		"ftp, tput\n"
930 		COPYRIGHT_STRING "1996-2008 The NetBSD Foundation, Inc.  "
931 		"All rights reserved.",
932 		"http://www.netbsd.org");
933 			// TODO: License!
934 
935 	// FFMpeg copyrights
936 	_AddPackageCredit(PackageCredit("FFMpeg libavcodec")
937 		.SetCopyright(COPYRIGHT_STRING "2000-2007 Fabrice Bellard, et al.")
938 		.SetURL("http://www.ffmpeg.org"));
939 			// TODO: License!
940 
941 	// AGG copyrights
942 	_AddPackageCredit(PackageCredit("AntiGrain Geometry")
943 		.SetCopyright(COPYRIGHT_STRING "2002-2006 Maxim Shemanarev (McSeem).")
944 		.SetURL("http://www.antigrain.com"));
945 			// TODO: License!
946 
947 	// PDFLib copyrights
948 	_AddPackageCredit(PackageCredit("PDFLib")
949 		.SetCopyright(COPYRIGHT_STRING "1997-2006 PDFlib GmbH and Thomas Merz. "
950 			"All rights reserved.\n"
951 			"PDFlib and PDFlib logo are registered trademarks of PDFlib GmbH.")
952 		.SetURL("http://www.pdflib.com"));
953 			// TODO: License!
954 
955 	// FreeType copyrights
956 	_AddPackageCredit(PackageCredit("FreeType2")
957 		.SetCopyright("Portions of this software are copyright "
958 			B_UTF8_COPYRIGHT " 1996-2006 "
959 			"The FreeType Project.  All rights reserved.")
960 		.SetURL("http://www.freetype.org"));
961 			// TODO: License!
962 
963 	// Mesa3D (http://www.mesa3d.org) copyrights
964 	_AddPackageCredit(PackageCredit("Mesa")
965 		.SetCopyright(COPYRIGHT_STRING "1999-2006 Brian Paul. "
966 			"Mesa3D project.  All rights reserved.")
967 		.SetURL("http://www.mesa3d.org"));
968 			// TODO: License!
969 
970 	// SGI's GLU implementation copyrights
971 	_AddPackageCredit(PackageCredit("GLU")
972 		.SetCopyright(COPYRIGHT_STRING
973 			"1991-2000 Silicon Graphics, Inc. "
974 			"SGI's Software FreeB license.  All rights reserved."));
975 			// TODO: License!
976 
977 	// GLUT implementation copyrights
978 	_AddPackageCredit(PackageCredit("GLUT")
979 		.SetCopyrights(COPYRIGHT_STRING "1994-1997 Mark Kilgard. "
980 				"All rights reserved.",
981 			COPYRIGHT_STRING "1997 Be Inc.",
982 			COPYRIGHT_STRING "1999 Jake Hamby.",
983 			NULL));
984 			// TODO: License!
985 
986 	// OpenGroup & DEC (BRegion backend) copyright
987 	_AddPackageCredit(PackageCredit("BRegion backend (XFree86)")
988 		.SetCopyrights(COPYRIGHT_STRING "1987, 1988, 1998 The Open Group.",
989 			COPYRIGHT_STRING "1987, 1988 Digital Equipment "
990 				"Corporation, Maynard, Massachusetts.\n"
991 				"All rights reserved.",
992 			NULL));
993 			// TODO: License!
994 
995 	// Konatu font
996 	_AddPackageCredit(PackageCredit("Konatu font")
997 		.SetCopyright(COPYRIGHT_STRING "2002- MASUDA mitiya.\n"
998 			"MIT license. All rights reserved."));
999 			// TODO: License!
1000 
1001 	// expat copyrights
1002 	_AddPackageCredit(PackageCredit("expat")
1003 		.SetCopyrights(COPYRIGHT_STRING
1004 				"1998, 1999, 2000 Thai Open Source "
1005 				"Software Center Ltd and Clark Cooper.",
1006 			COPYRIGHT_STRING "2001, 2002, 2003 Expat maintainers.",
1007 			NULL));
1008 			// TODO: License!
1009 
1010 	// zlib copyrights
1011 	_AddPackageCredit(PackageCredit("zlib")
1012 		.SetCopyright(COPYRIGHT_STRING
1013 			"1995-2004 Jean-loup Gailly and Mark Adler."));
1014 			// TODO: License!
1015 
1016 	// zip copyrights
1017 	_AddPackageCredit(PackageCredit("Info-ZIP")
1018 		.SetCopyright(COPYRIGHT_STRING
1019 			"1990-2002 Info-ZIP. All rights reserved."));
1020 			// TODO: License!
1021 
1022 	// bzip2 copyrights
1023 	_AddPackageCredit(PackageCredit("bzip2")
1024 		.SetCopyright(COPYRIGHT_STRING
1025 			"1996-2005 Julian R Seward. All rights reserved."));
1026 			// TODO: License!
1027 
1028 	// VIM copyrights
1029 	_AddPackageCredit(PackageCredit("Vi IMproved")
1030 		.SetCopyright(COPYRIGHT_STRING "Bram Moolenaar et al."));
1031 			// TODO: License!
1032 
1033 	// lp_solve copyrights
1034 	_AddPackageCredit(PackageCredit("lp_solve")
1035 		.SetCopyright(COPYRIGHT_STRING
1036 			"Michel Berkelaar, Kjell Eikland, Peter Notebaert")
1037 		.SetLicense("GNU LGPL v2.1")
1038 		.SetURL("http://lpsolve.sourceforge.net/"));
1039 
1040 	// OpenEXR copyrights
1041 	_AddPackageCredit(PackageCredit("OpenEXR")
1042 		.SetCopyright(COPYRIGHT_STRING "2002-2005 Industrial Light & Magic, "
1043 			"a division of Lucas Digital Ltd. LLC."));
1044 			// TODO: License!
1045 
1046 	// Bullet copyrights
1047 	_AddPackageCredit(PackageCredit("Bullet")
1048 		.SetCopyright(COPYRIGHT_STRING "2003-2008 Erwin Coumans")
1049 		.SetURL("http://www.bulletphysics.com"));
1050 			// TODO: License!
1051 
1052 	// atftp copyrights
1053 	_AddPackageCredit(PackageCredit("atftp")
1054 		.SetCopyright(COPYRIGHT_STRING
1055 			"2000 Jean-Pierre Lefebvre and Remi Lefebvre"));
1056 			// TODO: License!
1057 
1058 	// Netcat copyrights
1059 	_AddPackageCredit(PackageCredit("Netcat")
1060 		.SetCopyright(COPYRIGHT_STRING "1996 Hobbit"));
1061 			// TODO: License!
1062 
1063 	// acpica copyrights
1064 	_AddPackageCredit(PackageCredit("acpica")
1065 		.SetCopyright(COPYRIGHT_STRING "1999-2006 Intel Corp."));
1066 			// TODO: License!
1067 
1068 	// unrar copyrights
1069 	_AddPackageCredit(PackageCredit("unrar")
1070 		.SetCopyright(COPYRIGHT_STRING "2002-2008 Alexander L. Roshal. "
1071 			"All rights reserved.")
1072 		.SetURL("http://www.rarlab.com"));
1073 			// TODO: License!
1074 
1075 	// libpng copyrights
1076 	_AddPackageCredit(PackageCredit("libpng")
1077 		.SetCopyright(COPYRIGHT_STRING "2004, 2006-2008 Glenn "
1078 			"Randers-Pehrson."));
1079 			// TODO: License!
1080 
1081 	// libprint copyrights
1082 	_AddPackageCredit(PackageCredit("libprint")
1083 		.SetCopyright(COPYRIGHT_STRING
1084 			"1999-2000 Y.Takagi. All rights reserved."));
1085 			// TODO: License!
1086 
1087 	// cortex copyrights
1088 	_AddPackageCredit(PackageCredit("Cortex")
1089 		.SetCopyright(COPYRIGHT_STRING "1999-2000 Eric Moon."));
1090 			// TODO: License!
1091 
1092 	// FluidSynth copyrights
1093 	_AddPackageCredit(PackageCredit("FluidSynth")
1094 		.SetCopyright(COPYRIGHT_STRING "2003 Peter Hanappe and others."));
1095 			// TODO: License!
1096 
1097 	// CannaIM copyrights
1098 	_AddPackageCredit(PackageCredit("CannaIM")
1099 		.SetCopyright(COPYRIGHT_STRING "1999 Masao Kawamura."));
1100 			// TODO: License!
1101 
1102 	// libxml2, libxslt, libexslt copyrights
1103 	_AddPackageCredit(PackageCredit("libxml2, libxslt")
1104 		.SetCopyright(COPYRIGHT_STRING
1105 			"1998-2003 Daniel Veillard. All rights reserved."));
1106 			// TODO: License!
1107 
1108 	_AddPackageCredit(PackageCredit("libexslt")
1109 		.SetCopyright(COPYRIGHT_STRING
1110 			"2001-2002 Thomas Broyer, Charlie "
1111 			"Bozeman and Daniel Veillard.  All rights reserved."));
1112 			// TODO: License!
1113 
1114 	// Xiph.org Foundation copyrights
1115 	_AddPackageCredit(PackageCredit("Xiph.org Foundation")
1116 		.SetCopyrights("libvorbis, libogg, libtheora, libspeex",
1117 			COPYRIGHT_STRING "1994-2008 Xiph.Org. "
1118 				"All rights reserved.",
1119 			NULL)
1120 		.SetURL("http://www.xiph.org"));
1121 			// TODO: License!
1122 
1123 	// The Tcpdump Group
1124 	_AddPackageCredit(PackageCredit("The Tcpdump Group")
1125 		.SetCopyright("tcpdump, libpcap")
1126 		.SetURL("http://www.tcpdump.org"));
1127 			// TODO: License!
1128 
1129 	// Matroska
1130 	_AddPackageCredit(PackageCredit("libmatroska")
1131 		.SetCopyright(COPYRIGHT_STRING "2002-2003 Steve Lhomme. "
1132 			"All rights reserved.")
1133 		.SetURL("http://www.matroska.org"));
1134 			// TODO: License!
1135 
1136 	// BColorQuantizer (originally CQuantizer code)
1137 	_AddPackageCredit(PackageCredit("CQuantizer")
1138 		.SetCopyright(COPYRIGHT_STRING "1996-1997 Jeff Prosise. "
1139 			"All rights reserved."));
1140 			// TODO: License!
1141 
1142 	// MAPM (Mike's Arbitrary Precision Math Library) used by DeskCalc
1143 	_AddPackageCredit(PackageCredit("MAPM")
1144 		.SetCopyright(COPYRIGHT_STRING
1145 			"1999-2007 Michael C. Ring. All rights reserved.")
1146 		.SetURL("http://tc.umn.edu/~ringx004"));
1147 			// TODO: License!
1148 
1149 	// MkDepend 1.7 copyright (Makefile dependency generator)
1150 	_AddPackageCredit(PackageCredit("MkDepend")
1151 		.SetCopyright(COPYRIGHT_STRING "1995-2001 Lars Düning. "
1152 			"All rights reserved."));
1153 			// TODO: License!
1154 
1155 	// libhttpd copyright (used as Poorman backend)
1156 	_AddPackageCredit(PackageCredit("libhttpd")
1157 		.SetCopyright(COPYRIGHT_STRING
1158 			"1995,1998,1999,2000,2001 by "
1159 			"Jef Poskanzer. All rights reserved.")
1160 		.SetLicense("LibHTTPd")
1161 		.SetURL("http://www.acme.com/software/thttpd/"));
1162 
1163 #ifdef __INTEL__
1164 	// Udis86 copyrights
1165 	_AddPackageCredit(PackageCredit("Udis86")
1166 		.SetCopyright(COPYRIGHT_STRING "2002, 2003, 2004 Vivek Mohan. "
1167 			"All rights reserved.")
1168 		.SetURL("http://udis86.sourceforge.net"));
1169 			// TODO: License!
1170 #endif
1171 
1172 	_AddCopyrightsFromAttribute();
1173 	_AddPackageCreditEntries();
1174 
1175 	return new CropView(creditsScroller, 0, 1, 1, 1);
1176 }
1177 
1178 
1179 status_t
1180 AboutView::_GetLicensePath(const char* license, BPath& path)
1181 {
1182 	static const directory_which directoryConstants[] = {
1183 		B_USER_DATA_DIRECTORY,
1184 		B_COMMON_DATA_DIRECTORY,
1185 		B_SYSTEM_DATA_DIRECTORY
1186 	};
1187 	static const int dirCount = 3;
1188 
1189 	for (int i = 0; i < dirCount; i++) {
1190 		struct stat st;
1191 		status_t error = find_directory(directoryConstants[i], &path);
1192 		if (error == B_OK && path.Append("licenses") == B_OK
1193 			&& path.Append(license) == B_OK
1194 			&& lstat(path.Path(), &st) == 0) {
1195 			return B_OK;
1196 		}
1197 	}
1198 
1199 	path.Unset();
1200 	return B_ENTRY_NOT_FOUND;
1201 }
1202 
1203 
1204 void
1205 AboutView::_AddCopyrightsFromAttribute()
1206 {
1207 #ifdef __HAIKU__
1208 	// open the app executable file
1209 	char appPath[B_PATH_NAME_LENGTH];
1210 	int appFD;
1211 	if (BPrivate::get_app_path(appPath) != B_OK
1212 		|| (appFD = open(appPath, O_RDONLY)) < 0) {
1213 		return;
1214 	}
1215 
1216 	// open the attribute
1217 	int attrFD = fs_fopen_attr(appFD, "COPYRIGHTS", B_STRING_TYPE, O_RDONLY);
1218 	close(appFD);
1219 	if (attrFD < 0)
1220 		return;
1221 
1222 	// attach it to a FILE
1223 	FILE* attrFile = fdopen(attrFD, "r");
1224 	if (attrFile == NULL) {
1225 		close(attrFD);
1226 		return;
1227 	}
1228 	CObjectDeleter<FILE, int> _(attrFile, fclose);
1229 
1230 	// read and parse the copyrights
1231 	BMessage package;
1232 	BString fieldName;
1233 	BString fieldValue;
1234 	char lineBuffer[LINE_MAX];
1235 	while (char* line = fgets(lineBuffer, sizeof(lineBuffer), attrFile)) {
1236 		// chop off line break
1237 		size_t lineLen = strlen(line);
1238 		if (lineLen > 0 && line[lineLen - 1] == '\n')
1239 			line[--lineLen] = '\0';
1240 
1241 		// flush previous field, if a new field begins, otherwise append
1242 		if (lineLen == 0 || !isspace(line[0])) {
1243 			// new field -- flush the previous one
1244 			if (fieldName.Length() > 0) {
1245 				fieldValue = trim_string(fieldValue.String(),
1246 					fieldValue.Length());
1247 				package.AddString(fieldName.String(), fieldValue);
1248 				fieldName = "";
1249 			}
1250 		} else if (fieldName.Length() > 0) {
1251 			// append to current field
1252 			fieldValue += line;
1253 			continue;
1254 		} else {
1255 			// bogus line -- ignore
1256 			continue;
1257 		}
1258 
1259 		if (lineLen == 0)
1260 			continue;
1261 
1262 		// parse new field
1263 		char* colon = strchr(line, ':');
1264 		if (colon == NULL) {
1265 			// bogus line -- ignore
1266 			continue;
1267 		}
1268 
1269 		fieldName.SetTo(line, colon - line);
1270 		fieldName = trim_string(line, colon - line);
1271 		if (fieldName.Length() == 0) {
1272 			// invalid field name
1273 			continue;
1274 		}
1275 
1276 		fieldValue = colon + 1;
1277 
1278 		if (fieldName == "Package") {
1279 			// flush the current package
1280 			_AddPackageCredit(PackageCredit(package));
1281 			package.MakeEmpty();
1282 		}
1283 	}
1284 
1285 	// flush current package
1286 	_AddPackageCredit(PackageCredit(package));
1287 #endif
1288 }
1289 
1290 
1291 void
1292 AboutView::_AddPackageCreditEntries()
1293 {
1294 	for (PackageCreditMap::iterator it = fPackageCredits.begin();
1295 		it != fPackageCredits.end(); ++it) {
1296 		PackageCredit* package = it->second;
1297 
1298 		BString text(package->CopyrightAt(0));
1299 		int32 count = package->CountCopyrights();
1300 		for (int32 i = 1; i < count; i++)
1301 			text << "\n" << package->CopyrightAt(i);
1302 
1303 		AddCopyrightEntry(package->PackageName(), text.String(),
1304 			package->Licenses(), package->URL());
1305 	}
1306 }
1307 
1308 
1309 void
1310 AboutView::_AddPackageCredit(const PackageCredit& package)
1311 {
1312 	if (!package.IsValid())
1313 		return;
1314 
1315 	PackageCreditMap::iterator it = fPackageCredits.find(package.PackageName());
1316 	if (it != fPackageCredits.end()) {
1317 		// If the new package credit isn't "better" than the old one, ignore it.
1318 		PackageCredit* oldPackage = it->second;
1319 		if (!package.IsBetterThan(*oldPackage))
1320 			return;
1321 
1322 		// replace the old credit
1323 		fPackageCredits.erase(it);
1324 		delete oldPackage;
1325 	}
1326 
1327 	fPackageCredits[package.PackageName()] = new PackageCredit(package);
1328 }
1329 
1330 
1331 //	#pragma mark -
1332 
1333 
1334 static const char *
1335 MemUsageToString(char string[], size_t size, system_info *info)
1336 {
1337 	snprintf(string, size, "%d MB total, %d MB used (%d%%)",
1338 			int(info->max_pages / 256.0f + 0.5f),
1339 			int(info->used_pages / 256.0f + 0.5f),
1340 			int(100 * info->used_pages / info->max_pages));
1341 
1342 	return string;
1343 }
1344 
1345 
1346 static const char *
1347 UptimeToString(char string[], size_t size)
1348 {
1349 	int64 days, hours, minutes, seconds, remainder;
1350 	int64 systime = system_time();
1351 
1352 	days = systime / 86400000000LL;
1353 	remainder = systime % 86400000000LL;
1354 
1355 	hours = remainder / 3600000000LL;
1356 	remainder = remainder % 3600000000LL;
1357 
1358 	minutes = remainder / 60000000;
1359 	remainder = remainder % 60000000;
1360 
1361 	seconds = remainder / 1000000;
1362 
1363 	char *str = string;
1364 	if (days) {
1365 		str += snprintf(str, size, "%lld day%s",days, days > 1 ? "s" : "");
1366 	}
1367 	if (hours) {
1368 		str += snprintf(str, size - strlen(string), "%s%lld hour%s",
1369 				str != string ? ", " : "",
1370 				hours, hours > 1 ? "s" : "");
1371 	}
1372 	if (minutes) {
1373 		str += snprintf(str, size - strlen(string), "%s%lld minute%s",
1374 				str != string ? ", " : "",
1375 				minutes, minutes > 1 ? "s" : "");
1376 	}
1377 
1378 	if (seconds || str == string) {
1379 		// Haiku would be well-known to boot very fast.
1380 		// Let's be ready to handle below minute uptime, zero second included ;-)
1381 		str += snprintf(str, size - strlen(string), "%s%lld second%s",
1382 				str != string ? ", " : "",
1383 				seconds, seconds > 1 ? "s" : "");
1384 	}
1385 
1386 	return string;
1387 }
1388 
1389 
1390 int
1391 main()
1392 {
1393 	AboutApp app;
1394 	app.Run();
1395 	return 0;
1396 }
1397 
1398