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*4ec6c3a0SAdrien Destugues #include <LayoutUtils.h> 18de9dcd41SStephan Aßmus #include <Messenger.h> 19*4ec6c3a0SAdrien Destugues #include <Path.h> 20de9dcd41SStephan Aßmus #include <Roster.h> 21beeda306SAdrien Destugues #include <StatusBar.h> 22de9dcd41SStephan Aßmus 23de9dcd41SStephan Aßmus #include "NotificationView.h" 24de9dcd41SStephan Aßmus #include "NotificationWindow.h" 25de9dcd41SStephan Aßmus 260e07be06SAdrien Destugues static const int kIconStripeWidth = 32; 279dcd41a8SAdrien Destugues 28de9dcd41SStephan Aßmus property_info message_prop_list[] = { 29de9dcd41SStephan Aßmus { "type", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 30de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the notification type"}, 31de9dcd41SStephan Aßmus { "app", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 32de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's app"}, 33de9dcd41SStephan Aßmus { "title", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 34de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's title"}, 35de9dcd41SStephan Aßmus { "content", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 36de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's contents"}, 37de9dcd41SStephan Aßmus { "icon", {B_GET_PROPERTY, 0}, 38de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get icon as an archived bitmap"}, 39de9dcd41SStephan Aßmus { "progress", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 40de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the progress (between 0.0 and 1.0)"}, 41de9dcd41SStephan Aßmus { NULL } 42de9dcd41SStephan Aßmus }; 43de9dcd41SStephan Aßmus 44de9dcd41SStephan Aßmus 45de9dcd41SStephan Aßmus NotificationView::NotificationView(NotificationWindow* win, 46*4ec6c3a0SAdrien Destugues BNotification* notification, bigtime_t timeout) 47de9dcd41SStephan Aßmus : 48*4ec6c3a0SAdrien Destugues BView("NotificationView", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE 49de9dcd41SStephan Aßmus | B_FRAME_EVENTS), 50de9dcd41SStephan Aßmus fParent(win), 51*4ec6c3a0SAdrien Destugues fNotification(notification), 52*4ec6c3a0SAdrien Destugues fTimeout(timeout), 53de9dcd41SStephan Aßmus fRunner(NULL), 54*4ec6c3a0SAdrien Destugues fBitmap(NULL) 55de9dcd41SStephan Aßmus { 56*4ec6c3a0SAdrien Destugues if (fNotification->Icon() != NULL) 57*4ec6c3a0SAdrien Destugues fBitmap = new BBitmap(fNotification->Icon()); 58de9dcd41SStephan Aßmus 59*4ec6c3a0SAdrien Destugues if (fTimeout <= 0) 60*4ec6c3a0SAdrien Destugues fTimeout = fParent->Timeout() * 1000000; 61de9dcd41SStephan Aßmus 62*4ec6c3a0SAdrien Destugues SetText(); 63de9dcd41SStephan Aßmus 64*4ec6c3a0SAdrien Destugues switch (fNotification->Type()) { 65de9dcd41SStephan Aßmus case B_IMPORTANT_NOTIFICATION: 66de9dcd41SStephan Aßmus SetViewColor(255, 255, 255); 67de9dcd41SStephan Aßmus SetLowColor(255, 255, 255); 68de9dcd41SStephan Aßmus break; 69de9dcd41SStephan Aßmus case B_ERROR_NOTIFICATION: 70de9dcd41SStephan Aßmus SetViewColor(ui_color(B_FAILURE_COLOR)); 71de9dcd41SStephan Aßmus SetLowColor(ui_color(B_FAILURE_COLOR)); 72de9dcd41SStephan Aßmus break; 73beeda306SAdrien Destugues case B_PROGRESS_NOTIFICATION: 74beeda306SAdrien Destugues { 7514ac1ee9SAdrien Destugues BRect frame(kIconStripeWidth + 9, Bounds().bottom - 36, 7614ac1ee9SAdrien Destugues Bounds().right - 8, Bounds().bottom - 10); 77beeda306SAdrien Destugues BStatusBar* progress = new BStatusBar(frame, "progress"); 78beeda306SAdrien Destugues progress->SetBarHeight(12.0f); 79beeda306SAdrien Destugues progress->SetMaxValue(1.0f); 80*4ec6c3a0SAdrien Destugues progress->Update(fNotification->Progress()); 81beeda306SAdrien Destugues 82beeda306SAdrien Destugues BString label = ""; 83*4ec6c3a0SAdrien Destugues label << (int)(fNotification->Progress() * 100) << " %"; 84beeda306SAdrien Destugues progress->SetTrailingText(label); 85beeda306SAdrien Destugues 86beeda306SAdrien Destugues AddChild(progress); 87beeda306SAdrien Destugues } 88*4ec6c3a0SAdrien Destugues // fall through 89de9dcd41SStephan Aßmus default: 90de9dcd41SStephan Aßmus SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 91de9dcd41SStephan Aßmus SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 92de9dcd41SStephan Aßmus } 93de9dcd41SStephan Aßmus } 94de9dcd41SStephan Aßmus 95de9dcd41SStephan Aßmus 96de9dcd41SStephan Aßmus NotificationView::~NotificationView() 97de9dcd41SStephan Aßmus { 98de9dcd41SStephan Aßmus delete fRunner; 99de9dcd41SStephan Aßmus delete fBitmap; 100*4ec6c3a0SAdrien Destugues delete fNotification; 101de9dcd41SStephan Aßmus 102de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 103de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 104de9dcd41SStephan Aßmus delete (*lIt); 105de9dcd41SStephan Aßmus } 106de9dcd41SStephan Aßmus 107de9dcd41SStephan Aßmus 108de9dcd41SStephan Aßmus void 109de9dcd41SStephan Aßmus NotificationView::AttachedToWindow() 110de9dcd41SStephan Aßmus { 111de9dcd41SStephan Aßmus BMessage msg(kRemoveView); 112de9dcd41SStephan Aßmus msg.AddPointer("view", this); 113de9dcd41SStephan Aßmus 114*4ec6c3a0SAdrien Destugues fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1); 115de9dcd41SStephan Aßmus } 116de9dcd41SStephan Aßmus 117de9dcd41SStephan Aßmus 118de9dcd41SStephan Aßmus void 119de9dcd41SStephan Aßmus NotificationView::MessageReceived(BMessage* msg) 120de9dcd41SStephan Aßmus { 121de9dcd41SStephan Aßmus switch (msg->what) { 122de9dcd41SStephan Aßmus case B_GET_PROPERTY: 123de9dcd41SStephan Aßmus { 124de9dcd41SStephan Aßmus BMessage specifier; 125de9dcd41SStephan Aßmus const char* property; 126de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 127de9dcd41SStephan Aßmus bool msgOkay = true; 128de9dcd41SStephan Aßmus 129de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 130de9dcd41SStephan Aßmus msgOkay = false; 131de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 132de9dcd41SStephan Aßmus msgOkay = false; 133de9dcd41SStephan Aßmus 134de9dcd41SStephan Aßmus if (msgOkay) { 135de9dcd41SStephan Aßmus if (strcmp(property, "type") == 0) 136*4ec6c3a0SAdrien Destugues reply.AddInt32("result", fNotification->Type()); 137de9dcd41SStephan Aßmus 138*4ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 139*4ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Group()); 140de9dcd41SStephan Aßmus 141de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 142*4ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Title()); 143de9dcd41SStephan Aßmus 144de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 145*4ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Content()); 146de9dcd41SStephan Aßmus 147de9dcd41SStephan Aßmus if (strcmp(property, "progress") == 0) 148*4ec6c3a0SAdrien Destugues reply.AddFloat("result", fNotification->Progress()); 149de9dcd41SStephan Aßmus 150de9dcd41SStephan Aßmus if ((strcmp(property, "icon") == 0) && fBitmap) { 151de9dcd41SStephan Aßmus BMessage archive; 152de9dcd41SStephan Aßmus if (fBitmap->Archive(&archive) == B_OK) 153de9dcd41SStephan Aßmus reply.AddMessage("result", &archive); 154de9dcd41SStephan Aßmus } 155de9dcd41SStephan Aßmus 156de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 157de9dcd41SStephan Aßmus } else { 158de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 159de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 160de9dcd41SStephan Aßmus } 161de9dcd41SStephan Aßmus 162de9dcd41SStephan Aßmus msg->SendReply(&reply); 163de9dcd41SStephan Aßmus break; 164de9dcd41SStephan Aßmus } 165de9dcd41SStephan Aßmus case B_SET_PROPERTY: 166de9dcd41SStephan Aßmus { 167de9dcd41SStephan Aßmus BMessage specifier; 168de9dcd41SStephan Aßmus const char* property; 169de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 170de9dcd41SStephan Aßmus bool msgOkay = true; 171de9dcd41SStephan Aßmus 172de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 173de9dcd41SStephan Aßmus msgOkay = false; 174de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 175de9dcd41SStephan Aßmus msgOkay = false; 176de9dcd41SStephan Aßmus 177de9dcd41SStephan Aßmus if (msgOkay) { 178*4ec6c3a0SAdrien Destugues const char* value = NULL; 179*4ec6c3a0SAdrien Destugues 180*4ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 181*4ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 182*4ec6c3a0SAdrien Destugues fNotification->SetGroup(value); 183de9dcd41SStephan Aßmus 184de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 185*4ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 186*4ec6c3a0SAdrien Destugues fNotification->SetTitle(value); 187de9dcd41SStephan Aßmus 188de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 189*4ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 190*4ec6c3a0SAdrien Destugues fNotification->SetContent(value); 191de9dcd41SStephan Aßmus 192de9dcd41SStephan Aßmus if (strcmp(property, "icon") == 0) { 193de9dcd41SStephan Aßmus BMessage archive; 194de9dcd41SStephan Aßmus if (msg->FindMessage("data", &archive) == B_OK) { 195de9dcd41SStephan Aßmus delete fBitmap; 196de9dcd41SStephan Aßmus fBitmap = new BBitmap(&archive); 197de9dcd41SStephan Aßmus } 198de9dcd41SStephan Aßmus } 199de9dcd41SStephan Aßmus 200*4ec6c3a0SAdrien Destugues SetText(); 201de9dcd41SStephan Aßmus Invalidate(); 202de9dcd41SStephan Aßmus 203de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 204de9dcd41SStephan Aßmus } else { 205de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 206de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 207de9dcd41SStephan Aßmus } 208de9dcd41SStephan Aßmus 209de9dcd41SStephan Aßmus msg->SendReply(&reply); 210de9dcd41SStephan Aßmus break; 211de9dcd41SStephan Aßmus } 212de9dcd41SStephan Aßmus default: 213de9dcd41SStephan Aßmus BView::MessageReceived(msg); 214de9dcd41SStephan Aßmus } 215de9dcd41SStephan Aßmus } 216de9dcd41SStephan Aßmus 217de9dcd41SStephan Aßmus 218de9dcd41SStephan Aßmus void 219de9dcd41SStephan Aßmus NotificationView::Draw(BRect updateRect) 220de9dcd41SStephan Aßmus { 221de9dcd41SStephan Aßmus BRect progRect; 222de9dcd41SStephan Aßmus 223de9dcd41SStephan Aßmus SetDrawingMode(B_OP_ALPHA); 224de9dcd41SStephan Aßmus SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 225de9dcd41SStephan Aßmus 226de9dcd41SStephan Aßmus // Icon size 227de9dcd41SStephan Aßmus float iconSize = (float)fParent->IconSize(); 228de9dcd41SStephan Aßmus 2299dcd41a8SAdrien Destugues BRect stripeRect = Bounds(); 2300e07be06SAdrien Destugues stripeRect.right = kIconStripeWidth; 2319dcd41a8SAdrien Destugues SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 2329dcd41a8SAdrien Destugues FillRect(stripeRect); 2339dcd41a8SAdrien Destugues 2349dcd41a8SAdrien Destugues SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); 235de9dcd41SStephan Aßmus // Rectangle for icon and overlay icon 236de9dcd41SStephan Aßmus BRect iconRect(0, 0, 0, 0); 237de9dcd41SStephan Aßmus 238de9dcd41SStephan Aßmus // Draw icon 239de9dcd41SStephan Aßmus if (fBitmap) { 2405414f4dcSAdrien Destugues float ix = 18; 2415414f4dcSAdrien Destugues float iy = (Bounds().Height() - iconSize) / 4.0; 2420e07be06SAdrien Destugues // Icon is vertically centered in view 243de9dcd41SStephan Aßmus 244*4ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) 2450e07be06SAdrien Destugues { 246de9dcd41SStephan Aßmus // Move icon up by half progress bar height if it's present 2470e07be06SAdrien Destugues iy -= (progRect.Height() + kEdgePadding); 2480e07be06SAdrien Destugues } 249de9dcd41SStephan Aßmus 2507dd47a9bSPhilippe Houdoin iconRect.Set(ix, iy, ix + iconSize - 1.0, iy + iconSize - 1.0); 251bdde2d30SPhilippe Houdoin DrawBitmapAsync(fBitmap, fBitmap->Bounds(), iconRect); 252de9dcd41SStephan Aßmus } 253de9dcd41SStephan Aßmus 254de9dcd41SStephan Aßmus // Draw content 255de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 256de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) { 257de9dcd41SStephan Aßmus LineInfo *l = (*lIt); 258de9dcd41SStephan Aßmus 259de9dcd41SStephan Aßmus SetFont(&l->font); 260de9dcd41SStephan Aßmus DrawString(l->text.String(), l->text.Length(), l->location); 261de9dcd41SStephan Aßmus } 262de9dcd41SStephan Aßmus 263de9dcd41SStephan Aßmus rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR); 264de9dcd41SStephan Aßmus detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT); 265de9dcd41SStephan Aßmus 266de9dcd41SStephan Aßmus // Draw the close widget 267de9dcd41SStephan Aßmus BRect closeRect = Bounds(); 2680e07be06SAdrien Destugues closeRect.InsetBy(2 * kEdgePadding, 2 * kEdgePadding); 269de9dcd41SStephan Aßmus closeRect.left = closeRect.right - kCloseSize; 270de9dcd41SStephan Aßmus closeRect.bottom = closeRect.top + kCloseSize; 271de9dcd41SStephan Aßmus 272de9dcd41SStephan Aßmus PushState(); 273de9dcd41SStephan Aßmus SetHighColor(detailCol); 274de9dcd41SStephan Aßmus StrokeRoundRect(closeRect, kSmallPadding, kSmallPadding); 275de9dcd41SStephan Aßmus BRect closeCross = closeRect.InsetByCopy(kSmallPadding, kSmallPadding); 276de9dcd41SStephan Aßmus StrokeLine(closeCross.LeftTop(), closeCross.RightBottom()); 277de9dcd41SStephan Aßmus StrokeLine(closeCross.LeftBottom(), closeCross.RightTop()); 278de9dcd41SStephan Aßmus PopState(); 279de9dcd41SStephan Aßmus 2805414f4dcSAdrien Destugues SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 2815414f4dcSAdrien Destugues BPoint left(Bounds().left, Bounds().bottom - 1); 2825414f4dcSAdrien Destugues BPoint right(Bounds().right, Bounds().bottom - 1); 2835414f4dcSAdrien Destugues StrokeLine(left, right); 2845414f4dcSAdrien Destugues 285de9dcd41SStephan Aßmus Sync(); 286de9dcd41SStephan Aßmus } 287de9dcd41SStephan Aßmus 288de9dcd41SStephan Aßmus 289de9dcd41SStephan Aßmus void 290de9dcd41SStephan Aßmus NotificationView::MouseDown(BPoint point) 291de9dcd41SStephan Aßmus { 292de9dcd41SStephan Aßmus int32 buttons; 293de9dcd41SStephan Aßmus Window()->CurrentMessage()->FindInt32("buttons", &buttons); 294de9dcd41SStephan Aßmus 295de9dcd41SStephan Aßmus switch (buttons) { 296de9dcd41SStephan Aßmus case B_PRIMARY_MOUSE_BUTTON: 297de9dcd41SStephan Aßmus { 298de9dcd41SStephan Aßmus BRect closeRect = Bounds().InsetByCopy(2,2); 299de9dcd41SStephan Aßmus closeRect.left = closeRect.right - kCloseSize; 300de9dcd41SStephan Aßmus closeRect.bottom = closeRect.top + kCloseSize; 301de9dcd41SStephan Aßmus 302de9dcd41SStephan Aßmus if (!closeRect.Contains(point)) { 303de9dcd41SStephan Aßmus entry_ref launchRef; 304de9dcd41SStephan Aßmus BString launchString; 305de9dcd41SStephan Aßmus BMessage argMsg(B_ARGV_RECEIVED); 306de9dcd41SStephan Aßmus BMessage refMsg(B_REFS_RECEIVED); 307de9dcd41SStephan Aßmus entry_ref appRef; 308de9dcd41SStephan Aßmus bool useArgv = false; 309de9dcd41SStephan Aßmus BList messages; 310de9dcd41SStephan Aßmus entry_ref ref; 311de9dcd41SStephan Aßmus 312*4ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL 313*4ec6c3a0SAdrien Destugues && be_roster->FindApp(fNotification->OnClickApp(), &appRef) 314*4ec6c3a0SAdrien Destugues == B_OK) { 315de9dcd41SStephan Aßmus useArgv = true; 316de9dcd41SStephan Aßmus } 317de9dcd41SStephan Aßmus 318*4ec6c3a0SAdrien Destugues if (fNotification->OnClickFile() != NULL 319*4ec6c3a0SAdrien Destugues && be_roster->FindApp( 320*4ec6c3a0SAdrien Destugues (entry_ref*)fNotification->OnClickFile(), &appRef) 321*4ec6c3a0SAdrien Destugues == B_OK) { 322*4ec6c3a0SAdrien Destugues useArgv = true; 323*4ec6c3a0SAdrien Destugues } 324de9dcd41SStephan Aßmus 325*4ec6c3a0SAdrien Destugues for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++) 326*4ec6c3a0SAdrien Destugues refMsg.AddRef("refs", fNotification->OnClickRefAt(i)); 327de9dcd41SStephan Aßmus messages.AddItem((void*)&refMsg); 328de9dcd41SStephan Aßmus 329de9dcd41SStephan Aßmus if (useArgv) { 330*4ec6c3a0SAdrien Destugues int32 argc = fNotification->CountOnClickArgs() + 1; 331de9dcd41SStephan Aßmus BString arg; 332de9dcd41SStephan Aßmus 333de9dcd41SStephan Aßmus BPath p(&appRef); 334de9dcd41SStephan Aßmus argMsg.AddString("argv", p.Path()); 335de9dcd41SStephan Aßmus 336*4ec6c3a0SAdrien Destugues argMsg.AddInt32("argc", argc); 337de9dcd41SStephan Aßmus 338*4ec6c3a0SAdrien Destugues for (int32 i = 0; i < argc - 1; i++) { 339*4ec6c3a0SAdrien Destugues argMsg.AddString("argv", 340*4ec6c3a0SAdrien Destugues fNotification->OnClickArgAt(i)); 341*4ec6c3a0SAdrien Destugues } 342de9dcd41SStephan Aßmus 343de9dcd41SStephan Aßmus messages.AddItem((void*)&argMsg); 344de9dcd41SStephan Aßmus } 345de9dcd41SStephan Aßmus 346*4ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL) 347*4ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickApp(), &messages); 348de9dcd41SStephan Aßmus else 349*4ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickFile(), &messages); 350de9dcd41SStephan Aßmus } 351de9dcd41SStephan Aßmus 352de9dcd41SStephan Aßmus // Remove the info view after a click 353de9dcd41SStephan Aßmus BMessage remove_msg(kRemoveView); 354de9dcd41SStephan Aßmus remove_msg.AddPointer("view", this); 355de9dcd41SStephan Aßmus 356de9dcd41SStephan Aßmus BMessenger msgr(Parent()); 357de9dcd41SStephan Aßmus msgr.SendMessage(&remove_msg); 358de9dcd41SStephan Aßmus break; 359de9dcd41SStephan Aßmus } 360de9dcd41SStephan Aßmus } 361de9dcd41SStephan Aßmus } 362de9dcd41SStephan Aßmus 363de9dcd41SStephan Aßmus 364*4ec6c3a0SAdrien Destugues BSize 365*4ec6c3a0SAdrien Destugues NotificationView::MinSize() 366de9dcd41SStephan Aßmus { 367*4ec6c3a0SAdrien Destugues return BLayoutUtils::ComposeSize(ExplicitMinSize(), _CalculateSize()); 368*4ec6c3a0SAdrien Destugues } 369*4ec6c3a0SAdrien Destugues 370*4ec6c3a0SAdrien Destugues 371*4ec6c3a0SAdrien Destugues BSize 372*4ec6c3a0SAdrien Destugues NotificationView::MaxSize() 373*4ec6c3a0SAdrien Destugues { 374*4ec6c3a0SAdrien Destugues return BLayoutUtils::ComposeSize(ExplicitMaxSize(), _CalculateSize()); 375*4ec6c3a0SAdrien Destugues } 376*4ec6c3a0SAdrien Destugues 377*4ec6c3a0SAdrien Destugues 378*4ec6c3a0SAdrien Destugues BSize 379*4ec6c3a0SAdrien Destugues NotificationView::PreferredSize() 380*4ec6c3a0SAdrien Destugues { 381*4ec6c3a0SAdrien Destugues return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), 382*4ec6c3a0SAdrien Destugues _CalculateSize()); 383de9dcd41SStephan Aßmus } 384de9dcd41SStephan Aßmus 385de9dcd41SStephan Aßmus 386de9dcd41SStephan Aßmus BHandler* 387*4ec6c3a0SAdrien Destugues NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, 388*4ec6c3a0SAdrien Destugues int32 form, const char* prop) 389de9dcd41SStephan Aßmus { 390de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 391de9dcd41SStephan Aßmus if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) { 392de9dcd41SStephan Aßmus msg->PopSpecifier(); 393de9dcd41SStephan Aßmus return this; 394de9dcd41SStephan Aßmus } 395de9dcd41SStephan Aßmus 396de9dcd41SStephan Aßmus return BView::ResolveSpecifier(msg, index, spec, form, prop); 397de9dcd41SStephan Aßmus } 398de9dcd41SStephan Aßmus 399de9dcd41SStephan Aßmus 400de9dcd41SStephan Aßmus status_t 401de9dcd41SStephan Aßmus NotificationView::GetSupportedSuites(BMessage* msg) 402de9dcd41SStephan Aßmus { 403de9dcd41SStephan Aßmus msg->AddString("suites", "suite/x-vnd.Haiku-notification_server"); 404de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 405de9dcd41SStephan Aßmus msg->AddFlat("messages", &prop_info); 406de9dcd41SStephan Aßmus return BView::GetSupportedSuites(msg); 407de9dcd41SStephan Aßmus } 408de9dcd41SStephan Aßmus 409de9dcd41SStephan Aßmus 410de9dcd41SStephan Aßmus void 411*4ec6c3a0SAdrien Destugues NotificationView::SetText(float newMaxWidth) 412de9dcd41SStephan Aßmus { 413de9dcd41SStephan Aßmus if (newMaxWidth < 0) 414de9dcd41SStephan Aßmus newMaxWidth = Bounds().Width() - (kEdgePadding * 2); 415de9dcd41SStephan Aßmus 416de9dcd41SStephan Aßmus // Delete old lines 417de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 418de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 419de9dcd41SStephan Aßmus delete (*lIt); 420de9dcd41SStephan Aßmus fLines.clear(); 421de9dcd41SStephan Aßmus 4220e07be06SAdrien Destugues float iconRight = kIconStripeWidth; 423de9dcd41SStephan Aßmus if (fBitmap != NULL) 4245414f4dcSAdrien Destugues iconRight += fParent->IconSize(); 4250e07be06SAdrien Destugues else 4265414f4dcSAdrien Destugues iconRight += 32; 427de9dcd41SStephan Aßmus 428de9dcd41SStephan Aßmus font_height fh; 429de9dcd41SStephan Aßmus be_bold_font->GetHeight(&fh); 430de9dcd41SStephan Aßmus float fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 431de9dcd41SStephan Aßmus + ceilf(fh.ascent); 4320e07be06SAdrien Destugues float y = 2 * fontHeight; 433de9dcd41SStephan Aßmus 434de9dcd41SStephan Aßmus // Title 435de9dcd41SStephan Aßmus LineInfo* titleLine = new LineInfo; 436*4ec6c3a0SAdrien Destugues titleLine->text = fNotification->Title(); 437de9dcd41SStephan Aßmus titleLine->font = *be_bold_font; 438de9dcd41SStephan Aßmus 439de9dcd41SStephan Aßmus titleLine->location = BPoint(iconRight, y); 440de9dcd41SStephan Aßmus 441de9dcd41SStephan Aßmus fLines.push_front(titleLine); 442de9dcd41SStephan Aßmus y += fontHeight; 443de9dcd41SStephan Aßmus 444de9dcd41SStephan Aßmus // Rest of text is rendered with be_plain_font. 445de9dcd41SStephan Aßmus be_plain_font->GetHeight(&fh); 446de9dcd41SStephan Aßmus fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 447de9dcd41SStephan Aßmus + ceilf(fh.ascent); 448de9dcd41SStephan Aßmus 449de9dcd41SStephan Aßmus // Split text into chunks between certain characters and compose the lines. 450de9dcd41SStephan Aßmus const char kSeparatorCharacters[] = " \n-\\/"; 451*4ec6c3a0SAdrien Destugues BString textBuffer = fNotification->Content(); 452de9dcd41SStephan Aßmus textBuffer.ReplaceAll("\t", " "); 453de9dcd41SStephan Aßmus const char* chunkStart = textBuffer.String(); 454de9dcd41SStephan Aßmus float maxWidth = newMaxWidth - kEdgePadding - iconRight; 455de9dcd41SStephan Aßmus LineInfo* line = NULL; 456de9dcd41SStephan Aßmus ssize_t length = textBuffer.Length(); 457de9dcd41SStephan Aßmus while (chunkStart - textBuffer.String() < length) { 458de9dcd41SStephan Aßmus size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1; 459de9dcd41SStephan Aßmus 460*4ec6c3a0SAdrien Destugues // Start a new line if we didn't start one before 46131a3c4e8SJérôme Duval BString tempText; 46231a3c4e8SJérôme Duval if (line != NULL) 46331a3c4e8SJérôme Duval tempText.SetTo(line->text); 464de9dcd41SStephan Aßmus tempText.Append(chunkStart, chunkLength); 465de9dcd41SStephan Aßmus 466de9dcd41SStephan Aßmus if (line == NULL || chunkStart[0] == '\n' 467de9dcd41SStephan Aßmus || StringWidth(tempText) > maxWidth) { 468de9dcd41SStephan Aßmus line = new LineInfo; 469de9dcd41SStephan Aßmus line->font = *be_plain_font; 470de9dcd41SStephan Aßmus line->location = BPoint(iconRight + kEdgePadding, y); 471de9dcd41SStephan Aßmus 472de9dcd41SStephan Aßmus fLines.push_front(line); 473de9dcd41SStephan Aßmus y += fontHeight; 474de9dcd41SStephan Aßmus 475*4ec6c3a0SAdrien Destugues // Skip the eventual new-line character at the beginning of this chunk 476de9dcd41SStephan Aßmus if (chunkStart[0] == '\n') { 477de9dcd41SStephan Aßmus chunkStart++; 478de9dcd41SStephan Aßmus chunkLength--; 479de9dcd41SStephan Aßmus } 480*4ec6c3a0SAdrien Destugues 481*4ec6c3a0SAdrien Destugues // Skip more new-line characters and move the line further down 482de9dcd41SStephan Aßmus while (chunkStart[0] == '\n') { 483de9dcd41SStephan Aßmus chunkStart++; 484de9dcd41SStephan Aßmus chunkLength--; 485de9dcd41SStephan Aßmus line->location.y += fontHeight; 486de9dcd41SStephan Aßmus y += fontHeight; 487de9dcd41SStephan Aßmus } 488*4ec6c3a0SAdrien Destugues 489*4ec6c3a0SAdrien Destugues // Strip space at beginning of a new line 490de9dcd41SStephan Aßmus while (chunkStart[0] == ' ') { 491de9dcd41SStephan Aßmus chunkLength--; 492de9dcd41SStephan Aßmus chunkStart++; 493de9dcd41SStephan Aßmus } 494de9dcd41SStephan Aßmus } 495de9dcd41SStephan Aßmus 496de9dcd41SStephan Aßmus if (chunkStart[0] == '\0') 497de9dcd41SStephan Aßmus break; 498de9dcd41SStephan Aßmus 499de9dcd41SStephan Aßmus // Append the chunk to the current line, which was either a new 500*4ec6c3a0SAdrien Destugues // line or the one from the previous iteration 501de9dcd41SStephan Aßmus line->text.Append(chunkStart, chunkLength); 502de9dcd41SStephan Aßmus 503de9dcd41SStephan Aßmus chunkStart += chunkLength; 504de9dcd41SStephan Aßmus } 505de9dcd41SStephan Aßmus 506de9dcd41SStephan Aßmus fHeight = y + (kEdgePadding * 2); 507de9dcd41SStephan Aßmus 508de9dcd41SStephan Aßmus // Make sure icon fits 509de9dcd41SStephan Aßmus if (fBitmap != NULL) { 510*4ec6c3a0SAdrien Destugues float minHeight = fBitmap->Bounds().Height() + 2 * kEdgePadding; 511de9dcd41SStephan Aßmus 512de9dcd41SStephan Aßmus if (fHeight < minHeight) 513de9dcd41SStephan Aßmus fHeight = minHeight; 514de9dcd41SStephan Aßmus } 515de9dcd41SStephan Aßmus } 516de9dcd41SStephan Aßmus 517de9dcd41SStephan Aßmus 518de9dcd41SStephan Aßmus const char* 519*4ec6c3a0SAdrien Destugues NotificationView::MessageID() const 520de9dcd41SStephan Aßmus { 521*4ec6c3a0SAdrien Destugues return fNotification->MessageID(); 522de9dcd41SStephan Aßmus } 523de9dcd41SStephan Aßmus 524de9dcd41SStephan Aßmus 525*4ec6c3a0SAdrien Destugues BSize 526*4ec6c3a0SAdrien Destugues NotificationView::_CalculateSize() 527de9dcd41SStephan Aßmus { 528*4ec6c3a0SAdrien Destugues BSize size; 529*4ec6c3a0SAdrien Destugues 530*4ec6c3a0SAdrien Destugues // Parent width, minus the edge padding, minus the pensize 531*4ec6c3a0SAdrien Destugues size.width = fParent->Width() - (kEdgePadding * 2) - (kPenSize * 2); 532*4ec6c3a0SAdrien Destugues size.height = fHeight; 533*4ec6c3a0SAdrien Destugues 534*4ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) { 535*4ec6c3a0SAdrien Destugues font_height fh; 536*4ec6c3a0SAdrien Destugues be_plain_font->GetHeight(&fh); 537*4ec6c3a0SAdrien Destugues float fontHeight = fh.ascent + fh.descent + fh.leading; 538*4ec6c3a0SAdrien Destugues size.height += (kSmallPadding * 2) + (kEdgePadding * 1) + fontHeight; 539de9dcd41SStephan Aßmus } 540de9dcd41SStephan Aßmus 541*4ec6c3a0SAdrien Destugues return size; 542de9dcd41SStephan Aßmus } 543