1de9dcd41SStephan Aßmus /* 2beeda306SAdrien Destugues * Copyright 2010-2011, Haiku, Inc. All Rights Reserved. 3de9dcd41SStephan Aßmus * Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved. 4de9dcd41SStephan Aßmus * Copyright 2004-2008, Michael Davidson. All Rights Reserved. 5de9dcd41SStephan Aßmus * Copyright 2004-2007, Mikael Eiman. All Rights Reserved. 6de9dcd41SStephan Aßmus * Distributed under the terms of the MIT License. 7de9dcd41SStephan Aßmus * 8de9dcd41SStephan Aßmus * Authors: 9de9dcd41SStephan Aßmus * Michael Davidson, slaad@bong.com.au 10de9dcd41SStephan Aßmus * Mikael Eiman, mikael@eiman.tv 11de9dcd41SStephan Aßmus * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com 12f33637d9SStephan Aßmus * Stephan Aßmus <superstippi@gmx.de> 13f2fc3a86SAdrien Destugues * Adrien Destugues <pulkomandy@pulkomandy.ath.cx> 14de9dcd41SStephan Aßmus */ 15de9dcd41SStephan Aßmus 16259ffc02SAlex Wilson 17259ffc02SAlex Wilson #include "NotificationView.h" 18259ffc02SAlex Wilson 19259ffc02SAlex Wilson 20259ffc02SAlex Wilson #include <Bitmap.h> 2182a67460SAdrien Destugues - PulkoMandy #include <ControlLook.h> 22e0890a26SAdrien Destugues #include <GroupLayout.h> 234ec6c3a0SAdrien Destugues #include <LayoutUtils.h> 24259ffc02SAlex Wilson #include <MessageRunner.h> 25de9dcd41SStephan Aßmus #include <Messenger.h> 26259ffc02SAlex Wilson #include <Notification.h> 274ec6c3a0SAdrien Destugues #include <Path.h> 28259ffc02SAlex Wilson #include <PropertyInfo.h> 29de9dcd41SStephan Aßmus #include <Roster.h> 30beeda306SAdrien Destugues #include <StatusBar.h> 31de9dcd41SStephan Aßmus 322a740449SFrançois Revol #include <Notifications.h> 332a740449SFrançois Revol 34f6afd3e9SRyan Leavengood #include "AppGroupView.h" 35de9dcd41SStephan Aßmus #include "NotificationWindow.h" 36de9dcd41SStephan Aßmus 37259ffc02SAlex Wilson 380e07be06SAdrien Destugues static const int kIconStripeWidth = 32; 399dcd41a8SAdrien Destugues 40de9dcd41SStephan Aßmus property_info message_prop_list[] = { 41de9dcd41SStephan Aßmus { "type", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 42de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the notification type"}, 43de9dcd41SStephan Aßmus { "app", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 44de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's app"}, 45de9dcd41SStephan Aßmus { "title", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 46de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's title"}, 47de9dcd41SStephan Aßmus { "content", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 48de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's contents"}, 49de9dcd41SStephan Aßmus { "icon", {B_GET_PROPERTY, 0}, 50de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get icon as an archived bitmap"}, 51de9dcd41SStephan Aßmus { "progress", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 52de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the progress (between 0.0 and 1.0)"}, 53de9dcd41SStephan Aßmus { NULL } 54de9dcd41SStephan Aßmus }; 55de9dcd41SStephan Aßmus 56de9dcd41SStephan Aßmus 57de9dcd41SStephan Aßmus NotificationView::NotificationView(NotificationWindow* win, 584ec6c3a0SAdrien Destugues BNotification* notification, bigtime_t timeout) 59de9dcd41SStephan Aßmus : 6044c6e69bSAdrien Destugues BView("NotificationView", B_WILL_DRAW), 61de9dcd41SStephan Aßmus fParent(win), 624ec6c3a0SAdrien Destugues fNotification(notification), 634ec6c3a0SAdrien Destugues fTimeout(timeout), 64de9dcd41SStephan Aßmus fRunner(NULL), 6582a67460SAdrien Destugues - PulkoMandy fBitmap(NULL), 6682a67460SAdrien Destugues - PulkoMandy fCloseClicked(false) 67de9dcd41SStephan Aßmus { 684ec6c3a0SAdrien Destugues if (fNotification->Icon() != NULL) 694ec6c3a0SAdrien Destugues fBitmap = new BBitmap(fNotification->Icon()); 70de9dcd41SStephan Aßmus 714ec6c3a0SAdrien Destugues if (fTimeout <= 0) 724ec6c3a0SAdrien Destugues fTimeout = fParent->Timeout() * 1000000; 73de9dcd41SStephan Aßmus 74e0890a26SAdrien Destugues BGroupLayout* layout = new BGroupLayout(B_VERTICAL); 75e0890a26SAdrien Destugues SetLayout(layout); 76e0890a26SAdrien Destugues 7748d90a50SAdrien Destugues SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 7848d90a50SAdrien Destugues SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 7948d90a50SAdrien Destugues 804ec6c3a0SAdrien Destugues switch (fNotification->Type()) { 81de9dcd41SStephan Aßmus case B_IMPORTANT_NOTIFICATION: 8248d90a50SAdrien Destugues fStripeColor = ui_color(B_CONTROL_HIGHLIGHT_COLOR); 83de9dcd41SStephan Aßmus break; 84de9dcd41SStephan Aßmus case B_ERROR_NOTIFICATION: 8548d90a50SAdrien Destugues fStripeColor = ui_color(B_FAILURE_COLOR); 86de9dcd41SStephan Aßmus break; 87beeda306SAdrien Destugues case B_PROGRESS_NOTIFICATION: 88beeda306SAdrien Destugues { 89e0890a26SAdrien Destugues BStatusBar* progress = new BStatusBar("progress"); 90beeda306SAdrien Destugues progress->SetBarHeight(12.0f); 91beeda306SAdrien Destugues progress->SetMaxValue(1.0f); 924ec6c3a0SAdrien Destugues progress->Update(fNotification->Progress()); 93beeda306SAdrien Destugues 94beeda306SAdrien Destugues BString label = ""; 954ec6c3a0SAdrien Destugues label << (int)(fNotification->Progress() * 100) << " %"; 96beeda306SAdrien Destugues progress->SetTrailingText(label); 97beeda306SAdrien Destugues 9844c6e69bSAdrien Destugues layout->AddView(progress); 99beeda306SAdrien Destugues } 10048d90a50SAdrien Destugues // fall through. 10148d90a50SAdrien Destugues case B_INFORMATION_NOTIFICATION: 10248d90a50SAdrien Destugues fStripeColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 10348d90a50SAdrien Destugues B_DARKEN_1_TINT); 10448d90a50SAdrien Destugues break; 105de9dcd41SStephan Aßmus } 106de9dcd41SStephan Aßmus } 107de9dcd41SStephan Aßmus 108de9dcd41SStephan Aßmus 109de9dcd41SStephan Aßmus NotificationView::~NotificationView() 110de9dcd41SStephan Aßmus { 111de9dcd41SStephan Aßmus delete fRunner; 112de9dcd41SStephan Aßmus delete fBitmap; 1134ec6c3a0SAdrien Destugues delete fNotification; 114de9dcd41SStephan Aßmus 115de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 116de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 117de9dcd41SStephan Aßmus delete (*lIt); 118de9dcd41SStephan Aßmus } 119de9dcd41SStephan Aßmus 120de9dcd41SStephan Aßmus 121de9dcd41SStephan Aßmus void 122de9dcd41SStephan Aßmus NotificationView::AttachedToWindow() 123de9dcd41SStephan Aßmus { 1242a740449SFrançois Revol SetText(); 1252a740449SFrançois Revol 126de9dcd41SStephan Aßmus BMessage msg(kRemoveView); 127de9dcd41SStephan Aßmus msg.AddPointer("view", this); 128de9dcd41SStephan Aßmus 1294ec6c3a0SAdrien Destugues fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1); 130de9dcd41SStephan Aßmus } 131de9dcd41SStephan Aßmus 132de9dcd41SStephan Aßmus 133de9dcd41SStephan Aßmus void 134de9dcd41SStephan Aßmus NotificationView::MessageReceived(BMessage* msg) 135de9dcd41SStephan Aßmus { 136de9dcd41SStephan Aßmus switch (msg->what) { 137de9dcd41SStephan Aßmus case B_GET_PROPERTY: 138de9dcd41SStephan Aßmus { 139de9dcd41SStephan Aßmus BMessage specifier; 140de9dcd41SStephan Aßmus const char* property; 141de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 142de9dcd41SStephan Aßmus bool msgOkay = true; 143de9dcd41SStephan Aßmus 144de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 145de9dcd41SStephan Aßmus msgOkay = false; 146de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 147de9dcd41SStephan Aßmus msgOkay = false; 148de9dcd41SStephan Aßmus 149de9dcd41SStephan Aßmus if (msgOkay) { 150de9dcd41SStephan Aßmus if (strcmp(property, "type") == 0) 1514ec6c3a0SAdrien Destugues reply.AddInt32("result", fNotification->Type()); 152de9dcd41SStephan Aßmus 1534ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 1544ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Group()); 155de9dcd41SStephan Aßmus 156de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 1574ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Title()); 158de9dcd41SStephan Aßmus 159de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 1604ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Content()); 161de9dcd41SStephan Aßmus 162de9dcd41SStephan Aßmus if (strcmp(property, "progress") == 0) 1634ec6c3a0SAdrien Destugues reply.AddFloat("result", fNotification->Progress()); 164de9dcd41SStephan Aßmus 165de9dcd41SStephan Aßmus if ((strcmp(property, "icon") == 0) && fBitmap) { 166de9dcd41SStephan Aßmus BMessage archive; 167de9dcd41SStephan Aßmus if (fBitmap->Archive(&archive) == B_OK) 168de9dcd41SStephan Aßmus reply.AddMessage("result", &archive); 169de9dcd41SStephan Aßmus } 170de9dcd41SStephan Aßmus 171de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 172de9dcd41SStephan Aßmus } else { 173de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 174de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 175de9dcd41SStephan Aßmus } 176de9dcd41SStephan Aßmus 177de9dcd41SStephan Aßmus msg->SendReply(&reply); 178de9dcd41SStephan Aßmus break; 179de9dcd41SStephan Aßmus } 180de9dcd41SStephan Aßmus case B_SET_PROPERTY: 181de9dcd41SStephan Aßmus { 182de9dcd41SStephan Aßmus BMessage specifier; 183de9dcd41SStephan Aßmus const char* property; 184de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 185de9dcd41SStephan Aßmus bool msgOkay = true; 186de9dcd41SStephan Aßmus 187de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 188de9dcd41SStephan Aßmus msgOkay = false; 189de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 190de9dcd41SStephan Aßmus msgOkay = false; 191de9dcd41SStephan Aßmus 192de9dcd41SStephan Aßmus if (msgOkay) { 1934ec6c3a0SAdrien Destugues const char* value = NULL; 1944ec6c3a0SAdrien Destugues 1954ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 1964ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 1974ec6c3a0SAdrien Destugues fNotification->SetGroup(value); 198de9dcd41SStephan Aßmus 199de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 2004ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 2014ec6c3a0SAdrien Destugues fNotification->SetTitle(value); 202de9dcd41SStephan Aßmus 203de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 2044ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 2054ec6c3a0SAdrien Destugues fNotification->SetContent(value); 206de9dcd41SStephan Aßmus 207de9dcd41SStephan Aßmus if (strcmp(property, "icon") == 0) { 208de9dcd41SStephan Aßmus BMessage archive; 209de9dcd41SStephan Aßmus if (msg->FindMessage("data", &archive) == B_OK) { 210de9dcd41SStephan Aßmus delete fBitmap; 211de9dcd41SStephan Aßmus fBitmap = new BBitmap(&archive); 212de9dcd41SStephan Aßmus } 213de9dcd41SStephan Aßmus } 214de9dcd41SStephan Aßmus 2154ec6c3a0SAdrien Destugues SetText(); 216de9dcd41SStephan Aßmus Invalidate(); 217de9dcd41SStephan Aßmus 218de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 219de9dcd41SStephan Aßmus } else { 220de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 221de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 222de9dcd41SStephan Aßmus } 223de9dcd41SStephan Aßmus 224de9dcd41SStephan Aßmus msg->SendReply(&reply); 225de9dcd41SStephan Aßmus break; 226de9dcd41SStephan Aßmus } 227de9dcd41SStephan Aßmus default: 228de9dcd41SStephan Aßmus BView::MessageReceived(msg); 229de9dcd41SStephan Aßmus } 230de9dcd41SStephan Aßmus } 231de9dcd41SStephan Aßmus 232de9dcd41SStephan Aßmus 233de9dcd41SStephan Aßmus void 234de9dcd41SStephan Aßmus NotificationView::Draw(BRect updateRect) 235de9dcd41SStephan Aßmus { 236de9dcd41SStephan Aßmus BRect progRect; 237de9dcd41SStephan Aßmus 238de9dcd41SStephan Aßmus SetDrawingMode(B_OP_ALPHA); 239de9dcd41SStephan Aßmus SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 240de9dcd41SStephan Aßmus 241de9dcd41SStephan Aßmus // Icon size 242de9dcd41SStephan Aßmus float iconSize = (float)fParent->IconSize(); 243de9dcd41SStephan Aßmus 2449dcd41a8SAdrien Destugues BRect stripeRect = Bounds(); 2450e07be06SAdrien Destugues stripeRect.right = kIconStripeWidth; 24669631a6aSAdrien Destugues SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 24769631a6aSAdrien Destugues B_DARKEN_1_TINT)); 24869631a6aSAdrien Destugues FillRect(stripeRect); 24969631a6aSAdrien Destugues 25048d90a50SAdrien Destugues SetHighColor(fStripeColor); 25169631a6aSAdrien Destugues stripeRect.right = 2; 2529dcd41a8SAdrien Destugues FillRect(stripeRect); 2539dcd41a8SAdrien Destugues 2549dcd41a8SAdrien Destugues SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); 255de9dcd41SStephan Aßmus // Rectangle for icon and overlay icon 256de9dcd41SStephan Aßmus BRect iconRect(0, 0, 0, 0); 257de9dcd41SStephan Aßmus 258de9dcd41SStephan Aßmus // Draw icon 259de9dcd41SStephan Aßmus if (fBitmap) { 2605414f4dcSAdrien Destugues float ix = 18; 2615414f4dcSAdrien Destugues float iy = (Bounds().Height() - iconSize) / 4.0; 2620e07be06SAdrien Destugues // Icon is vertically centered in view 263de9dcd41SStephan Aßmus 2644ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) 2650e07be06SAdrien Destugues { 266de9dcd41SStephan Aßmus // Move icon up by half progress bar height if it's present 2670e07be06SAdrien Destugues iy -= (progRect.Height() + kEdgePadding); 2680e07be06SAdrien Destugues } 269de9dcd41SStephan Aßmus 2707dd47a9bSPhilippe Houdoin iconRect.Set(ix, iy, ix + iconSize - 1.0, iy + iconSize - 1.0); 271bdde2d30SPhilippe Houdoin DrawBitmapAsync(fBitmap, fBitmap->Bounds(), iconRect); 272de9dcd41SStephan Aßmus } 273de9dcd41SStephan Aßmus 274de9dcd41SStephan Aßmus // Draw content 275de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 276de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) { 277de9dcd41SStephan Aßmus LineInfo *l = (*lIt); 278de9dcd41SStephan Aßmus 279de9dcd41SStephan Aßmus SetFont(&l->font); 28063a4690eSAdrien Destugues // Truncate the string. We have already line-wrapped the text but if 28163a4690eSAdrien Destugues // there is a very long 'word' we can only truncate it. 28263a4690eSAdrien Destugues TruncateString(&(l->text), B_TRUNCATE_END, 28384e1c7faSAdrien Destugues Bounds().Width() - l->location.x); 284de9dcd41SStephan Aßmus DrawString(l->text.String(), l->text.Length(), l->location); 285de9dcd41SStephan Aßmus } 286de9dcd41SStephan Aßmus 287de9dcd41SStephan Aßmus rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR); 288de9dcd41SStephan Aßmus detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT); 289de9dcd41SStephan Aßmus 290f6afd3e9SRyan Leavengood AppGroupView* groupView = dynamic_cast<AppGroupView*>(Parent()); 291f6afd3e9SRyan Leavengood if (groupView != NULL && groupView->ChildrenCount() > 1) 29282a67460SAdrien Destugues - PulkoMandy _DrawCloseButton(updateRect); 293de9dcd41SStephan Aßmus 2945414f4dcSAdrien Destugues SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 29544c6e69bSAdrien Destugues BPoint left(Bounds().left, Bounds().top); 29644c6e69bSAdrien Destugues BPoint right(Bounds().right, Bounds().top); 2975414f4dcSAdrien Destugues StrokeLine(left, right); 2985414f4dcSAdrien Destugues 299de9dcd41SStephan Aßmus Sync(); 300de9dcd41SStephan Aßmus } 301de9dcd41SStephan Aßmus 302de9dcd41SStephan Aßmus 303de9dcd41SStephan Aßmus void 30482a67460SAdrien Destugues - PulkoMandy NotificationView::_DrawCloseButton(const BRect& updateRect) 30582a67460SAdrien Destugues - PulkoMandy { 30682a67460SAdrien Destugues - PulkoMandy PushState(); 30782a67460SAdrien Destugues - PulkoMandy BRect closeRect = Bounds(); 30882a67460SAdrien Destugues - PulkoMandy 30982a67460SAdrien Destugues - PulkoMandy closeRect.InsetBy(3 * kEdgePadding, 3 * kEdgePadding); 31082a67460SAdrien Destugues - PulkoMandy closeRect.left = closeRect.right - kCloseSize; 31182a67460SAdrien Destugues - PulkoMandy closeRect.bottom = closeRect.top + kCloseSize; 31282a67460SAdrien Destugues - PulkoMandy 31382a67460SAdrien Destugues - PulkoMandy rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 31482a67460SAdrien Destugues - PulkoMandy float tint = B_DARKEN_2_TINT; 31582a67460SAdrien Destugues - PulkoMandy 31682a67460SAdrien Destugues - PulkoMandy if (fCloseClicked) { 31782a67460SAdrien Destugues - PulkoMandy BRect buttonRect(closeRect.InsetByCopy(-4, -4)); 31882a67460SAdrien Destugues - PulkoMandy be_control_look->DrawButtonFrame(this, buttonRect, updateRect, 31982a67460SAdrien Destugues - PulkoMandy base, base, 32082a67460SAdrien Destugues - PulkoMandy BControlLook::B_ACTIVATED | BControlLook::B_BLEND_FRAME); 32182a67460SAdrien Destugues - PulkoMandy be_control_look->DrawButtonBackground(this, buttonRect, updateRect, 32282a67460SAdrien Destugues - PulkoMandy base, BControlLook::B_ACTIVATED); 32382a67460SAdrien Destugues - PulkoMandy tint *= 1.2; 32482a67460SAdrien Destugues - PulkoMandy closeRect.OffsetBy(1, 1); 32582a67460SAdrien Destugues - PulkoMandy } 32682a67460SAdrien Destugues - PulkoMandy 32782a67460SAdrien Destugues - PulkoMandy base = tint_color(base, tint); 32882a67460SAdrien Destugues - PulkoMandy SetHighColor(base); 32982a67460SAdrien Destugues - PulkoMandy SetPenSize(2); 33082a67460SAdrien Destugues - PulkoMandy StrokeLine(closeRect.LeftTop(), closeRect.RightBottom()); 33182a67460SAdrien Destugues - PulkoMandy StrokeLine(closeRect.LeftBottom(), closeRect.RightTop()); 33282a67460SAdrien Destugues - PulkoMandy PopState(); 33382a67460SAdrien Destugues - PulkoMandy } 33482a67460SAdrien Destugues - PulkoMandy 33582a67460SAdrien Destugues - PulkoMandy 33682a67460SAdrien Destugues - PulkoMandy void 337de9dcd41SStephan Aßmus NotificationView::MouseDown(BPoint point) 338de9dcd41SStephan Aßmus { 339de9dcd41SStephan Aßmus int32 buttons; 340de9dcd41SStephan Aßmus Window()->CurrentMessage()->FindInt32("buttons", &buttons); 341de9dcd41SStephan Aßmus 342de9dcd41SStephan Aßmus switch (buttons) { 343de9dcd41SStephan Aßmus case B_PRIMARY_MOUSE_BUTTON: 344de9dcd41SStephan Aßmus { 345de9dcd41SStephan Aßmus BRect closeRect = Bounds().InsetByCopy(2,2); 346de9dcd41SStephan Aßmus closeRect.left = closeRect.right - kCloseSize; 347de9dcd41SStephan Aßmus closeRect.bottom = closeRect.top + kCloseSize; 348de9dcd41SStephan Aßmus 349de9dcd41SStephan Aßmus if (!closeRect.Contains(point)) { 350de9dcd41SStephan Aßmus entry_ref launchRef; 351de9dcd41SStephan Aßmus BString launchString; 352de9dcd41SStephan Aßmus BMessage argMsg(B_ARGV_RECEIVED); 353de9dcd41SStephan Aßmus BMessage refMsg(B_REFS_RECEIVED); 354de9dcd41SStephan Aßmus entry_ref appRef; 355de9dcd41SStephan Aßmus bool useArgv = false; 356de9dcd41SStephan Aßmus BList messages; 357de9dcd41SStephan Aßmus entry_ref ref; 358de9dcd41SStephan Aßmus 3594ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL 3604ec6c3a0SAdrien Destugues && be_roster->FindApp(fNotification->OnClickApp(), &appRef) 3614ec6c3a0SAdrien Destugues == B_OK) { 362de9dcd41SStephan Aßmus useArgv = true; 363de9dcd41SStephan Aßmus } 364de9dcd41SStephan Aßmus 3654ec6c3a0SAdrien Destugues if (fNotification->OnClickFile() != NULL 3664ec6c3a0SAdrien Destugues && be_roster->FindApp( 3674ec6c3a0SAdrien Destugues (entry_ref*)fNotification->OnClickFile(), &appRef) 3684ec6c3a0SAdrien Destugues == B_OK) { 3694ec6c3a0SAdrien Destugues useArgv = true; 3704ec6c3a0SAdrien Destugues } 371de9dcd41SStephan Aßmus 3724ec6c3a0SAdrien Destugues for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++) 3734ec6c3a0SAdrien Destugues refMsg.AddRef("refs", fNotification->OnClickRefAt(i)); 374de9dcd41SStephan Aßmus messages.AddItem((void*)&refMsg); 375de9dcd41SStephan Aßmus 376de9dcd41SStephan Aßmus if (useArgv) { 3774ec6c3a0SAdrien Destugues int32 argc = fNotification->CountOnClickArgs() + 1; 378de9dcd41SStephan Aßmus BString arg; 379de9dcd41SStephan Aßmus 380de9dcd41SStephan Aßmus BPath p(&appRef); 381de9dcd41SStephan Aßmus argMsg.AddString("argv", p.Path()); 382de9dcd41SStephan Aßmus 3834ec6c3a0SAdrien Destugues argMsg.AddInt32("argc", argc); 384de9dcd41SStephan Aßmus 3854ec6c3a0SAdrien Destugues for (int32 i = 0; i < argc - 1; i++) { 3864ec6c3a0SAdrien Destugues argMsg.AddString("argv", 3874ec6c3a0SAdrien Destugues fNotification->OnClickArgAt(i)); 3884ec6c3a0SAdrien Destugues } 389de9dcd41SStephan Aßmus 390de9dcd41SStephan Aßmus messages.AddItem((void*)&argMsg); 391de9dcd41SStephan Aßmus } 392de9dcd41SStephan Aßmus 3934ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL) 3944ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickApp(), &messages); 395de9dcd41SStephan Aßmus else 3964ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickFile(), &messages); 39782a67460SAdrien Destugues - PulkoMandy } else { 39882a67460SAdrien Destugues - PulkoMandy fCloseClicked = true; 399de9dcd41SStephan Aßmus } 400de9dcd41SStephan Aßmus 401de9dcd41SStephan Aßmus // Remove the info view after a click 402de9dcd41SStephan Aßmus BMessage remove_msg(kRemoveView); 403de9dcd41SStephan Aßmus remove_msg.AddPointer("view", this); 404de9dcd41SStephan Aßmus 405de9dcd41SStephan Aßmus BMessenger msgr(Parent()); 406de9dcd41SStephan Aßmus msgr.SendMessage(&remove_msg); 407de9dcd41SStephan Aßmus break; 408de9dcd41SStephan Aßmus } 409de9dcd41SStephan Aßmus } 410de9dcd41SStephan Aßmus } 411de9dcd41SStephan Aßmus 412de9dcd41SStephan Aßmus 413de9dcd41SStephan Aßmus BHandler* 4144ec6c3a0SAdrien Destugues NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, 4154ec6c3a0SAdrien Destugues int32 form, const char* prop) 416de9dcd41SStephan Aßmus { 417de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 418de9dcd41SStephan Aßmus if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) { 419de9dcd41SStephan Aßmus msg->PopSpecifier(); 420de9dcd41SStephan Aßmus return this; 421de9dcd41SStephan Aßmus } 422de9dcd41SStephan Aßmus 423de9dcd41SStephan Aßmus return BView::ResolveSpecifier(msg, index, spec, form, prop); 424de9dcd41SStephan Aßmus } 425de9dcd41SStephan Aßmus 426de9dcd41SStephan Aßmus 427de9dcd41SStephan Aßmus status_t 428de9dcd41SStephan Aßmus NotificationView::GetSupportedSuites(BMessage* msg) 429de9dcd41SStephan Aßmus { 430de9dcd41SStephan Aßmus msg->AddString("suites", "suite/x-vnd.Haiku-notification_server"); 431de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 432de9dcd41SStephan Aßmus msg->AddFlat("messages", &prop_info); 433de9dcd41SStephan Aßmus return BView::GetSupportedSuites(msg); 434de9dcd41SStephan Aßmus } 435de9dcd41SStephan Aßmus 436de9dcd41SStephan Aßmus 437de9dcd41SStephan Aßmus void 4384ec6c3a0SAdrien Destugues NotificationView::SetText(float newMaxWidth) 439de9dcd41SStephan Aßmus { 4402a740449SFrançois Revol if (newMaxWidth < 0 && Parent()) 4412a740449SFrançois Revol newMaxWidth = Parent()->Bounds().IntegerWidth(); 4422a740449SFrançois Revol if (newMaxWidth <= 0) 4432a740449SFrançois Revol newMaxWidth = kDefaultWidth; 444de9dcd41SStephan Aßmus 445de9dcd41SStephan Aßmus // Delete old lines 446de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 447de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 448de9dcd41SStephan Aßmus delete (*lIt); 449de9dcd41SStephan Aßmus fLines.clear(); 450de9dcd41SStephan Aßmus 4510e07be06SAdrien Destugues float iconRight = kIconStripeWidth; 452de9dcd41SStephan Aßmus if (fBitmap != NULL) 4535414f4dcSAdrien Destugues iconRight += fParent->IconSize(); 4540e07be06SAdrien Destugues else 4555414f4dcSAdrien Destugues iconRight += 32; 456de9dcd41SStephan Aßmus 457de9dcd41SStephan Aßmus font_height fh; 458de9dcd41SStephan Aßmus be_bold_font->GetHeight(&fh); 459de9dcd41SStephan Aßmus float fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 460de9dcd41SStephan Aßmus + ceilf(fh.ascent); 4610e07be06SAdrien Destugues float y = 2 * fontHeight; 462de9dcd41SStephan Aßmus 463de9dcd41SStephan Aßmus // Title 464de9dcd41SStephan Aßmus LineInfo* titleLine = new LineInfo; 4654ec6c3a0SAdrien Destugues titleLine->text = fNotification->Title(); 466de9dcd41SStephan Aßmus titleLine->font = *be_bold_font; 467de9dcd41SStephan Aßmus 468*569a7bfcSAdrien Destugues titleLine->location = BPoint(iconRight + kEdgePadding, y); 469de9dcd41SStephan Aßmus 470de9dcd41SStephan Aßmus fLines.push_front(titleLine); 471de9dcd41SStephan Aßmus y += fontHeight; 472de9dcd41SStephan Aßmus 473de9dcd41SStephan Aßmus // Rest of text is rendered with be_plain_font. 474de9dcd41SStephan Aßmus be_plain_font->GetHeight(&fh); 475de9dcd41SStephan Aßmus fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 476de9dcd41SStephan Aßmus + ceilf(fh.ascent); 477de9dcd41SStephan Aßmus 478de9dcd41SStephan Aßmus // Split text into chunks between certain characters and compose the lines. 479e0890a26SAdrien Destugues const char kSeparatorCharacters[] = " \n-\\"; 4804ec6c3a0SAdrien Destugues BString textBuffer = fNotification->Content(); 481de9dcd41SStephan Aßmus textBuffer.ReplaceAll("\t", " "); 482de9dcd41SStephan Aßmus const char* chunkStart = textBuffer.String(); 483de9dcd41SStephan Aßmus float maxWidth = newMaxWidth - kEdgePadding - iconRight; 484de9dcd41SStephan Aßmus LineInfo* line = NULL; 485de9dcd41SStephan Aßmus ssize_t length = textBuffer.Length(); 486de9dcd41SStephan Aßmus while (chunkStart - textBuffer.String() < length) { 487de9dcd41SStephan Aßmus size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1; 488de9dcd41SStephan Aßmus 4894ec6c3a0SAdrien Destugues // Start a new line if we didn't start one before 49031a3c4e8SJérôme Duval BString tempText; 49131a3c4e8SJérôme Duval if (line != NULL) 49231a3c4e8SJérôme Duval tempText.SetTo(line->text); 493de9dcd41SStephan Aßmus tempText.Append(chunkStart, chunkLength); 494de9dcd41SStephan Aßmus 495de9dcd41SStephan Aßmus if (line == NULL || chunkStart[0] == '\n' 496de9dcd41SStephan Aßmus || StringWidth(tempText) > maxWidth) { 497de9dcd41SStephan Aßmus line = new LineInfo; 498de9dcd41SStephan Aßmus line->font = *be_plain_font; 499de9dcd41SStephan Aßmus line->location = BPoint(iconRight + kEdgePadding, y); 500de9dcd41SStephan Aßmus 501de9dcd41SStephan Aßmus fLines.push_front(line); 502de9dcd41SStephan Aßmus y += fontHeight; 503de9dcd41SStephan Aßmus 5044ec6c3a0SAdrien Destugues // Skip the eventual new-line character at the beginning of this chunk 505de9dcd41SStephan Aßmus if (chunkStart[0] == '\n') { 506de9dcd41SStephan Aßmus chunkStart++; 507de9dcd41SStephan Aßmus chunkLength--; 508de9dcd41SStephan Aßmus } 5094ec6c3a0SAdrien Destugues 5104ec6c3a0SAdrien Destugues // Skip more new-line characters and move the line further down 511de9dcd41SStephan Aßmus while (chunkStart[0] == '\n') { 512de9dcd41SStephan Aßmus chunkStart++; 513de9dcd41SStephan Aßmus chunkLength--; 514de9dcd41SStephan Aßmus line->location.y += fontHeight; 515de9dcd41SStephan Aßmus y += fontHeight; 516de9dcd41SStephan Aßmus } 5174ec6c3a0SAdrien Destugues 5184ec6c3a0SAdrien Destugues // Strip space at beginning of a new line 519de9dcd41SStephan Aßmus while (chunkStart[0] == ' ') { 520de9dcd41SStephan Aßmus chunkLength--; 521de9dcd41SStephan Aßmus chunkStart++; 522de9dcd41SStephan Aßmus } 523de9dcd41SStephan Aßmus } 524de9dcd41SStephan Aßmus 525de9dcd41SStephan Aßmus if (chunkStart[0] == '\0') 526de9dcd41SStephan Aßmus break; 527de9dcd41SStephan Aßmus 528de9dcd41SStephan Aßmus // Append the chunk to the current line, which was either a new 5294ec6c3a0SAdrien Destugues // line or the one from the previous iteration 530de9dcd41SStephan Aßmus line->text.Append(chunkStart, chunkLength); 531de9dcd41SStephan Aßmus 532de9dcd41SStephan Aßmus chunkStart += chunkLength; 533de9dcd41SStephan Aßmus } 534de9dcd41SStephan Aßmus 535de9dcd41SStephan Aßmus fHeight = y + (kEdgePadding * 2); 536de9dcd41SStephan Aßmus 537de9dcd41SStephan Aßmus // Make sure icon fits 538de9dcd41SStephan Aßmus if (fBitmap != NULL) { 5394ec6c3a0SAdrien Destugues float minHeight = fBitmap->Bounds().Height() + 2 * kEdgePadding; 540de9dcd41SStephan Aßmus 541de9dcd41SStephan Aßmus if (fHeight < minHeight) 542de9dcd41SStephan Aßmus fHeight = minHeight; 543de9dcd41SStephan Aßmus } 544e0890a26SAdrien Destugues 545e0890a26SAdrien Destugues // Make sure the progress bar is below the text, and the window is big 546e0890a26SAdrien Destugues // enough. 547e0890a26SAdrien Destugues static_cast<BGroupLayout*>(GetLayout())->SetInsets(kIconStripeWidth + 8, 548e0890a26SAdrien Destugues fHeight, 8, 8); 54944c6e69bSAdrien Destugues 55044c6e69bSAdrien Destugues _CalculateSize(); 551de9dcd41SStephan Aßmus } 552de9dcd41SStephan Aßmus 553de9dcd41SStephan Aßmus 554de9dcd41SStephan Aßmus const char* 5554ec6c3a0SAdrien Destugues NotificationView::MessageID() const 556de9dcd41SStephan Aßmus { 5574ec6c3a0SAdrien Destugues return fNotification->MessageID(); 558de9dcd41SStephan Aßmus } 559de9dcd41SStephan Aßmus 560de9dcd41SStephan Aßmus 561c2fbfb1dSAlex Wilson void 5624ec6c3a0SAdrien Destugues NotificationView::_CalculateSize() 563de9dcd41SStephan Aßmus { 564c2fbfb1dSAlex Wilson float height = fHeight; 5654ec6c3a0SAdrien Destugues 5664ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) { 5674ec6c3a0SAdrien Destugues font_height fh; 5684ec6c3a0SAdrien Destugues be_plain_font->GetHeight(&fh); 5694ec6c3a0SAdrien Destugues float fontHeight = fh.ascent + fh.descent + fh.leading; 570c2fbfb1dSAlex Wilson height += 9 + (kSmallPadding * 2) + (kEdgePadding * 1) 57144c6e69bSAdrien Destugues + fontHeight * 2; 572de9dcd41SStephan Aßmus } 573de9dcd41SStephan Aßmus 574c2fbfb1dSAlex Wilson SetExplicitMinSize(BSize(0, height)); 575c2fbfb1dSAlex Wilson SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, height)); 576de9dcd41SStephan Aßmus } 577