1de9dcd41SStephan Aßmus /* 2*6aa05872SBrian Hill * Copyright 2010-2017, 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> 14*6aa05872SBrian Hill * Brian Hill, supernova@tycho.email 15de9dcd41SStephan Aßmus */ 16de9dcd41SStephan Aßmus 17259ffc02SAlex Wilson 18259ffc02SAlex Wilson #include "NotificationView.h" 19259ffc02SAlex Wilson 20259ffc02SAlex Wilson 21259ffc02SAlex Wilson #include <Bitmap.h> 2282a67460SAdrien Destugues - PulkoMandy #include <ControlLook.h> 23e0890a26SAdrien Destugues #include <GroupLayout.h> 244ec6c3a0SAdrien Destugues #include <LayoutUtils.h> 25259ffc02SAlex Wilson #include <MessageRunner.h> 26de9dcd41SStephan Aßmus #include <Messenger.h> 27259ffc02SAlex Wilson #include <Notification.h> 284ec6c3a0SAdrien Destugues #include <Path.h> 29259ffc02SAlex Wilson #include <PropertyInfo.h> 30de9dcd41SStephan Aßmus #include <Roster.h> 31beeda306SAdrien Destugues #include <StatusBar.h> 32de9dcd41SStephan Aßmus 332a740449SFrançois Revol #include <Notifications.h> 342a740449SFrançois Revol 35f6afd3e9SRyan Leavengood #include "AppGroupView.h" 36de9dcd41SStephan Aßmus #include "NotificationWindow.h" 37de9dcd41SStephan Aßmus 38259ffc02SAlex Wilson 39*6aa05872SBrian Hill const int kIconStripeWidth = 32; 40*6aa05872SBrian Hill const float kCloseSize = 6; 41*6aa05872SBrian Hill const float kEdgePadding = 2; 42*6aa05872SBrian Hill const float kSmallPadding = 2; 439dcd41a8SAdrien Destugues 44de9dcd41SStephan Aßmus property_info message_prop_list[] = { 45de9dcd41SStephan Aßmus { "type", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 46de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the notification type"}, 47de9dcd41SStephan Aßmus { "app", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 48de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's app"}, 49de9dcd41SStephan Aßmus { "title", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 50de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's title"}, 51de9dcd41SStephan Aßmus { "content", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 52de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's contents"}, 53de9dcd41SStephan Aßmus { "icon", {B_GET_PROPERTY, 0}, 54de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get icon as an archived bitmap"}, 55de9dcd41SStephan Aßmus { "progress", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 56de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the progress (between 0.0 and 1.0)"}, 57de9dcd41SStephan Aßmus { NULL } 58de9dcd41SStephan Aßmus }; 59de9dcd41SStephan Aßmus 60de9dcd41SStephan Aßmus 61*6aa05872SBrian Hill NotificationView::NotificationView(BNotification* notification, bigtime_t timeout, 62*6aa05872SBrian Hill float iconSize, bool disableTimeout) 63de9dcd41SStephan Aßmus : 6444c6e69bSAdrien Destugues BView("NotificationView", B_WILL_DRAW), 654ec6c3a0SAdrien Destugues fNotification(notification), 664ec6c3a0SAdrien Destugues fTimeout(timeout), 67*6aa05872SBrian Hill fIconSize(iconSize), 68*6aa05872SBrian Hill fDisableTimeout(disableTimeout), 69de9dcd41SStephan Aßmus fRunner(NULL), 7082a67460SAdrien Destugues - PulkoMandy fBitmap(NULL), 71*6aa05872SBrian Hill fCloseClicked(false), 72*6aa05872SBrian Hill fPreviewModeOn(false) 73de9dcd41SStephan Aßmus { 744ec6c3a0SAdrien Destugues if (fNotification->Icon() != NULL) 754ec6c3a0SAdrien Destugues fBitmap = new BBitmap(fNotification->Icon()); 76de9dcd41SStephan Aßmus 77e0890a26SAdrien Destugues BGroupLayout* layout = new BGroupLayout(B_VERTICAL); 78e0890a26SAdrien Destugues SetLayout(layout); 79e0890a26SAdrien Destugues 801a8c00c1Slooncraz SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 8148d90a50SAdrien Destugues SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 8248d90a50SAdrien Destugues 834ec6c3a0SAdrien Destugues switch (fNotification->Type()) { 84de9dcd41SStephan Aßmus case B_IMPORTANT_NOTIFICATION: 8548d90a50SAdrien Destugues fStripeColor = ui_color(B_CONTROL_HIGHLIGHT_COLOR); 86de9dcd41SStephan Aßmus break; 87de9dcd41SStephan Aßmus case B_ERROR_NOTIFICATION: 8848d90a50SAdrien Destugues fStripeColor = ui_color(B_FAILURE_COLOR); 89de9dcd41SStephan Aßmus break; 90beeda306SAdrien Destugues case B_PROGRESS_NOTIFICATION: 91beeda306SAdrien Destugues { 92e0890a26SAdrien Destugues BStatusBar* progress = new BStatusBar("progress"); 93beeda306SAdrien Destugues progress->SetBarHeight(12.0f); 94beeda306SAdrien Destugues progress->SetMaxValue(1.0f); 954ec6c3a0SAdrien Destugues progress->Update(fNotification->Progress()); 96beeda306SAdrien Destugues 97beeda306SAdrien Destugues BString label = ""; 984ec6c3a0SAdrien Destugues label << (int)(fNotification->Progress() * 100) << " %"; 99beeda306SAdrien Destugues progress->SetTrailingText(label); 100beeda306SAdrien Destugues 10144c6e69bSAdrien Destugues layout->AddView(progress); 102beeda306SAdrien Destugues } 10348d90a50SAdrien Destugues // fall through. 10448d90a50SAdrien Destugues case B_INFORMATION_NOTIFICATION: 10548d90a50SAdrien Destugues fStripeColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 10648d90a50SAdrien Destugues B_DARKEN_1_TINT); 10748d90a50SAdrien Destugues break; 108de9dcd41SStephan Aßmus } 109de9dcd41SStephan Aßmus } 110de9dcd41SStephan Aßmus 111de9dcd41SStephan Aßmus 112de9dcd41SStephan Aßmus NotificationView::~NotificationView() 113de9dcd41SStephan Aßmus { 114de9dcd41SStephan Aßmus delete fRunner; 115de9dcd41SStephan Aßmus delete fBitmap; 1164ec6c3a0SAdrien Destugues delete fNotification; 117de9dcd41SStephan Aßmus 118de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 119de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 120de9dcd41SStephan Aßmus delete (*lIt); 121de9dcd41SStephan Aßmus } 122de9dcd41SStephan Aßmus 123de9dcd41SStephan Aßmus 124de9dcd41SStephan Aßmus void 125de9dcd41SStephan Aßmus NotificationView::AttachedToWindow() 126de9dcd41SStephan Aßmus { 1272a740449SFrançois Revol SetText(); 1282a740449SFrançois Revol 129*6aa05872SBrian Hill if (!fDisableTimeout) { 130de9dcd41SStephan Aßmus BMessage msg(kRemoveView); 131de9dcd41SStephan Aßmus msg.AddPointer("view", this); 1324ec6c3a0SAdrien Destugues fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1); 133de9dcd41SStephan Aßmus } 134*6aa05872SBrian Hill } 135de9dcd41SStephan Aßmus 136de9dcd41SStephan Aßmus 137de9dcd41SStephan Aßmus void 138de9dcd41SStephan Aßmus NotificationView::MessageReceived(BMessage* msg) 139de9dcd41SStephan Aßmus { 140de9dcd41SStephan Aßmus switch (msg->what) { 141de9dcd41SStephan Aßmus case B_GET_PROPERTY: 142de9dcd41SStephan Aßmus { 143de9dcd41SStephan Aßmus BMessage specifier; 144de9dcd41SStephan Aßmus const char* property; 145de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 146de9dcd41SStephan Aßmus bool msgOkay = true; 147de9dcd41SStephan Aßmus 148de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 149de9dcd41SStephan Aßmus msgOkay = false; 150de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 151de9dcd41SStephan Aßmus msgOkay = false; 152de9dcd41SStephan Aßmus 153de9dcd41SStephan Aßmus if (msgOkay) { 154de9dcd41SStephan Aßmus if (strcmp(property, "type") == 0) 1554ec6c3a0SAdrien Destugues reply.AddInt32("result", fNotification->Type()); 156de9dcd41SStephan Aßmus 1574ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 1584ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Group()); 159de9dcd41SStephan Aßmus 160de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 1614ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Title()); 162de9dcd41SStephan Aßmus 163de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 1644ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Content()); 165de9dcd41SStephan Aßmus 166de9dcd41SStephan Aßmus if (strcmp(property, "progress") == 0) 1674ec6c3a0SAdrien Destugues reply.AddFloat("result", fNotification->Progress()); 168de9dcd41SStephan Aßmus 169de9dcd41SStephan Aßmus if ((strcmp(property, "icon") == 0) && fBitmap) { 170de9dcd41SStephan Aßmus BMessage archive; 171de9dcd41SStephan Aßmus if (fBitmap->Archive(&archive) == B_OK) 172de9dcd41SStephan Aßmus reply.AddMessage("result", &archive); 173de9dcd41SStephan Aßmus } 174de9dcd41SStephan Aßmus 175de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 176de9dcd41SStephan Aßmus } else { 177de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 178de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 179de9dcd41SStephan Aßmus } 180de9dcd41SStephan Aßmus 181de9dcd41SStephan Aßmus msg->SendReply(&reply); 182de9dcd41SStephan Aßmus break; 183de9dcd41SStephan Aßmus } 184de9dcd41SStephan Aßmus case B_SET_PROPERTY: 185de9dcd41SStephan Aßmus { 186de9dcd41SStephan Aßmus BMessage specifier; 187de9dcd41SStephan Aßmus const char* property; 188de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 189de9dcd41SStephan Aßmus bool msgOkay = true; 190de9dcd41SStephan Aßmus 191de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 192de9dcd41SStephan Aßmus msgOkay = false; 193de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 194de9dcd41SStephan Aßmus msgOkay = false; 195de9dcd41SStephan Aßmus 196de9dcd41SStephan Aßmus if (msgOkay) { 1974ec6c3a0SAdrien Destugues const char* value = NULL; 1984ec6c3a0SAdrien Destugues 1994ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 2004ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 2014ec6c3a0SAdrien Destugues fNotification->SetGroup(value); 202de9dcd41SStephan Aßmus 203de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 2044ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 2054ec6c3a0SAdrien Destugues fNotification->SetTitle(value); 206de9dcd41SStephan Aßmus 207de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 2084ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 2094ec6c3a0SAdrien Destugues fNotification->SetContent(value); 210de9dcd41SStephan Aßmus 211de9dcd41SStephan Aßmus if (strcmp(property, "icon") == 0) { 212de9dcd41SStephan Aßmus BMessage archive; 213de9dcd41SStephan Aßmus if (msg->FindMessage("data", &archive) == B_OK) { 214de9dcd41SStephan Aßmus delete fBitmap; 215de9dcd41SStephan Aßmus fBitmap = new BBitmap(&archive); 216de9dcd41SStephan Aßmus } 217de9dcd41SStephan Aßmus } 218de9dcd41SStephan Aßmus 2194ec6c3a0SAdrien Destugues SetText(); 220de9dcd41SStephan Aßmus Invalidate(); 221de9dcd41SStephan Aßmus 222de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 223de9dcd41SStephan Aßmus } else { 224de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 225de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 226de9dcd41SStephan Aßmus } 227de9dcd41SStephan Aßmus 228de9dcd41SStephan Aßmus msg->SendReply(&reply); 229de9dcd41SStephan Aßmus break; 230de9dcd41SStephan Aßmus } 231de9dcd41SStephan Aßmus default: 232de9dcd41SStephan Aßmus BView::MessageReceived(msg); 233de9dcd41SStephan Aßmus } 234de9dcd41SStephan Aßmus } 235de9dcd41SStephan Aßmus 236de9dcd41SStephan Aßmus 237de9dcd41SStephan Aßmus void 238de9dcd41SStephan Aßmus NotificationView::Draw(BRect updateRect) 239de9dcd41SStephan Aßmus { 240de9dcd41SStephan Aßmus BRect progRect; 241de9dcd41SStephan Aßmus 242de9dcd41SStephan Aßmus SetDrawingMode(B_OP_ALPHA); 243de9dcd41SStephan Aßmus SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 244de9dcd41SStephan Aßmus 2459dcd41a8SAdrien Destugues BRect stripeRect = Bounds(); 2460e07be06SAdrien Destugues stripeRect.right = kIconStripeWidth; 24769631a6aSAdrien Destugues SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 24869631a6aSAdrien Destugues B_DARKEN_1_TINT)); 24969631a6aSAdrien Destugues FillRect(stripeRect); 25069631a6aSAdrien Destugues 25148d90a50SAdrien Destugues SetHighColor(fStripeColor); 25269631a6aSAdrien Destugues stripeRect.right = 2; 2539dcd41a8SAdrien Destugues FillRect(stripeRect); 2549dcd41a8SAdrien Destugues 2559dcd41a8SAdrien Destugues SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); 256de9dcd41SStephan Aßmus // Rectangle for icon and overlay icon 257de9dcd41SStephan Aßmus BRect iconRect(0, 0, 0, 0); 258de9dcd41SStephan Aßmus 259de9dcd41SStephan Aßmus // Draw icon 260de9dcd41SStephan Aßmus if (fBitmap) { 2615414f4dcSAdrien Destugues float ix = 18; 262*6aa05872SBrian Hill float iy = (Bounds().Height() - fIconSize) / 4.0; 2630e07be06SAdrien Destugues // Icon is vertically centered in view 264de9dcd41SStephan Aßmus 2654ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) 2660e07be06SAdrien Destugues { 267de9dcd41SStephan Aßmus // Move icon up by half progress bar height if it's present 2680e07be06SAdrien Destugues iy -= (progRect.Height() + kEdgePadding); 2690e07be06SAdrien Destugues } 270de9dcd41SStephan Aßmus 271*6aa05872SBrian Hill iconRect.Set(ix, iy, ix + fIconSize - 1.0, iy + fIconSize - 1.0); 272bdde2d30SPhilippe Houdoin DrawBitmapAsync(fBitmap, fBitmap->Bounds(), iconRect); 273de9dcd41SStephan Aßmus } 274de9dcd41SStephan Aßmus 275de9dcd41SStephan Aßmus // Draw content 276de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 277de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) { 278de9dcd41SStephan Aßmus LineInfo *l = (*lIt); 279de9dcd41SStephan Aßmus 280de9dcd41SStephan Aßmus SetFont(&l->font); 28163a4690eSAdrien Destugues // Truncate the string. We have already line-wrapped the text but if 28263a4690eSAdrien Destugues // there is a very long 'word' we can only truncate it. 283*6aa05872SBrian Hill BString text(l->text); 284*6aa05872SBrian Hill TruncateString(&text, B_TRUNCATE_END, 28584e1c7faSAdrien Destugues Bounds().Width() - l->location.x); 286*6aa05872SBrian Hill DrawString(text.String(), text.Length(), l->location); 287de9dcd41SStephan Aßmus } 288de9dcd41SStephan Aßmus 289f6afd3e9SRyan Leavengood AppGroupView* groupView = dynamic_cast<AppGroupView*>(Parent()); 290f6afd3e9SRyan Leavengood if (groupView != NULL && groupView->ChildrenCount() > 1) 29182a67460SAdrien Destugues - PulkoMandy _DrawCloseButton(updateRect); 292de9dcd41SStephan Aßmus 2935414f4dcSAdrien Destugues SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 29444c6e69bSAdrien Destugues BPoint left(Bounds().left, Bounds().top); 29544c6e69bSAdrien Destugues BPoint right(Bounds().right, Bounds().top); 2965414f4dcSAdrien Destugues StrokeLine(left, right); 2975414f4dcSAdrien Destugues 298de9dcd41SStephan Aßmus Sync(); 299de9dcd41SStephan Aßmus } 300de9dcd41SStephan Aßmus 301de9dcd41SStephan Aßmus 302de9dcd41SStephan Aßmus void 30382a67460SAdrien Destugues - PulkoMandy NotificationView::_DrawCloseButton(const BRect& updateRect) 30482a67460SAdrien Destugues - PulkoMandy { 30582a67460SAdrien Destugues - PulkoMandy PushState(); 30682a67460SAdrien Destugues - PulkoMandy BRect closeRect = Bounds(); 30782a67460SAdrien Destugues - PulkoMandy 30882a67460SAdrien Destugues - PulkoMandy closeRect.InsetBy(3 * kEdgePadding, 3 * kEdgePadding); 30982a67460SAdrien Destugues - PulkoMandy closeRect.left = closeRect.right - kCloseSize; 31082a67460SAdrien Destugues - PulkoMandy closeRect.bottom = closeRect.top + kCloseSize; 31182a67460SAdrien Destugues - PulkoMandy 31282a67460SAdrien Destugues - PulkoMandy rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 31382a67460SAdrien Destugues - PulkoMandy float tint = B_DARKEN_2_TINT; 31482a67460SAdrien Destugues - PulkoMandy 31582a67460SAdrien Destugues - PulkoMandy if (fCloseClicked) { 31682a67460SAdrien Destugues - PulkoMandy BRect buttonRect(closeRect.InsetByCopy(-4, -4)); 31782a67460SAdrien Destugues - PulkoMandy be_control_look->DrawButtonFrame(this, buttonRect, updateRect, 31882a67460SAdrien Destugues - PulkoMandy base, base, 31982a67460SAdrien Destugues - PulkoMandy BControlLook::B_ACTIVATED | BControlLook::B_BLEND_FRAME); 32082a67460SAdrien Destugues - PulkoMandy be_control_look->DrawButtonBackground(this, buttonRect, updateRect, 32182a67460SAdrien Destugues - PulkoMandy base, BControlLook::B_ACTIVATED); 32282a67460SAdrien Destugues - PulkoMandy tint *= 1.2; 32382a67460SAdrien Destugues - PulkoMandy closeRect.OffsetBy(1, 1); 32482a67460SAdrien Destugues - PulkoMandy } 32582a67460SAdrien Destugues - PulkoMandy 32682a67460SAdrien Destugues - PulkoMandy base = tint_color(base, tint); 32782a67460SAdrien Destugues - PulkoMandy SetHighColor(base); 32882a67460SAdrien Destugues - PulkoMandy SetPenSize(2); 32982a67460SAdrien Destugues - PulkoMandy StrokeLine(closeRect.LeftTop(), closeRect.RightBottom()); 33082a67460SAdrien Destugues - PulkoMandy StrokeLine(closeRect.LeftBottom(), closeRect.RightTop()); 33182a67460SAdrien Destugues - PulkoMandy PopState(); 33282a67460SAdrien Destugues - PulkoMandy } 33382a67460SAdrien Destugues - PulkoMandy 33482a67460SAdrien Destugues - PulkoMandy 33582a67460SAdrien Destugues - PulkoMandy void 336de9dcd41SStephan Aßmus NotificationView::MouseDown(BPoint point) 337de9dcd41SStephan Aßmus { 338*6aa05872SBrian Hill // Preview Mode ignores any mouse clicks 339*6aa05872SBrian Hill if (fPreviewModeOn) 340*6aa05872SBrian Hill return; 341*6aa05872SBrian Hill 342de9dcd41SStephan Aßmus int32 buttons; 343de9dcd41SStephan Aßmus Window()->CurrentMessage()->FindInt32("buttons", &buttons); 344de9dcd41SStephan Aßmus 345de9dcd41SStephan Aßmus switch (buttons) { 346de9dcd41SStephan Aßmus case B_PRIMARY_MOUSE_BUTTON: 347de9dcd41SStephan Aßmus { 348de9dcd41SStephan Aßmus BRect closeRect = Bounds().InsetByCopy(2,2); 349de9dcd41SStephan Aßmus closeRect.left = closeRect.right - kCloseSize; 350de9dcd41SStephan Aßmus closeRect.bottom = closeRect.top + kCloseSize; 351de9dcd41SStephan Aßmus 352de9dcd41SStephan Aßmus if (!closeRect.Contains(point)) { 353de9dcd41SStephan Aßmus entry_ref launchRef; 354de9dcd41SStephan Aßmus BString launchString; 355de9dcd41SStephan Aßmus BMessage argMsg(B_ARGV_RECEIVED); 356de9dcd41SStephan Aßmus BMessage refMsg(B_REFS_RECEIVED); 357de9dcd41SStephan Aßmus entry_ref appRef; 358de9dcd41SStephan Aßmus bool useArgv = false; 359de9dcd41SStephan Aßmus BList messages; 360de9dcd41SStephan Aßmus entry_ref ref; 361de9dcd41SStephan Aßmus 3624ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL 3634ec6c3a0SAdrien Destugues && be_roster->FindApp(fNotification->OnClickApp(), &appRef) 3644ec6c3a0SAdrien Destugues == B_OK) { 365de9dcd41SStephan Aßmus useArgv = true; 366de9dcd41SStephan Aßmus } 367de9dcd41SStephan Aßmus 3684ec6c3a0SAdrien Destugues if (fNotification->OnClickFile() != NULL 3694ec6c3a0SAdrien Destugues && be_roster->FindApp( 3704ec6c3a0SAdrien Destugues (entry_ref*)fNotification->OnClickFile(), &appRef) 3714ec6c3a0SAdrien Destugues == B_OK) { 3724ec6c3a0SAdrien Destugues useArgv = true; 3734ec6c3a0SAdrien Destugues } 374de9dcd41SStephan Aßmus 3754ec6c3a0SAdrien Destugues for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++) 3764ec6c3a0SAdrien Destugues refMsg.AddRef("refs", fNotification->OnClickRefAt(i)); 377de9dcd41SStephan Aßmus messages.AddItem((void*)&refMsg); 378de9dcd41SStephan Aßmus 379de9dcd41SStephan Aßmus if (useArgv) { 3804ec6c3a0SAdrien Destugues int32 argc = fNotification->CountOnClickArgs() + 1; 381de9dcd41SStephan Aßmus BString arg; 382de9dcd41SStephan Aßmus 383de9dcd41SStephan Aßmus BPath p(&appRef); 384de9dcd41SStephan Aßmus argMsg.AddString("argv", p.Path()); 385de9dcd41SStephan Aßmus 3864ec6c3a0SAdrien Destugues argMsg.AddInt32("argc", argc); 387de9dcd41SStephan Aßmus 3884ec6c3a0SAdrien Destugues for (int32 i = 0; i < argc - 1; i++) { 3894ec6c3a0SAdrien Destugues argMsg.AddString("argv", 3904ec6c3a0SAdrien Destugues fNotification->OnClickArgAt(i)); 3914ec6c3a0SAdrien Destugues } 392de9dcd41SStephan Aßmus 393de9dcd41SStephan Aßmus messages.AddItem((void*)&argMsg); 394de9dcd41SStephan Aßmus } 395de9dcd41SStephan Aßmus 3964ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL) 3974ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickApp(), &messages); 398de9dcd41SStephan Aßmus else 3994ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickFile(), &messages); 40082a67460SAdrien Destugues - PulkoMandy } else { 40182a67460SAdrien Destugues - PulkoMandy fCloseClicked = true; 402de9dcd41SStephan Aßmus } 403de9dcd41SStephan Aßmus 404de9dcd41SStephan Aßmus // Remove the info view after a click 405de9dcd41SStephan Aßmus BMessage remove_msg(kRemoveView); 406de9dcd41SStephan Aßmus remove_msg.AddPointer("view", this); 407de9dcd41SStephan Aßmus 408de9dcd41SStephan Aßmus BMessenger msgr(Parent()); 409de9dcd41SStephan Aßmus msgr.SendMessage(&remove_msg); 410de9dcd41SStephan Aßmus break; 411de9dcd41SStephan Aßmus } 412de9dcd41SStephan Aßmus } 413de9dcd41SStephan Aßmus } 414de9dcd41SStephan Aßmus 415de9dcd41SStephan Aßmus 416de9dcd41SStephan Aßmus BHandler* 4174ec6c3a0SAdrien Destugues NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, 4184ec6c3a0SAdrien Destugues int32 form, const char* prop) 419de9dcd41SStephan Aßmus { 420de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 421de9dcd41SStephan Aßmus if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) { 422de9dcd41SStephan Aßmus msg->PopSpecifier(); 423de9dcd41SStephan Aßmus return this; 424de9dcd41SStephan Aßmus } 425de9dcd41SStephan Aßmus 426de9dcd41SStephan Aßmus return BView::ResolveSpecifier(msg, index, spec, form, prop); 427de9dcd41SStephan Aßmus } 428de9dcd41SStephan Aßmus 429de9dcd41SStephan Aßmus 430de9dcd41SStephan Aßmus status_t 431de9dcd41SStephan Aßmus NotificationView::GetSupportedSuites(BMessage* msg) 432de9dcd41SStephan Aßmus { 433de9dcd41SStephan Aßmus msg->AddString("suites", "suite/x-vnd.Haiku-notification_server"); 434de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 435de9dcd41SStephan Aßmus msg->AddFlat("messages", &prop_info); 436de9dcd41SStephan Aßmus return BView::GetSupportedSuites(msg); 437de9dcd41SStephan Aßmus } 438de9dcd41SStephan Aßmus 439de9dcd41SStephan Aßmus 440de9dcd41SStephan Aßmus void 4414ec6c3a0SAdrien Destugues NotificationView::SetText(float newMaxWidth) 442de9dcd41SStephan Aßmus { 4432a740449SFrançois Revol if (newMaxWidth < 0 && Parent()) 4442a740449SFrançois Revol newMaxWidth = Parent()->Bounds().IntegerWidth(); 4452a740449SFrançois Revol if (newMaxWidth <= 0) 4462a740449SFrançois Revol newMaxWidth = kDefaultWidth; 447de9dcd41SStephan Aßmus 448de9dcd41SStephan Aßmus // Delete old lines 449de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 450de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 451de9dcd41SStephan Aßmus delete (*lIt); 452de9dcd41SStephan Aßmus fLines.clear(); 453de9dcd41SStephan Aßmus 4540e07be06SAdrien Destugues float iconRight = kIconStripeWidth; 455de9dcd41SStephan Aßmus if (fBitmap != NULL) 456*6aa05872SBrian Hill iconRight += fIconSize; 4570e07be06SAdrien Destugues else 4585414f4dcSAdrien Destugues iconRight += 32; 459de9dcd41SStephan Aßmus 460*6aa05872SBrian Hill BFont boldFont(be_plain_font); 461*6aa05872SBrian Hill boldFont.SetFace(B_BOLD_FACE); 462de9dcd41SStephan Aßmus font_height fh; 463*6aa05872SBrian Hill boldFont.GetHeight(&fh); 464de9dcd41SStephan Aßmus float fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 465de9dcd41SStephan Aßmus + ceilf(fh.ascent); 466*6aa05872SBrian Hill float y = fontHeight + kEdgePadding * 2; 467de9dcd41SStephan Aßmus 468de9dcd41SStephan Aßmus // Title 469de9dcd41SStephan Aßmus LineInfo* titleLine = new LineInfo; 4704ec6c3a0SAdrien Destugues titleLine->text = fNotification->Title(); 471*6aa05872SBrian Hill titleLine->font = boldFont; 472de9dcd41SStephan Aßmus 473569a7bfcSAdrien Destugues titleLine->location = BPoint(iconRight + kEdgePadding, y); 474de9dcd41SStephan Aßmus 475de9dcd41SStephan Aßmus fLines.push_front(titleLine); 476de9dcd41SStephan Aßmus y += fontHeight; 477de9dcd41SStephan Aßmus 478de9dcd41SStephan Aßmus // Rest of text is rendered with be_plain_font. 479de9dcd41SStephan Aßmus be_plain_font->GetHeight(&fh); 480de9dcd41SStephan Aßmus fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 481de9dcd41SStephan Aßmus + ceilf(fh.ascent); 482de9dcd41SStephan Aßmus 483de9dcd41SStephan Aßmus // Split text into chunks between certain characters and compose the lines. 484e0890a26SAdrien Destugues const char kSeparatorCharacters[] = " \n-\\"; 4854ec6c3a0SAdrien Destugues BString textBuffer = fNotification->Content(); 486de9dcd41SStephan Aßmus textBuffer.ReplaceAll("\t", " "); 487de9dcd41SStephan Aßmus const char* chunkStart = textBuffer.String(); 488de9dcd41SStephan Aßmus float maxWidth = newMaxWidth - kEdgePadding - iconRight; 489de9dcd41SStephan Aßmus LineInfo* line = NULL; 490de9dcd41SStephan Aßmus ssize_t length = textBuffer.Length(); 491de9dcd41SStephan Aßmus while (chunkStart - textBuffer.String() < length) { 492de9dcd41SStephan Aßmus size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1; 493de9dcd41SStephan Aßmus 4944ec6c3a0SAdrien Destugues // Start a new line if we didn't start one before 49531a3c4e8SJérôme Duval BString tempText; 49631a3c4e8SJérôme Duval if (line != NULL) 49731a3c4e8SJérôme Duval tempText.SetTo(line->text); 498de9dcd41SStephan Aßmus tempText.Append(chunkStart, chunkLength); 499de9dcd41SStephan Aßmus 500de9dcd41SStephan Aßmus if (line == NULL || chunkStart[0] == '\n' 501de9dcd41SStephan Aßmus || StringWidth(tempText) > maxWidth) { 502de9dcd41SStephan Aßmus line = new LineInfo; 503de9dcd41SStephan Aßmus line->font = *be_plain_font; 504de9dcd41SStephan Aßmus line->location = BPoint(iconRight + kEdgePadding, y); 505de9dcd41SStephan Aßmus 506de9dcd41SStephan Aßmus fLines.push_front(line); 507de9dcd41SStephan Aßmus y += fontHeight; 508de9dcd41SStephan Aßmus 5094ec6c3a0SAdrien Destugues // Skip the eventual new-line character at the beginning of this chunk 510de9dcd41SStephan Aßmus if (chunkStart[0] == '\n') { 511de9dcd41SStephan Aßmus chunkStart++; 512de9dcd41SStephan Aßmus chunkLength--; 513de9dcd41SStephan Aßmus } 5144ec6c3a0SAdrien Destugues 5154ec6c3a0SAdrien Destugues // Skip more new-line characters and move the line further down 516de9dcd41SStephan Aßmus while (chunkStart[0] == '\n') { 517de9dcd41SStephan Aßmus chunkStart++; 518de9dcd41SStephan Aßmus chunkLength--; 519de9dcd41SStephan Aßmus line->location.y += fontHeight; 520de9dcd41SStephan Aßmus y += fontHeight; 521de9dcd41SStephan Aßmus } 5224ec6c3a0SAdrien Destugues 5234ec6c3a0SAdrien Destugues // Strip space at beginning of a new line 524de9dcd41SStephan Aßmus while (chunkStart[0] == ' ') { 525de9dcd41SStephan Aßmus chunkLength--; 526de9dcd41SStephan Aßmus chunkStart++; 527de9dcd41SStephan Aßmus } 528de9dcd41SStephan Aßmus } 529de9dcd41SStephan Aßmus 530de9dcd41SStephan Aßmus if (chunkStart[0] == '\0') 531de9dcd41SStephan Aßmus break; 532de9dcd41SStephan Aßmus 533de9dcd41SStephan Aßmus // Append the chunk to the current line, which was either a new 5344ec6c3a0SAdrien Destugues // line or the one from the previous iteration 535de9dcd41SStephan Aßmus line->text.Append(chunkStart, chunkLength); 536de9dcd41SStephan Aßmus 537de9dcd41SStephan Aßmus chunkStart += chunkLength; 538de9dcd41SStephan Aßmus } 539de9dcd41SStephan Aßmus 540de9dcd41SStephan Aßmus fHeight = y + (kEdgePadding * 2); 541de9dcd41SStephan Aßmus 542de9dcd41SStephan Aßmus // Make sure icon fits 543de9dcd41SStephan Aßmus if (fBitmap != NULL) { 5444ec6c3a0SAdrien Destugues float minHeight = fBitmap->Bounds().Height() + 2 * kEdgePadding; 545de9dcd41SStephan Aßmus 546de9dcd41SStephan Aßmus if (fHeight < minHeight) 547de9dcd41SStephan Aßmus fHeight = minHeight; 548de9dcd41SStephan Aßmus } 549e0890a26SAdrien Destugues 550e0890a26SAdrien Destugues // Make sure the progress bar is below the text, and the window is big 551e0890a26SAdrien Destugues // enough. 552e0890a26SAdrien Destugues static_cast<BGroupLayout*>(GetLayout())->SetInsets(kIconStripeWidth + 8, 553e0890a26SAdrien Destugues fHeight, 8, 8); 55444c6e69bSAdrien Destugues 55544c6e69bSAdrien Destugues _CalculateSize(); 556de9dcd41SStephan Aßmus } 557de9dcd41SStephan Aßmus 558de9dcd41SStephan Aßmus 559*6aa05872SBrian Hill void 560*6aa05872SBrian Hill NotificationView::SetPreviewModeOn(bool enabled) 561*6aa05872SBrian Hill { 562*6aa05872SBrian Hill fPreviewModeOn = enabled; 563*6aa05872SBrian Hill } 564*6aa05872SBrian Hill 565*6aa05872SBrian Hill 566de9dcd41SStephan Aßmus const char* 5674ec6c3a0SAdrien Destugues NotificationView::MessageID() const 568de9dcd41SStephan Aßmus { 5694ec6c3a0SAdrien Destugues return fNotification->MessageID(); 570de9dcd41SStephan Aßmus } 571de9dcd41SStephan Aßmus 572de9dcd41SStephan Aßmus 573c2fbfb1dSAlex Wilson void 5744ec6c3a0SAdrien Destugues NotificationView::_CalculateSize() 575de9dcd41SStephan Aßmus { 576c2fbfb1dSAlex Wilson float height = fHeight; 5774ec6c3a0SAdrien Destugues 5784ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) { 5794ec6c3a0SAdrien Destugues font_height fh; 5804ec6c3a0SAdrien Destugues be_plain_font->GetHeight(&fh); 5814ec6c3a0SAdrien Destugues float fontHeight = fh.ascent + fh.descent + fh.leading; 582c2fbfb1dSAlex Wilson height += 9 + (kSmallPadding * 2) + (kEdgePadding * 1) 58344c6e69bSAdrien Destugues + fontHeight * 2; 584de9dcd41SStephan Aßmus } 585de9dcd41SStephan Aßmus 586c2fbfb1dSAlex Wilson SetExplicitMinSize(BSize(0, height)); 587c2fbfb1dSAlex Wilson SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, height)); 588de9dcd41SStephan Aßmus } 589