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 165414f4dcSAdrien Destugues #include <ControlLook.h> 17*e0890a26SAdrien Destugues #include <GroupLayout.h> 18*e0890a26SAdrien Destugues #include <GroupLayoutBuilder.h> 19*e0890a26SAdrien Destugues #include <Layout.h> 204ec6c3a0SAdrien Destugues #include <LayoutUtils.h> 21de9dcd41SStephan Aßmus #include <Messenger.h> 224ec6c3a0SAdrien Destugues #include <Path.h> 23de9dcd41SStephan Aßmus #include <Roster.h> 24beeda306SAdrien Destugues #include <StatusBar.h> 25de9dcd41SStephan Aßmus 26de9dcd41SStephan Aßmus #include "NotificationView.h" 27de9dcd41SStephan Aßmus #include "NotificationWindow.h" 28de9dcd41SStephan Aßmus 290e07be06SAdrien Destugues static const int kIconStripeWidth = 32; 309dcd41a8SAdrien Destugues 31de9dcd41SStephan Aßmus property_info message_prop_list[] = { 32de9dcd41SStephan Aßmus { "type", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 33de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the notification type"}, 34de9dcd41SStephan Aßmus { "app", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 35de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's app"}, 36de9dcd41SStephan Aßmus { "title", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 37de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's title"}, 38de9dcd41SStephan Aßmus { "content", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 39de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's contents"}, 40de9dcd41SStephan Aßmus { "icon", {B_GET_PROPERTY, 0}, 41de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get icon as an archived bitmap"}, 42de9dcd41SStephan Aßmus { "progress", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 43de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the progress (between 0.0 and 1.0)"}, 44de9dcd41SStephan Aßmus { NULL } 45de9dcd41SStephan Aßmus }; 46de9dcd41SStephan Aßmus 47de9dcd41SStephan Aßmus 48de9dcd41SStephan Aßmus NotificationView::NotificationView(NotificationWindow* win, 494ec6c3a0SAdrien Destugues BNotification* notification, bigtime_t timeout) 50de9dcd41SStephan Aßmus : 514ec6c3a0SAdrien Destugues BView("NotificationView", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE 52de9dcd41SStephan Aßmus | B_FRAME_EVENTS), 53de9dcd41SStephan Aßmus fParent(win), 544ec6c3a0SAdrien Destugues fNotification(notification), 554ec6c3a0SAdrien Destugues fTimeout(timeout), 56de9dcd41SStephan Aßmus fRunner(NULL), 574ec6c3a0SAdrien Destugues fBitmap(NULL) 58de9dcd41SStephan Aßmus { 594ec6c3a0SAdrien Destugues if (fNotification->Icon() != NULL) 604ec6c3a0SAdrien Destugues fBitmap = new BBitmap(fNotification->Icon()); 61de9dcd41SStephan Aßmus 624ec6c3a0SAdrien Destugues if (fTimeout <= 0) 634ec6c3a0SAdrien Destugues fTimeout = fParent->Timeout() * 1000000; 64de9dcd41SStephan Aßmus 65*e0890a26SAdrien Destugues BGroupLayout* layout = new BGroupLayout(B_VERTICAL); 66*e0890a26SAdrien Destugues SetLayout(layout); 67*e0890a26SAdrien Destugues 684ec6c3a0SAdrien Destugues SetText(); 69de9dcd41SStephan Aßmus 704ec6c3a0SAdrien Destugues switch (fNotification->Type()) { 71de9dcd41SStephan Aßmus case B_IMPORTANT_NOTIFICATION: 72de9dcd41SStephan Aßmus SetViewColor(255, 255, 255); 73de9dcd41SStephan Aßmus SetLowColor(255, 255, 255); 74de9dcd41SStephan Aßmus break; 75de9dcd41SStephan Aßmus case B_ERROR_NOTIFICATION: 76de9dcd41SStephan Aßmus SetViewColor(ui_color(B_FAILURE_COLOR)); 77de9dcd41SStephan Aßmus SetLowColor(ui_color(B_FAILURE_COLOR)); 78de9dcd41SStephan Aßmus break; 79beeda306SAdrien Destugues case B_PROGRESS_NOTIFICATION: 80beeda306SAdrien Destugues { 81*e0890a26SAdrien Destugues BStatusBar* progress = new BStatusBar("progress"); 82beeda306SAdrien Destugues progress->SetBarHeight(12.0f); 83beeda306SAdrien Destugues progress->SetMaxValue(1.0f); 844ec6c3a0SAdrien Destugues progress->Update(fNotification->Progress()); 85beeda306SAdrien Destugues 86beeda306SAdrien Destugues BString label = ""; 874ec6c3a0SAdrien Destugues label << (int)(fNotification->Progress() * 100) << " %"; 88beeda306SAdrien Destugues progress->SetTrailingText(label); 89beeda306SAdrien Destugues 90*e0890a26SAdrien Destugues BGroupLayoutBuilder b(layout); 91*e0890a26SAdrien Destugues b.AddGlue() 92*e0890a26SAdrien Destugues .Add(progress); 93beeda306SAdrien Destugues } 944ec6c3a0SAdrien Destugues // fall through 95de9dcd41SStephan Aßmus default: 96de9dcd41SStephan Aßmus SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 97de9dcd41SStephan Aßmus SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 98de9dcd41SStephan Aßmus } 99de9dcd41SStephan Aßmus } 100de9dcd41SStephan Aßmus 101de9dcd41SStephan Aßmus 102de9dcd41SStephan Aßmus NotificationView::~NotificationView() 103de9dcd41SStephan Aßmus { 104de9dcd41SStephan Aßmus delete fRunner; 105de9dcd41SStephan Aßmus delete fBitmap; 1064ec6c3a0SAdrien Destugues delete fNotification; 107de9dcd41SStephan Aßmus 108de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 109de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 110de9dcd41SStephan Aßmus delete (*lIt); 111de9dcd41SStephan Aßmus } 112de9dcd41SStephan Aßmus 113de9dcd41SStephan Aßmus 114de9dcd41SStephan Aßmus void 115de9dcd41SStephan Aßmus NotificationView::AttachedToWindow() 116de9dcd41SStephan Aßmus { 117de9dcd41SStephan Aßmus BMessage msg(kRemoveView); 118de9dcd41SStephan Aßmus msg.AddPointer("view", this); 119de9dcd41SStephan Aßmus 1204ec6c3a0SAdrien Destugues fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1); 121de9dcd41SStephan Aßmus } 122de9dcd41SStephan Aßmus 123de9dcd41SStephan Aßmus 124de9dcd41SStephan Aßmus void 125de9dcd41SStephan Aßmus NotificationView::MessageReceived(BMessage* msg) 126de9dcd41SStephan Aßmus { 127de9dcd41SStephan Aßmus switch (msg->what) { 128de9dcd41SStephan Aßmus case B_GET_PROPERTY: 129de9dcd41SStephan Aßmus { 130de9dcd41SStephan Aßmus BMessage specifier; 131de9dcd41SStephan Aßmus const char* property; 132de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 133de9dcd41SStephan Aßmus bool msgOkay = true; 134de9dcd41SStephan Aßmus 135de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 136de9dcd41SStephan Aßmus msgOkay = false; 137de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 138de9dcd41SStephan Aßmus msgOkay = false; 139de9dcd41SStephan Aßmus 140de9dcd41SStephan Aßmus if (msgOkay) { 141de9dcd41SStephan Aßmus if (strcmp(property, "type") == 0) 1424ec6c3a0SAdrien Destugues reply.AddInt32("result", fNotification->Type()); 143de9dcd41SStephan Aßmus 1444ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 1454ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Group()); 146de9dcd41SStephan Aßmus 147de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 1484ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Title()); 149de9dcd41SStephan Aßmus 150de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 1514ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Content()); 152de9dcd41SStephan Aßmus 153de9dcd41SStephan Aßmus if (strcmp(property, "progress") == 0) 1544ec6c3a0SAdrien Destugues reply.AddFloat("result", fNotification->Progress()); 155de9dcd41SStephan Aßmus 156de9dcd41SStephan Aßmus if ((strcmp(property, "icon") == 0) && fBitmap) { 157de9dcd41SStephan Aßmus BMessage archive; 158de9dcd41SStephan Aßmus if (fBitmap->Archive(&archive) == B_OK) 159de9dcd41SStephan Aßmus reply.AddMessage("result", &archive); 160de9dcd41SStephan Aßmus } 161de9dcd41SStephan Aßmus 162de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 163de9dcd41SStephan Aßmus } else { 164de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 165de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 166de9dcd41SStephan Aßmus } 167de9dcd41SStephan Aßmus 168de9dcd41SStephan Aßmus msg->SendReply(&reply); 169de9dcd41SStephan Aßmus break; 170de9dcd41SStephan Aßmus } 171de9dcd41SStephan Aßmus case B_SET_PROPERTY: 172de9dcd41SStephan Aßmus { 173de9dcd41SStephan Aßmus BMessage specifier; 174de9dcd41SStephan Aßmus const char* property; 175de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 176de9dcd41SStephan Aßmus bool msgOkay = true; 177de9dcd41SStephan Aßmus 178de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 179de9dcd41SStephan Aßmus msgOkay = false; 180de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 181de9dcd41SStephan Aßmus msgOkay = false; 182de9dcd41SStephan Aßmus 183de9dcd41SStephan Aßmus if (msgOkay) { 1844ec6c3a0SAdrien Destugues const char* value = NULL; 1854ec6c3a0SAdrien Destugues 1864ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 1874ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 1884ec6c3a0SAdrien Destugues fNotification->SetGroup(value); 189de9dcd41SStephan Aßmus 190de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 1914ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 1924ec6c3a0SAdrien Destugues fNotification->SetTitle(value); 193de9dcd41SStephan Aßmus 194de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 1954ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 1964ec6c3a0SAdrien Destugues fNotification->SetContent(value); 197de9dcd41SStephan Aßmus 198de9dcd41SStephan Aßmus if (strcmp(property, "icon") == 0) { 199de9dcd41SStephan Aßmus BMessage archive; 200de9dcd41SStephan Aßmus if (msg->FindMessage("data", &archive) == B_OK) { 201de9dcd41SStephan Aßmus delete fBitmap; 202de9dcd41SStephan Aßmus fBitmap = new BBitmap(&archive); 203de9dcd41SStephan Aßmus } 204de9dcd41SStephan Aßmus } 205de9dcd41SStephan Aßmus 2064ec6c3a0SAdrien Destugues SetText(); 207de9dcd41SStephan Aßmus Invalidate(); 208de9dcd41SStephan Aßmus 209de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 210de9dcd41SStephan Aßmus } else { 211de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 212de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 213de9dcd41SStephan Aßmus } 214de9dcd41SStephan Aßmus 215de9dcd41SStephan Aßmus msg->SendReply(&reply); 216de9dcd41SStephan Aßmus break; 217de9dcd41SStephan Aßmus } 218de9dcd41SStephan Aßmus default: 219de9dcd41SStephan Aßmus BView::MessageReceived(msg); 220de9dcd41SStephan Aßmus } 221de9dcd41SStephan Aßmus } 222de9dcd41SStephan Aßmus 223de9dcd41SStephan Aßmus 224de9dcd41SStephan Aßmus void 225de9dcd41SStephan Aßmus NotificationView::Draw(BRect updateRect) 226de9dcd41SStephan Aßmus { 227de9dcd41SStephan Aßmus BRect progRect; 228de9dcd41SStephan Aßmus 229de9dcd41SStephan Aßmus SetDrawingMode(B_OP_ALPHA); 230de9dcd41SStephan Aßmus SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 231de9dcd41SStephan Aßmus 232de9dcd41SStephan Aßmus // Icon size 233de9dcd41SStephan Aßmus float iconSize = (float)fParent->IconSize(); 234de9dcd41SStephan Aßmus 2359dcd41a8SAdrien Destugues BRect stripeRect = Bounds(); 2360e07be06SAdrien Destugues stripeRect.right = kIconStripeWidth; 2379dcd41a8SAdrien Destugues SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 2389dcd41a8SAdrien Destugues FillRect(stripeRect); 2399dcd41a8SAdrien Destugues 2409dcd41a8SAdrien Destugues SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); 241de9dcd41SStephan Aßmus // Rectangle for icon and overlay icon 242de9dcd41SStephan Aßmus BRect iconRect(0, 0, 0, 0); 243de9dcd41SStephan Aßmus 244de9dcd41SStephan Aßmus // Draw icon 245de9dcd41SStephan Aßmus if (fBitmap) { 2465414f4dcSAdrien Destugues float ix = 18; 2475414f4dcSAdrien Destugues float iy = (Bounds().Height() - iconSize) / 4.0; 2480e07be06SAdrien Destugues // Icon is vertically centered in view 249de9dcd41SStephan Aßmus 2504ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) 2510e07be06SAdrien Destugues { 252de9dcd41SStephan Aßmus // Move icon up by half progress bar height if it's present 2530e07be06SAdrien Destugues iy -= (progRect.Height() + kEdgePadding); 2540e07be06SAdrien Destugues } 255de9dcd41SStephan Aßmus 2567dd47a9bSPhilippe Houdoin iconRect.Set(ix, iy, ix + iconSize - 1.0, iy + iconSize - 1.0); 257bdde2d30SPhilippe Houdoin DrawBitmapAsync(fBitmap, fBitmap->Bounds(), iconRect); 258de9dcd41SStephan Aßmus } 259de9dcd41SStephan Aßmus 260de9dcd41SStephan Aßmus // Draw content 261de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 262de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) { 263de9dcd41SStephan Aßmus LineInfo *l = (*lIt); 264de9dcd41SStephan Aßmus 265de9dcd41SStephan Aßmus SetFont(&l->font); 266de9dcd41SStephan Aßmus DrawString(l->text.String(), l->text.Length(), l->location); 267de9dcd41SStephan Aßmus } 268de9dcd41SStephan Aßmus 269de9dcd41SStephan Aßmus rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR); 270de9dcd41SStephan Aßmus detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT); 271de9dcd41SStephan Aßmus 272de9dcd41SStephan Aßmus // Draw the close widget 273de9dcd41SStephan Aßmus BRect closeRect = Bounds(); 2740e07be06SAdrien Destugues closeRect.InsetBy(2 * kEdgePadding, 2 * kEdgePadding); 275de9dcd41SStephan Aßmus closeRect.left = closeRect.right - kCloseSize; 276de9dcd41SStephan Aßmus closeRect.bottom = closeRect.top + kCloseSize; 277de9dcd41SStephan Aßmus 278de9dcd41SStephan Aßmus PushState(); 279de9dcd41SStephan Aßmus SetHighColor(detailCol); 280de9dcd41SStephan Aßmus StrokeRoundRect(closeRect, kSmallPadding, kSmallPadding); 281de9dcd41SStephan Aßmus BRect closeCross = closeRect.InsetByCopy(kSmallPadding, kSmallPadding); 282de9dcd41SStephan Aßmus StrokeLine(closeCross.LeftTop(), closeCross.RightBottom()); 283de9dcd41SStephan Aßmus StrokeLine(closeCross.LeftBottom(), closeCross.RightTop()); 284de9dcd41SStephan Aßmus PopState(); 285de9dcd41SStephan Aßmus 2865414f4dcSAdrien Destugues SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 2875414f4dcSAdrien Destugues BPoint left(Bounds().left, Bounds().bottom - 1); 2885414f4dcSAdrien Destugues BPoint right(Bounds().right, Bounds().bottom - 1); 2895414f4dcSAdrien Destugues StrokeLine(left, right); 2905414f4dcSAdrien Destugues 291de9dcd41SStephan Aßmus Sync(); 292de9dcd41SStephan Aßmus } 293de9dcd41SStephan Aßmus 294de9dcd41SStephan Aßmus 295de9dcd41SStephan Aßmus void 296de9dcd41SStephan Aßmus NotificationView::MouseDown(BPoint point) 297de9dcd41SStephan Aßmus { 298de9dcd41SStephan Aßmus int32 buttons; 299de9dcd41SStephan Aßmus Window()->CurrentMessage()->FindInt32("buttons", &buttons); 300de9dcd41SStephan Aßmus 301de9dcd41SStephan Aßmus switch (buttons) { 302de9dcd41SStephan Aßmus case B_PRIMARY_MOUSE_BUTTON: 303de9dcd41SStephan Aßmus { 304de9dcd41SStephan Aßmus BRect closeRect = Bounds().InsetByCopy(2,2); 305de9dcd41SStephan Aßmus closeRect.left = closeRect.right - kCloseSize; 306de9dcd41SStephan Aßmus closeRect.bottom = closeRect.top + kCloseSize; 307de9dcd41SStephan Aßmus 308de9dcd41SStephan Aßmus if (!closeRect.Contains(point)) { 309de9dcd41SStephan Aßmus entry_ref launchRef; 310de9dcd41SStephan Aßmus BString launchString; 311de9dcd41SStephan Aßmus BMessage argMsg(B_ARGV_RECEIVED); 312de9dcd41SStephan Aßmus BMessage refMsg(B_REFS_RECEIVED); 313de9dcd41SStephan Aßmus entry_ref appRef; 314de9dcd41SStephan Aßmus bool useArgv = false; 315de9dcd41SStephan Aßmus BList messages; 316de9dcd41SStephan Aßmus entry_ref ref; 317de9dcd41SStephan Aßmus 3184ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL 3194ec6c3a0SAdrien Destugues && be_roster->FindApp(fNotification->OnClickApp(), &appRef) 3204ec6c3a0SAdrien Destugues == B_OK) { 321de9dcd41SStephan Aßmus useArgv = true; 322de9dcd41SStephan Aßmus } 323de9dcd41SStephan Aßmus 3244ec6c3a0SAdrien Destugues if (fNotification->OnClickFile() != NULL 3254ec6c3a0SAdrien Destugues && be_roster->FindApp( 3264ec6c3a0SAdrien Destugues (entry_ref*)fNotification->OnClickFile(), &appRef) 3274ec6c3a0SAdrien Destugues == B_OK) { 3284ec6c3a0SAdrien Destugues useArgv = true; 3294ec6c3a0SAdrien Destugues } 330de9dcd41SStephan Aßmus 3314ec6c3a0SAdrien Destugues for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++) 3324ec6c3a0SAdrien Destugues refMsg.AddRef("refs", fNotification->OnClickRefAt(i)); 333de9dcd41SStephan Aßmus messages.AddItem((void*)&refMsg); 334de9dcd41SStephan Aßmus 335de9dcd41SStephan Aßmus if (useArgv) { 3364ec6c3a0SAdrien Destugues int32 argc = fNotification->CountOnClickArgs() + 1; 337de9dcd41SStephan Aßmus BString arg; 338de9dcd41SStephan Aßmus 339de9dcd41SStephan Aßmus BPath p(&appRef); 340de9dcd41SStephan Aßmus argMsg.AddString("argv", p.Path()); 341de9dcd41SStephan Aßmus 3424ec6c3a0SAdrien Destugues argMsg.AddInt32("argc", argc); 343de9dcd41SStephan Aßmus 3444ec6c3a0SAdrien Destugues for (int32 i = 0; i < argc - 1; i++) { 3454ec6c3a0SAdrien Destugues argMsg.AddString("argv", 3464ec6c3a0SAdrien Destugues fNotification->OnClickArgAt(i)); 3474ec6c3a0SAdrien Destugues } 348de9dcd41SStephan Aßmus 349de9dcd41SStephan Aßmus messages.AddItem((void*)&argMsg); 350de9dcd41SStephan Aßmus } 351de9dcd41SStephan Aßmus 3524ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL) 3534ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickApp(), &messages); 354de9dcd41SStephan Aßmus else 3554ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickFile(), &messages); 356de9dcd41SStephan Aßmus } 357de9dcd41SStephan Aßmus 358de9dcd41SStephan Aßmus // Remove the info view after a click 359de9dcd41SStephan Aßmus BMessage remove_msg(kRemoveView); 360de9dcd41SStephan Aßmus remove_msg.AddPointer("view", this); 361de9dcd41SStephan Aßmus 362de9dcd41SStephan Aßmus BMessenger msgr(Parent()); 363de9dcd41SStephan Aßmus msgr.SendMessage(&remove_msg); 364de9dcd41SStephan Aßmus break; 365de9dcd41SStephan Aßmus } 366de9dcd41SStephan Aßmus } 367de9dcd41SStephan Aßmus } 368de9dcd41SStephan Aßmus 369de9dcd41SStephan Aßmus 3704ec6c3a0SAdrien Destugues BSize 3714ec6c3a0SAdrien Destugues NotificationView::MinSize() 372de9dcd41SStephan Aßmus { 3734ec6c3a0SAdrien Destugues return BLayoutUtils::ComposeSize(ExplicitMinSize(), _CalculateSize()); 3744ec6c3a0SAdrien Destugues } 3754ec6c3a0SAdrien Destugues 3764ec6c3a0SAdrien Destugues 3774ec6c3a0SAdrien Destugues BSize 3784ec6c3a0SAdrien Destugues NotificationView::MaxSize() 3794ec6c3a0SAdrien Destugues { 3804ec6c3a0SAdrien Destugues return BLayoutUtils::ComposeSize(ExplicitMaxSize(), _CalculateSize()); 3814ec6c3a0SAdrien Destugues } 3824ec6c3a0SAdrien Destugues 3834ec6c3a0SAdrien Destugues 3844ec6c3a0SAdrien Destugues BSize 3854ec6c3a0SAdrien Destugues NotificationView::PreferredSize() 3864ec6c3a0SAdrien Destugues { 3874ec6c3a0SAdrien Destugues return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), 3884ec6c3a0SAdrien Destugues _CalculateSize()); 389de9dcd41SStephan Aßmus } 390de9dcd41SStephan Aßmus 391de9dcd41SStephan Aßmus 392de9dcd41SStephan Aßmus BHandler* 3934ec6c3a0SAdrien Destugues NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, 3944ec6c3a0SAdrien Destugues int32 form, const char* prop) 395de9dcd41SStephan Aßmus { 396de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 397de9dcd41SStephan Aßmus if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) { 398de9dcd41SStephan Aßmus msg->PopSpecifier(); 399de9dcd41SStephan Aßmus return this; 400de9dcd41SStephan Aßmus } 401de9dcd41SStephan Aßmus 402de9dcd41SStephan Aßmus return BView::ResolveSpecifier(msg, index, spec, form, prop); 403de9dcd41SStephan Aßmus } 404de9dcd41SStephan Aßmus 405de9dcd41SStephan Aßmus 406de9dcd41SStephan Aßmus status_t 407de9dcd41SStephan Aßmus NotificationView::GetSupportedSuites(BMessage* msg) 408de9dcd41SStephan Aßmus { 409de9dcd41SStephan Aßmus msg->AddString("suites", "suite/x-vnd.Haiku-notification_server"); 410de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 411de9dcd41SStephan Aßmus msg->AddFlat("messages", &prop_info); 412de9dcd41SStephan Aßmus return BView::GetSupportedSuites(msg); 413de9dcd41SStephan Aßmus } 414de9dcd41SStephan Aßmus 415de9dcd41SStephan Aßmus 416de9dcd41SStephan Aßmus void 4174ec6c3a0SAdrien Destugues NotificationView::SetText(float newMaxWidth) 418de9dcd41SStephan Aßmus { 419*e0890a26SAdrien Destugues if (newMaxWidth < 0) { 420*e0890a26SAdrien Destugues newMaxWidth = 200; 421*e0890a26SAdrien Destugues } 422de9dcd41SStephan Aßmus 423de9dcd41SStephan Aßmus // Delete old lines 424de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 425de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 426de9dcd41SStephan Aßmus delete (*lIt); 427de9dcd41SStephan Aßmus fLines.clear(); 428de9dcd41SStephan Aßmus 4290e07be06SAdrien Destugues float iconRight = kIconStripeWidth; 430de9dcd41SStephan Aßmus if (fBitmap != NULL) 4315414f4dcSAdrien Destugues iconRight += fParent->IconSize(); 4320e07be06SAdrien Destugues else 4335414f4dcSAdrien Destugues iconRight += 32; 434de9dcd41SStephan Aßmus 435de9dcd41SStephan Aßmus font_height fh; 436de9dcd41SStephan Aßmus be_bold_font->GetHeight(&fh); 437de9dcd41SStephan Aßmus float fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 438de9dcd41SStephan Aßmus + ceilf(fh.ascent); 4390e07be06SAdrien Destugues float y = 2 * fontHeight; 440de9dcd41SStephan Aßmus 441de9dcd41SStephan Aßmus // Title 442de9dcd41SStephan Aßmus LineInfo* titleLine = new LineInfo; 4434ec6c3a0SAdrien Destugues titleLine->text = fNotification->Title(); 444de9dcd41SStephan Aßmus titleLine->font = *be_bold_font; 445de9dcd41SStephan Aßmus 446de9dcd41SStephan Aßmus titleLine->location = BPoint(iconRight, y); 447de9dcd41SStephan Aßmus 448de9dcd41SStephan Aßmus fLines.push_front(titleLine); 449de9dcd41SStephan Aßmus y += fontHeight; 450de9dcd41SStephan Aßmus 451de9dcd41SStephan Aßmus // Rest of text is rendered with be_plain_font. 452de9dcd41SStephan Aßmus be_plain_font->GetHeight(&fh); 453de9dcd41SStephan Aßmus fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 454de9dcd41SStephan Aßmus + ceilf(fh.ascent); 455de9dcd41SStephan Aßmus 456de9dcd41SStephan Aßmus // Split text into chunks between certain characters and compose the lines. 457*e0890a26SAdrien Destugues const char kSeparatorCharacters[] = " \n-\\"; 4584ec6c3a0SAdrien Destugues BString textBuffer = fNotification->Content(); 459de9dcd41SStephan Aßmus textBuffer.ReplaceAll("\t", " "); 460de9dcd41SStephan Aßmus const char* chunkStart = textBuffer.String(); 461de9dcd41SStephan Aßmus float maxWidth = newMaxWidth - kEdgePadding - iconRight; 462de9dcd41SStephan Aßmus LineInfo* line = NULL; 463de9dcd41SStephan Aßmus ssize_t length = textBuffer.Length(); 464de9dcd41SStephan Aßmus while (chunkStart - textBuffer.String() < length) { 465de9dcd41SStephan Aßmus size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1; 466de9dcd41SStephan Aßmus 4674ec6c3a0SAdrien Destugues // Start a new line if we didn't start one before 46831a3c4e8SJérôme Duval BString tempText; 46931a3c4e8SJérôme Duval if (line != NULL) 47031a3c4e8SJérôme Duval tempText.SetTo(line->text); 471de9dcd41SStephan Aßmus tempText.Append(chunkStart, chunkLength); 472de9dcd41SStephan Aßmus 473de9dcd41SStephan Aßmus if (line == NULL || chunkStart[0] == '\n' 474de9dcd41SStephan Aßmus || StringWidth(tempText) > maxWidth) { 475de9dcd41SStephan Aßmus line = new LineInfo; 476de9dcd41SStephan Aßmus line->font = *be_plain_font; 477de9dcd41SStephan Aßmus line->location = BPoint(iconRight + kEdgePadding, y); 478de9dcd41SStephan Aßmus 479de9dcd41SStephan Aßmus fLines.push_front(line); 480de9dcd41SStephan Aßmus y += fontHeight; 481de9dcd41SStephan Aßmus 4824ec6c3a0SAdrien Destugues // Skip the eventual new-line character at the beginning of this chunk 483de9dcd41SStephan Aßmus if (chunkStart[0] == '\n') { 484de9dcd41SStephan Aßmus chunkStart++; 485de9dcd41SStephan Aßmus chunkLength--; 486de9dcd41SStephan Aßmus } 4874ec6c3a0SAdrien Destugues 4884ec6c3a0SAdrien Destugues // Skip more new-line characters and move the line further down 489de9dcd41SStephan Aßmus while (chunkStart[0] == '\n') { 490de9dcd41SStephan Aßmus chunkStart++; 491de9dcd41SStephan Aßmus chunkLength--; 492de9dcd41SStephan Aßmus line->location.y += fontHeight; 493de9dcd41SStephan Aßmus y += fontHeight; 494de9dcd41SStephan Aßmus } 4954ec6c3a0SAdrien Destugues 4964ec6c3a0SAdrien Destugues // Strip space at beginning of a new line 497de9dcd41SStephan Aßmus while (chunkStart[0] == ' ') { 498de9dcd41SStephan Aßmus chunkLength--; 499de9dcd41SStephan Aßmus chunkStart++; 500de9dcd41SStephan Aßmus } 501de9dcd41SStephan Aßmus } 502de9dcd41SStephan Aßmus 503de9dcd41SStephan Aßmus if (chunkStart[0] == '\0') 504de9dcd41SStephan Aßmus break; 505de9dcd41SStephan Aßmus 506de9dcd41SStephan Aßmus // Append the chunk to the current line, which was either a new 5074ec6c3a0SAdrien Destugues // line or the one from the previous iteration 508de9dcd41SStephan Aßmus line->text.Append(chunkStart, chunkLength); 509de9dcd41SStephan Aßmus 510de9dcd41SStephan Aßmus chunkStart += chunkLength; 511de9dcd41SStephan Aßmus } 512de9dcd41SStephan Aßmus 513de9dcd41SStephan Aßmus fHeight = y + (kEdgePadding * 2); 514de9dcd41SStephan Aßmus 515de9dcd41SStephan Aßmus // Make sure icon fits 516de9dcd41SStephan Aßmus if (fBitmap != NULL) { 5174ec6c3a0SAdrien Destugues float minHeight = fBitmap->Bounds().Height() + 2 * kEdgePadding; 518de9dcd41SStephan Aßmus 519de9dcd41SStephan Aßmus if (fHeight < minHeight) 520de9dcd41SStephan Aßmus fHeight = minHeight; 521de9dcd41SStephan Aßmus } 522*e0890a26SAdrien Destugues 523*e0890a26SAdrien Destugues // Make sure the progress bar is below the text, and the window is big 524*e0890a26SAdrien Destugues // enough. 525*e0890a26SAdrien Destugues static_cast<BGroupLayout*>(GetLayout())->SetInsets(kIconStripeWidth + 8, 526*e0890a26SAdrien Destugues fHeight, 8, 8); 527de9dcd41SStephan Aßmus } 528de9dcd41SStephan Aßmus 529de9dcd41SStephan Aßmus 530de9dcd41SStephan Aßmus const char* 5314ec6c3a0SAdrien Destugues NotificationView::MessageID() const 532de9dcd41SStephan Aßmus { 5334ec6c3a0SAdrien Destugues return fNotification->MessageID(); 534de9dcd41SStephan Aßmus } 535de9dcd41SStephan Aßmus 536de9dcd41SStephan Aßmus 5374ec6c3a0SAdrien Destugues BSize 5384ec6c3a0SAdrien Destugues NotificationView::_CalculateSize() 539de9dcd41SStephan Aßmus { 5404ec6c3a0SAdrien Destugues BSize size; 5414ec6c3a0SAdrien Destugues 5424ec6c3a0SAdrien Destugues // Parent width, minus the edge padding, minus the pensize 543*e0890a26SAdrien Destugues size.width = B_SIZE_UNLIMITED; 5444ec6c3a0SAdrien Destugues size.height = fHeight; 5454ec6c3a0SAdrien Destugues 5464ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) { 5474ec6c3a0SAdrien Destugues font_height fh; 5484ec6c3a0SAdrien Destugues be_plain_font->GetHeight(&fh); 5494ec6c3a0SAdrien Destugues float fontHeight = fh.ascent + fh.descent + fh.leading; 5504ec6c3a0SAdrien Destugues size.height += (kSmallPadding * 2) + (kEdgePadding * 1) + fontHeight; 551de9dcd41SStephan Aßmus } 552de9dcd41SStephan Aßmus 5534ec6c3a0SAdrien Destugues return size; 554de9dcd41SStephan Aßmus } 555