1de9dcd41SStephan Aßmus/*
26aa05872SBrian 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>
146aa05872SBrian 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
396aa05872SBrian Hillconst int kIconStripeWidth			= 32;
406aa05872SBrian Hillconst float kCloseSize				= 6;
416aa05872SBrian Hillconst float kEdgePadding			= 2;
426aa05872SBrian Hillconst float kSmallPadding			= 2;
439dcd41a8SAdrien Destugues
44de9dcd41SStephan Aßmusproperty_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)"},
5716af9b4cSHumdinger
5816af9b4cSHumdinger	{ 0 }
59de9dcd41SStephan Aßmus};
60de9dcd41SStephan Aßmus
61de9dcd41SStephan Aßmus
626aa05872SBrian HillNotificationView::NotificationView(BNotification* notification, bigtime_t timeout,
636aa05872SBrian Hill	float iconSize, bool disableTimeout)
64de9dcd41SStephan Aßmus	:
6544c6e69bSAdrien Destugues	BView("NotificationView", B_WILL_DRAW),
664ec6c3a0SAdrien Destugues	fNotification(notification),
674ec6c3a0SAdrien Destugues	fTimeout(timeout),
686aa05872SBrian Hill	fIconSize(iconSize),
696aa05872SBrian Hill	fDisableTimeout(disableTimeout),
70de9dcd41SStephan Aßmus	fRunner(NULL),
7182a67460SAdrien Destugues - PulkoMandy	fBitmap(NULL),
726aa05872SBrian Hill	fCloseClicked(false),
736aa05872SBrian Hill	fPreviewModeOn(false)
74de9dcd41SStephan Aßmus{
754ec6c3a0SAdrien Destugues	if (fNotification->Icon() != NULL)
764ec6c3a0SAdrien Destugues		fBitmap = new BBitmap(fNotification->Icon());
77de9dcd41SStephan Aßmus
78e0890a26SAdrien Destugues	BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
79e0890a26SAdrien Destugues	SetLayout(layout);
80e0890a26SAdrien Destugues
811a8c00c1Slooncraz	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
8248d90a50SAdrien Destugues	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
83569a7bfcSAdrien Destugues
844ec6c3a0SAdrien Destugues	switch (fNotification->Type()) {
85de9dcd41SStephan Aßmus		case B_IMPORTANT_NOTIFICATION:
8648d90a50SAdrien Destugues			fStripeColor = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
87de9dcd41SStephan Aßmus			break;
88de9dcd41SStephan Aßmus		case B_ERROR_NOTIFICATION:
8948d90a50SAdrien Destugues			fStripeColor = ui_color(B_FAILURE_COLOR);
90de9dcd41SStephan Aßmus			break;
91beeda306SAdrien Destugues		case B_PROGRESS_NOTIFICATION:
92beeda306SAdrien Destugues		{
93e0890a26SAdrien Destugues			BStatusBar* progress = new BStatusBar("progress");
94beeda306SAdrien Destugues			progress->SetBarHeight(12.0f);
95beeda306SAdrien Destugues			progress->SetMaxValue(1.0f);
964ec6c3a0SAdrien Destugues			progress->Update(fNotification->Progress());
97569a7bfcSAdrien Destugues
98beeda306SAdrien Destugues			BString label = "";
994ec6c3a0SAdrien Destugues			label << (int)(fNotification->Progress() * 100) << " %";
100beeda306SAdrien Destugues			progress->SetTrailingText(label);
101e0890a26SAdrien Destugues
10244c6e69bSAdrien Destugues			layout->AddView(progress);
103beeda306SAdrien Destugues		}
10448d90a50SAdrien Destugues		// fall through.
10548d90a50SAdrien Destugues		case B_INFORMATION_NOTIFICATION:
10648d90a50SAdrien Destugues			fStripeColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
10748d90a50SAdrien Destugues				B_DARKEN_1_TINT);
10848d90a50SAdrien Destugues			break;
109de9dcd41SStephan Aßmus	}
110de9dcd41SStephan Aßmus}
111de9dcd41SStephan Aßmus
112de9dcd41SStephan Aßmus
113de9dcd41SStephan AßmusNotificationView::~NotificationView()
114de9dcd41SStephan Aßmus{
115de9dcd41SStephan Aßmus	delete fRunner;
116de9dcd41SStephan Aßmus	delete fBitmap;
1174ec6c3a0SAdrien Destugues	delete fNotification;
118de9dcd41SStephan Aßmus
119de9dcd41SStephan Aßmus	LineInfoList::iterator lIt;
120de9dcd41SStephan Aßmus	for (lIt = fLines.begin(); lIt != fLines.end(); lIt++)
121de9dcd41SStephan Aßmus		delete (*lIt);
122de9dcd41SStephan Aßmus}
123de9dcd41SStephan Aßmus
124de9dcd41SStephan Aßmus
125de9dcd41SStephan Aßmusvoid
126de9dcd41SStephan AßmusNotificationView::AttachedToWindow()
127de9dcd41SStephan Aßmus{
1282a740449SFrançois Revol	SetText();
1296aa05872SBrian Hill
1306aa05872SBrian Hill	if (!fDisableTimeout) {
1316aa05872SBrian Hill		BMessage msg(kRemoveView);
1326aa05872SBrian Hill		msg.AddPointer("view", this);
1336aa05872SBrian Hill		fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1);
1346aa05872SBrian Hill	}
135de9dcd41SStephan Aßmus}
136de9dcd41SStephan Aßmus
137de9dcd41SStephan Aßmus
138de9dcd41SStephan Aßmusvoid
139de9dcd41SStephan AßmusNotificationView::MessageReceived(BMessage* msg)
140de9dcd41SStephan Aßmus{
141de9dcd41SStephan Aßmus	switch (msg->what) {
142de9dcd41SStephan Aßmus		case B_GET_PROPERTY:
143de9dcd41SStephan Aßmus		{
144de9dcd41SStephan Aßmus			BMessage specifier;
145de9dcd41SStephan Aßmus			const char* property;
146de9dcd41SStephan Aßmus			BMessage reply(B_REPLY);
147de9dcd41SStephan Aßmus			bool msgOkay = true;
148de9dcd41SStephan Aßmus
149de9dcd41SStephan Aßmus			if (msg->FindMessage("specifiers", 0, &specifier) != B_OK)
150de9dcd41SStephan Aßmus				msgOkay = false;
151de9dcd41SStephan Aßmus			if (specifier.FindString("property", &property) != B_OK)
152de9dcd41SStephan Aßmus				msgOkay = false;
153de9dcd41SStephan Aßmus
154de9dcd41SStephan Aßmus			if (msgOkay) {
155de9dcd41SStephan Aßmus				if (strcmp(property, "type") == 0)
1564ec6c3a0SAdrien Destugues					reply.AddInt32("result", fNotification->Type());
157de9dcd41SStephan Aßmus
1584ec6c3a0SAdrien Destugues				if (strcmp(property, "group") == 0)
1594ec6c3a0SAdrien Destugues					reply.AddString("result", fNotification->Group());
160de9dcd41SStephan Aßmus
161de9dcd41SStephan Aßmus				if (strcmp(property, "title") == 0)
1624ec6c3a0SAdrien Destugues					reply.AddString("result", fNotification->Title());
163de9dcd41SStephan Aßmus
164de9dcd41SStephan Aßmus				if (strcmp(property, "content") == 0)
1654ec6c3a0SAdrien Destugues					reply.AddString("result", fNotification->Content());
166de9dcd41SStephan Aßmus
167de9dcd41SStephan Aßmus				if (strcmp(property, "progress") == 0)
1684ec6c3a0SAdrien Destugues					reply.AddFloat("result", fNotification->Progress());
169de9dcd41SStephan Aßmus
170de9dcd41SStephan Aßmus				if ((strcmp(property, "icon") == 0) && fBitmap) {
171de9dcd41SStephan Aßmus					BMessage archive;
172de9dcd41SStephan Aßmus					if (fBitmap->Archive(&archive) == B_OK)
173de9dcd41SStephan Aßmus						reply.AddMessage("result", &archive);
174de9dcd41SStephan Aßmus				}
175de9dcd41SStephan Aßmus
176de9dcd41SStephan Aßmus				reply.AddInt32("error", B_OK);
177de9dcd41SStephan Aßmus			} else {
178de9dcd41SStephan Aßmus				reply.what = B_MESSAGE_NOT_UNDERSTOOD;
179de9dcd41SStephan Aßmus				reply.AddInt32("error", B_ERROR);
180de9dcd41SStephan Aßmus			}
181de9dcd41SStephan Aßmus
182de9dcd41SStephan Aßmus			msg->SendReply(&reply);
183de9dcd41SStephan Aßmus			break;
184de9dcd41SStephan Aßmus		}
185de9dcd41SStephan Aßmus		case B_SET_PROPERTY:
186de9dcd41SStephan Aßmus		{
187de9dcd41SStephan Aßmus			BMessage specifier;
188de9dcd41SStephan Aßmus			const char* property;
189de9dcd41SStephan Aßmus			BMessage reply(B_REPLY);
190de9dcd41SStephan Aßmus			bool msgOkay = true;
191de9dcd41SStephan Aßmus
192de9dcd41SStephan Aßmus			if (msg->FindMessage("specifiers", 0, &specifier) != B_OK)
193de9dcd41SStephan Aßmus				msgOkay = false;
194de9dcd41SStephan Aßmus			if (specifier.FindString("property", &property) != B_OK)
195de9dcd41SStephan Aßmus				msgOkay = false;
196de9dcd41SStephan Aßmus
197de9dcd41SStephan Aßmus			if (msgOkay) {
1984ec6c3a0SAdrien Destugues				const char* value = NULL;
1994ec6c3a0SAdrien Destugues
2004ec6c3a0SAdrien Destugues				if (strcmp(property, "group") == 0)
2014ec6c3a0SAdrien Destugues					if (msg->FindString("data", &value) == B_OK)
2024ec6c3a0SAdrien Destugues						fNotification->SetGroup(value);
203de9dcd41SStephan Aßmus
204de9dcd41SStephan Aßmus				if (strcmp(property, "title") == 0)
2054ec6c3a0SAdrien Destugues					if (msg->FindString("data", &value) == B_OK)
2064ec6c3a0SAdrien Destugues						fNotification->SetTitle(value);
207de9dcd41SStephan Aßmus
208de9dcd41SStephan Aßmus				if (strcmp(property, "content") == 0)
2094ec6c3a0SAdrien Destugues					if (msg->FindString("data", &value) == B_OK)
2104ec6c3a0SAdrien Destugues						fNotification->SetContent(value);
211de9dcd41SStephan Aßmus
212de9dcd41SStephan Aßmus				if (strcmp(property, "icon") == 0) {
213de9dcd41SStephan Aßmus					BMessage archive;
214de9dcd41SStephan Aßmus					if (msg->FindMessage("data", &archive) == B_OK) {
215de9dcd41SStephan Aßmus						delete fBitmap;
216de9dcd41SStephan Aßmus						fBitmap = new BBitmap(&archive);
217de9dcd41SStephan Aßmus					}
218de9dcd41SStephan Aßmus				}
219de9dcd41SStephan Aßmus
2204ec6c3a0SAdrien Destugues				SetText();
221de9dcd41SStephan Aßmus				Invalidate();
222de9dcd41SStephan Aßmus
223de9dcd41SStephan Aßmus				reply.AddInt32("error", B_OK);
224de9dcd41SStephan Aßmus			} else {
225de9dcd41SStephan Aßmus				reply.what = B_MESSAGE_NOT_UNDERSTOOD;
226de9dcd41SStephan Aßmus				reply.AddInt32("error", B_ERROR);
227de9dcd41SStephan Aßmus			}
228de9dcd41SStephan Aßmus
229de9dcd41SStephan Aßmus			msg->SendReply(&reply);
230de9dcd41SStephan Aßmus			break;
231de9dcd41SStephan Aßmus		}
232de9dcd41SStephan Aßmus		default:
233de9dcd41SStephan Aßmus			BView::MessageReceived(msg);
234de9dcd41SStephan Aßmus	}
235de9dcd41SStephan Aßmus}
236de9dcd41SStephan Aßmus
237de9dcd41SStephan Aßmus
238de9dcd41SStephan Aßmusvoid
239de9dcd41SStephan AßmusNotificationView::Draw(BRect updateRect)
240de9dcd41SStephan Aßmus{
241de9dcd41SStephan Aßmus	BRect progRect;
242de9dcd41SStephan Aßmus
243de9dcd41SStephan Aßmus	SetDrawingMode(B_OP_ALPHA);
244de9dcd41SStephan Aßmus	SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
245de9dcd41SStephan Aßmus
2469dcd41a8SAdrien Destugues	BRect stripeRect = Bounds();
2470e07be06SAdrien Destugues	stripeRect.right = kIconStripeWidth;
24869631a6aSAdrien Destugues	SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
24969631a6aSAdrien Destugues		B_DARKEN_1_TINT));
25069631a6aSAdrien Destugues	FillRect(stripeRect);
25169631a6aSAdrien Destugues
25248d90a50SAdrien Destugues	SetHighColor(fStripeColor);
25369631a6aSAdrien Destugues	stripeRect.right = 2;
2549dcd41a8SAdrien Destugues	FillRect(stripeRect);
25563a4690eSAdrien Destugues
2569dcd41a8SAdrien Destugues	SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
257de9dcd41SStephan Aßmus	// Rectangle for icon and overlay icon
258de9dcd41SStephan Aßmus	BRect iconRect(0, 0, 0, 0);
259de9dcd41SStephan Aßmus
260de9dcd41SStephan Aßmus	// Draw icon
261de9dcd41SStephan Aßmus	if (fBitmap) {
2625414f4dcSAdrien Destugues		float ix = 18;
2636aa05872SBrian Hill		float iy = (Bounds().Height() - fIconSize) / 4.0;
2640e07be06SAdrien Destugues			// Icon is vertically centered in view
265de9dcd41SStephan Aßmus
266cd6365c7SJérôme Duval		if (fNotification->Type() == B_PROGRESS_NOTIFICATION) {
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
2716aa05872SBrian Hill		iconRect.Set(ix, iy, ix + fIconSize - 1.0, iy + fIconSize - 1.0);
2727dd47a9bSPhilippe 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);
279bdde2d30SPhilippe Houdoin
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.
2836aa05872SBrian Hill		BString text(l->text);
2846aa05872SBrian Hill		TruncateString(&text, B_TRUNCATE_END,
28584e1c7faSAdrien Destugues			Bounds().Width() - l->location.x);
2866aa05872SBrian 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)
291f6afd3e9SRyan Leavengood		_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
30282a67460SAdrien Destugues - PulkoMandyvoid
30382a67460SAdrien Destugues - PulkoMandyNotificationView::_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
335de9dcd41SStephan Aßmusvoid
336de9dcd41SStephan AßmusNotificationView::MouseDown(BPoint point)
337de9dcd41SStephan Aßmus{
3386aa05872SBrian Hill	// Preview Mode ignores any mouse clicks
3396aa05872SBrian Hill	if (fPreviewModeOn)
3406aa05872SBrian Hill		return;
3416aa05872SBrian 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;
350bdde2d30SPhilippe Houdoin			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) {
3654ec6c3a0SAdrien Destugues					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;
373de9dcd41SStephan Aßmus				}
374de9dcd41SStephan Aßmus
3754ec6c3a0SAdrien Destugues				for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++)
3764ec6c3a0SAdrien Destugues					refMsg.AddRef("refs", fNotification->OnClickRefAt(i));
3774ec6c3a0SAdrien Destugues				messages.AddItem((void*)&refMsg);
3784ec6c3a0SAdrien Destugues
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ßmusBHandler*
4174ec6c3a0SAdrien DestuguesNotificationView::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ßmusstatus_t
431de9dcd41SStephan AßmusNotificationView::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);
436bdde2d30SPhilippe Houdoin	return BView::GetSupportedSuites(msg);
437de9dcd41SStephan Aßmus}
438de9dcd41SStephan Aßmus
439de9dcd41SStephan Aßmus
440de9dcd41SStephan Aßmusvoid
4414ec6c3a0SAdrien DestuguesNotificationView::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)
4566aa05872SBrian Hill		iconRight += fIconSize;
4570e07be06SAdrien Destugues	else
4585414f4dcSAdrien Destugues		iconRight += 32;
459de9dcd41SStephan Aßmus
460de9dcd41SStephan Aßmus	font_height fh;
461a657e677SBrian Hill	be_bold_font->GetHeight(&fh);
462de9dcd41SStephan Aßmus	float fontHeight = ceilf(fh.leading) + ceilf(fh.descent)
463de9dcd41SStephan Aßmus		+ ceilf(fh.ascent);
4646aa05872SBrian Hill	float y = fontHeight + kEdgePadding * 2;
465de9dcd41SStephan Aßmus
466de9dcd41SStephan Aßmus	// Title
467de9dcd41SStephan Aßmus	LineInfo* titleLine = new LineInfo;
4684ec6c3a0SAdrien Destugues	titleLine->text = fNotification->Title();
469a657e677SBrian Hill	titleLine->font = *be_bold_font;
470de9dcd41SStephan Aßmus
471569a7bfcSAdrien Destugues	titleLine->location = BPoint(iconRight + kEdgePadding, y);
472de9dcd41SStephan Aßmus
473de9dcd41SStephan Aßmus	fLines.push_front(titleLine);
474de9dcd41SStephan Aßmus	y += fontHeight;
475de9dcd41SStephan Aßmus
476de9dcd41SStephan Aßmus	// Rest of text is rendered with be_plain_font.
477de9dcd41SStephan Aßmus	be_plain_font->GetHeight(&fh);
478de9dcd41SStephan Aßmus	fontHeight = ceilf(fh.leading) + ceilf(fh.descent)
479de9dcd41SStephan Aßmus		+ ceilf(fh.ascent);
480de9dcd41SStephan Aßmus
481de9dcd41SStephan Aßmus	// Split text into chunks between certain characters and compose the lines.
482e0890a26SAdrien Destugues	const char kSeparatorCharacters[] = " \n-\\";
4834ec6c3a0SAdrien Destugues	BString textBuffer = fNotification->Content();
484de9dcd41SStephan Aßmus	textBuffer.ReplaceAll("\t", "    ");
485de9dcd41SStephan Aßmus	const char* chunkStart = textBuffer.String();
486de9dcd41SStephan Aßmus	float maxWidth = newMaxWidth - kEdgePadding - iconRight;
487de9dcd41SStephan Aßmus	LineInfo* line = NULL;
488de9dcd41SStephan Aßmus	ssize_t length = textBuffer.Length();
489de9dcd41SStephan Aßmus	while (chunkStart - textBuffer.String() < length) {
490de9dcd41SStephan Aßmus		size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1;
491de9dcd41SStephan Aßmus
4924ec6c3a0SAdrien Destugues		// Start a new line if we didn't start one before
49331a3c4e8SJérôme Duval		BString tempText;
49431a3c4e8SJérôme Duval		if (line != NULL)
49531a3c4e8SJérôme Duval			tempText.SetTo(line->text);
496de9dcd41SStephan Aßmus		tempText.Append(chunkStart, chunkLength);
497de9dcd41SStephan Aßmus
498de9dcd41SStephan Aßmus		if (line == NULL || chunkStart[0] == '\n'
499de9dcd41SStephan Aßmus			|| StringWidth(tempText) > maxWidth) {
500de9dcd41SStephan Aßmus			line = new LineInfo;
501de9dcd41SStephan Aßmus			line->font = *be_plain_font;
502de9dcd41SStephan Aßmus			line->location = BPoint(iconRight + kEdgePadding, y);
503de9dcd41SStephan Aßmus
504de9dcd41SStephan Aßmus			fLines.push_front(line);
505de9dcd41SStephan Aßmus			y += fontHeight;
506de9dcd41SStephan Aßmus
5074ec6c3a0SAdrien Destugues			// Skip the eventual new-line character at the beginning of this chunk
508