#include <ControlLook.h>
#include <ScrollView.h>
#include <String.h>
#include <TextView.h>
#include <limits.h>
#include "ErrorLogWindow.h"
class Error : public BView {
public:
Error(BRect rect, alert_type type, const char *tag, const char *message, bool timestamp,
rgb_color backgroundColor, rgb_color foregroundColor);
void GetPreferredSize(float *width, float *height);
void Draw(BRect updateRect);
void FrameResized(float w, float h);
private:
alert_type type;
};
class ErrorPanel : public BView {
public:
ErrorPanel(BRect rect) : BView(rect, "ErrorScrollPanel", B_FOLLOW_ALL_SIDES,
B_DRAW_ON_CHILDREN | B_FRAME_EVENTS), alerts_displayed(0), add_next_at(0)
{
AdoptSystemColors();
}
void GetPreferredSize(float *width, float *height) {
*width = Bounds().Width();
*height = add_next_at;
}
void TargetedByScrollView(BScrollView *scroll_view)
{
scroll = scroll_view;
}
void FrameResized(float w, float ) {
add_next_at = 0;
for (int32 i = 0; i < CountChildren(); i++) {
ChildAt(i)->MoveTo(BPoint(0,add_next_at));
ChildAt(i)->ResizeTo(w, ChildAt(i)->Frame().Height());
ChildAt(i)->ResizeToPreferred();
add_next_at += ChildAt(i)->Bounds().Height();
}
}
int32 alerts_displayed;
float add_next_at;
BScrollView *scroll;
};
ErrorLogWindow::ErrorLogWindow(BRect rect, const char *name, window_type type)
:
BWindow(rect, name, type, B_NO_WORKSPACE_ACTIVATION | B_NOT_MINIMIZABLE
| B_ASYNCHRONOUS_CONTROLS),
fIsRunning(false)
{
SetColumnColors(ui_color(B_LIST_BACKGROUND_COLOR));
fTextColor = ui_color(B_LIST_ITEM_TEXT_COLOR);
rect = Bounds();
rect.right -= be_control_look->GetScrollBarWidth(B_VERTICAL);
view = new ErrorPanel(rect);
AddChild(new BScrollView("ErrorScroller", view, B_FOLLOW_ALL_SIDES, 0, false, true));
Show();
Hide();
}
void
ErrorLogWindow::AddError(alert_type type, const char *message, const char *tag, bool timestamp)
{
ErrorPanel *panel = (ErrorPanel *)view;
if (!fIsRunning) {
fIsRunning = true;
Show();
}
Lock();
Error *newError = new Error(BRect(0, panel->add_next_at, panel->Bounds().right,
panel->add_next_at + 1), type, tag, message, timestamp,
(panel->alerts_displayed++ % 2 == 0) ? fColumnColor : fColumnAlternateColor, fTextColor);
newError->ResizeToPreferred();
panel->add_next_at += newError->Bounds().Height();
panel->AddChild(newError);
panel->ResizeToPreferred();
if (panel->add_next_at > Frame().Height()) {
BScrollBar *bar = panel->scroll->ScrollBar(B_VERTICAL);
bar->SetRange(0, panel->add_next_at - Frame().Height());
bar->SetSteps(1, Frame().Height());
bar->SetProportion(Frame().Height() / panel->add_next_at);
} else
panel->scroll->ScrollBar(B_VERTICAL)->SetRange(0,0);
if (IsHidden())
Show();
Unlock();
}
void
ErrorLogWindow::MessageReceived(BMessage* message)
{
rgb_color color;
if (message->what == B_COLORS_UPDATED) {
if (message->FindColor(ui_color_name(B_LIST_BACKGROUND_COLOR), &color) == B_OK)
SetColumnColors(color);
if (message->FindColor(ui_color_name(B_LIST_ITEM_TEXT_COLOR), &color) == B_OK)
fTextColor = color;
}
BWindow::MessageReceived(message);
}
bool
ErrorLogWindow::QuitRequested()
{
Hide();
while (view->CountChildren() != 0) {
BView* child = view->ChildAt(0);
view->RemoveChild(child);
delete child;
}
ErrorPanel *panel = (ErrorPanel *)(view);
panel->add_next_at = 0;
panel->alerts_displayed = 0;
view->ResizeToPreferred();
return false;
}
void
ErrorLogWindow::FrameResized(float newWidth, float newHeight)
{
ErrorPanel *panel = (ErrorPanel *)view;
panel->Invalidate();
if (panel->add_next_at > newHeight) {
BScrollBar *bar = panel->scroll->ScrollBar(B_VERTICAL);
bar->SetRange(0, panel->add_next_at - Frame().Height());
bar->SetSteps(1, Frame().Height());
bar->SetProportion(Frame().Height() / panel->add_next_at);
} else
panel->scroll->ScrollBar(B_VERTICAL)->SetRange(0,0);
}
void
ErrorLogWindow::SetColumnColors(rgb_color color)
{
fColumnColor = color;
if (fColumnColor.IsDark())
fColumnAlternateColor = tint_color(color, 0.85f);
else
fColumnAlternateColor = tint_color(color, B_DARKEN_2_TINT);
}
Error::Error(BRect rect, alert_type atype, const char *tag, const char *message,
bool timestamp, rgb_color backgroundColor, rgb_color foregroundColor)
:
BView(rect,"error", B_FOLLOW_LEFT | B_FOLLOW_RIGHT | B_FOLLOW_TOP,
B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS), type(atype)
{
SetViewColor(backgroundColor);
SetLowColor(backgroundColor);
text_run_array array;
array.count = 1;
array.runs[0].offset = 0;
array.runs[0].font = *be_bold_font;
array.runs[0].color = foregroundColor;
BString msgString(message);
msgString.RemoveAll("\r");
BTextView *view = new BTextView(BRect(20, 0, rect.Width(), rect.Height()),
"error_display", BRect(0,3,rect.Width() - 20 - 3, LONG_MAX),
B_FOLLOW_ALL_SIDES);
view->SetLowColor(backgroundColor);
view->SetViewColor(backgroundColor);
view->SetText(msgString.String());
view->MakeSelectable(true);
view->SetStylable(true);
view->MakeEditable(false);
if (tag != NULL) {
BString tagString(tag);
tagString += " ";
view->Insert(0, tagString.String(), tagString.Length(), &array);
}
if (timestamp) {
array.runs[0].color = foregroundColor.IsLight()
? tint_color(foregroundColor, B_LIGHTEN_1_TINT)
: tint_color(foregroundColor, B_DARKEN_2_TINT);
array.runs[0].font.SetSize(9);
time_t thetime = time(NULL);
BString atime = asctime(localtime(&thetime));
atime.Prepend(" [");
atime.RemoveAll("\n");
atime.Append("]");
view->Insert(view->TextLength(),atime.String(),atime.Length(),&array);
}
float height,width;
width = view->Frame().Width();
height = view->TextHeight(0,view->CountLines()) + 3;
view->ResizeTo(width,height);
AddChild(view);
}
void
Error::GetPreferredSize(float *width, float *height)
{
BTextView *view = static_cast<BTextView *>(FindView("error_display"));
*width = view->Frame().Width() + 20;
*height = view->TextHeight(0, INT32_MAX) + 3;
}
void
Error::Draw(BRect updateRect)
{
FillRect(updateRect, B_SOLID_LOW);
}
void
Error::FrameResized(float w, float h)
{
BTextView *view = static_cast<BTextView *>(FindView("error_display"));
view->ResizeTo(w - 20, h);
view->SetTextRect(BRect(0, 3, w - 20, h));
}