1#include <ScrollView.h>
2#include <TextView.h>
3#include <String.h>
4#include <limits.h>
5
6#include "ErrorLogWindow.h"
7
8rgb_color white = {255,255,255,255};
9rgb_color notwhite = {255,255,200,255};
10
11class Error : public BView {
12	public:
13		Error(BRect rect,alert_type type,const char *tag,const char *message,bool timestamp,rgb_color bkg);
14
15		void GetPreferredSize(float *width, float *height);
16		void Draw(BRect updateRect);
17		void FrameResized(float w, float h);
18	private:
19		alert_type type;
20};
21
22class ErrorPanel : public BView {
23	public:
24		ErrorPanel(BRect rect) : BView(rect,"ErrorScrollPanel",B_FOLLOW_ALL_SIDES,B_DRAW_ON_CHILDREN | B_FRAME_EVENTS), alerts_displayed(0), add_next_at(0) {}
25
26		void GetPreferredSize(float *width, float *height) {
27			*width = Bounds().Width();
28			*height = add_next_at;
29		}
30
31		void TargetedByScrollView(BScrollView *scroll_view) { scroll = scroll_view; /*scroll->ScrollBar(B_VERTICAL)->SetRange(0,add_next_at);*/ }
32		void FrameResized(float w, float /*h*/) {
33			if (w == Frame().Width())
34				return;
35
36			add_next_at = 0;
37			for (int32 i = 0; i < CountChildren(); i++) {
38				ChildAt(i)->MoveTo(BPoint(0,add_next_at));
39				ChildAt(i)->ResizeTo(w,ChildAt(i)->Frame().Height());
40				ChildAt(i)->ResizeToPreferred();
41				add_next_at += ChildAt(i)->Bounds().Height();
42			}
43			ResizeTo(w,add_next_at);
44		}
45
46		int32 alerts_displayed;
47		float add_next_at;
48		BScrollView *scroll;
49};
50
51
52//	#pragma mark -
53
54
55ErrorLogWindow::ErrorLogWindow(BRect rect, const char *name, window_type type)
56	:
57	BWindow(rect, name, type, B_NO_WORKSPACE_ACTIVATION | B_NOT_MINIMIZABLE
58		| B_ASYNCHRONOUS_CONTROLS),
59	fIsRunning(false)
60{
61	rect = Bounds();
62	rect.right -= B_V_SCROLL_BAR_WIDTH;
63
64	view = new ErrorPanel(rect);
65	AddChild(new BScrollView("ErrorScroller", view, B_FOLLOW_ALL_SIDES, 0, false, true));
66	Show();
67	Hide();
68}
69
70
71void
72ErrorLogWindow::AddError(alert_type type, const char *message, const char *tag, bool timestamp)
73{
74	ErrorPanel *panel = (ErrorPanel *)view;
75
76	// first call?
77	if (!fIsRunning) {
78		fIsRunning = true;
79		Show();
80	}
81
82	Lock();
83
84	Error *newError = new Error(BRect(0, panel->add_next_at, panel->Bounds().right,
85		panel->add_next_at + 1), type, tag, message, timestamp,
86		(panel->alerts_displayed++ % 2 == 0) ? white : notwhite);
87
88	newError->ResizeToPreferred();
89	panel->add_next_at += newError->Bounds().Height();
90	panel->AddChild(newError);
91	panel->ResizeToPreferred();
92
93	if (panel->add_next_at > Frame().Height()) {
94		BScrollBar *bar = panel->scroll->ScrollBar(B_VERTICAL);
95
96		bar->SetRange(0, panel->add_next_at - Frame().Height());
97		bar->SetSteps(1, Frame().Height());
98		bar->SetProportion(Frame().Height() / panel->add_next_at);
99	} else
100		panel->scroll->ScrollBar(B_VERTICAL)->SetRange(0,0);
101
102	if (IsHidden())
103		Show();
104
105	Unlock();
106}
107
108
109bool
110ErrorLogWindow::QuitRequested()
111{
112	Hide();
113
114	while (view->CountChildren() != 0) {
115		BView* child = view->ChildAt(0);
116		view->RemoveChild(child);
117		delete child;
118	}
119
120	ErrorPanel *panel = (ErrorPanel *)(view);
121	panel->add_next_at = 0;
122	panel->alerts_displayed = 0;
123
124	view->ResizeToPreferred();
125	return false;
126}
127
128
129void
130ErrorLogWindow::FrameResized(float newWidth, float newHeight)
131{
132	ErrorPanel *panel = (ErrorPanel *)view;
133	panel->ResizeTo(newWidth, panel->add_next_at);
134	panel->FrameResized(newWidth - B_V_SCROLL_BAR_WIDTH, panel->add_next_at);
135	panel->Invalidate();
136
137	if (panel->add_next_at > newHeight) {
138		BScrollBar *bar = panel->scroll->ScrollBar(B_VERTICAL);
139
140		bar->SetRange(0, panel->add_next_at - Frame().Height());
141		bar->SetSteps(1, Frame().Height());
142		bar->SetProportion(Frame().Height() / panel->add_next_at);
143	} else
144		panel->scroll->ScrollBar(B_VERTICAL)->SetRange(0,0);
145}
146
147
148//	#pragma mark -
149
150
151Error::Error(BRect rect, alert_type atype, const char *tag, const char *message,
152	bool timestamp,rgb_color bkg)
153	:
154	BView(rect,"error",B_FOLLOW_LEFT | B_FOLLOW_RIGHT
155		| B_FOLLOW_TOP,B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS),
156	type(atype)
157{
158	SetViewColor(bkg);
159	SetLowColor(bkg);
160
161	text_run_array array;
162	array.count = 1;
163	array.runs[0].offset = 0;
164	array.runs[0].font = *be_bold_font;
165	array.runs[0].color = HighColor();
166
167	BString msgString(message);
168	msgString.RemoveAll("\r");
169
170	BTextView *view = new BTextView(BRect(20, 0, rect.Width(), rect.Height()),
171		"error_display", BRect(0,3,rect.Width() - 20 - 3, LONG_MAX),
172		B_FOLLOW_ALL_SIDES);
173	view->SetLowColor(bkg);
174	view->SetViewColor(bkg);
175	view->SetText(msgString.String());
176	view->MakeSelectable(true);
177	view->SetStylable(true);
178	view->MakeEditable(false);
179
180	if (tag != NULL) {
181		BString tagString(tag);
182		tagString += " ";
183		view->Insert(0, tagString.String(), tagString.Length(), &array);
184	}
185
186	if (timestamp) {
187		array.runs[0].color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),B_DARKEN_2_TINT);
188		array.runs[0].font.SetSize(9);
189		time_t thetime = time(NULL);
190		BString atime = asctime(localtime(&thetime));
191		atime.Prepend(" [");
192		atime.RemoveAll("\n");
193		atime.Append("]");
194		view->Insert(view->TextLength(),atime.String(),atime.Length(),&array);
195	}
196
197	float height,width;
198	width = view->Frame().Width();
199	height = view->TextHeight(0,view->CountLines()) + 3;
200	view->ResizeTo(width,height);
201	AddChild(view);
202}
203
204
205void
206Error::GetPreferredSize(float *width, float *height)
207{
208	BTextView *view = static_cast<BTextView *>(FindView("error_display"));
209
210	*width = view->Frame().Width() + 20;
211	*height = view->TextHeight(0, LONG_MAX) + 3;
212}
213
214
215void
216Error::Draw(BRect updateRect)
217{
218	FillRect(updateRect, B_SOLID_LOW);
219}
220
221
222void
223Error::FrameResized(float w, float h)
224{
225	BTextView *view = static_cast<BTextView *>(FindView("error_display"));
226
227	view->ResizeTo(w - 20, h);
228	view->SetTextRect(BRect(0, 3, w - 20, h));
229}
230