xref: /haiku/src/servers/notification/NotificationView.cpp (revision 44c6e69bd178b3fcfc48b180b394d4075a89d091)
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>
17e0890a26SAdrien Destugues #include <GroupLayout.h>
18e0890a26SAdrien Destugues #include <GroupLayoutBuilder.h>
19e0890a26SAdrien 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 	:
51*44c6e69bSAdrien Destugues 	BView("NotificationView", B_WILL_DRAW),
52de9dcd41SStephan Aßmus 	fParent(win),
534ec6c3a0SAdrien Destugues 	fNotification(notification),
544ec6c3a0SAdrien Destugues 	fTimeout(timeout),
55de9dcd41SStephan Aßmus 	fRunner(NULL),
564ec6c3a0SAdrien Destugues 	fBitmap(NULL)
57de9dcd41SStephan Aßmus {
584ec6c3a0SAdrien Destugues 	if (fNotification->Icon() != NULL)
594ec6c3a0SAdrien Destugues 		fBitmap = new BBitmap(fNotification->Icon());
60de9dcd41SStephan Aßmus 
614ec6c3a0SAdrien Destugues 	if (fTimeout <= 0)
624ec6c3a0SAdrien Destugues 		fTimeout = fParent->Timeout() * 1000000;
63de9dcd41SStephan Aßmus 
64e0890a26SAdrien Destugues 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
65e0890a26SAdrien Destugues 	SetLayout(layout);
66e0890a26SAdrien Destugues 
674ec6c3a0SAdrien Destugues 	switch (fNotification->Type()) {
68de9dcd41SStephan Aßmus 		case B_IMPORTANT_NOTIFICATION:
69de9dcd41SStephan Aßmus 			SetViewColor(255, 255, 255);
70de9dcd41SStephan Aßmus 			SetLowColor(255, 255, 255);
71de9dcd41SStephan Aßmus 			break;
72de9dcd41SStephan Aßmus 		case B_ERROR_NOTIFICATION:
73de9dcd41SStephan Aßmus 			SetViewColor(ui_color(B_FAILURE_COLOR));
74de9dcd41SStephan Aßmus 			SetLowColor(ui_color(B_FAILURE_COLOR));
75de9dcd41SStephan Aßmus 			break;
76beeda306SAdrien Destugues 		case B_PROGRESS_NOTIFICATION:
77beeda306SAdrien Destugues 		{
78e0890a26SAdrien Destugues 			BStatusBar* progress = new BStatusBar("progress");
79beeda306SAdrien Destugues 			progress->SetBarHeight(12.0f);
80beeda306SAdrien Destugues 			progress->SetMaxValue(1.0f);
814ec6c3a0SAdrien Destugues 			progress->Update(fNotification->Progress());
82beeda306SAdrien Destugues 
83beeda306SAdrien Destugues 			BString label = "";
844ec6c3a0SAdrien Destugues 			label << (int)(fNotification->Progress() * 100) << " %";
85beeda306SAdrien Destugues 			progress->SetTrailingText(label);
86beeda306SAdrien Destugues 
87*44c6e69bSAdrien Destugues 			layout->AddView(progress);
88beeda306SAdrien Destugues 		}
894ec6c3a0SAdrien Destugues 		// fall through
90de9dcd41SStephan Aßmus 		default:
91de9dcd41SStephan Aßmus 			SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
92de9dcd41SStephan Aßmus 			SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
93de9dcd41SStephan Aßmus 	}
94*44c6e69bSAdrien Destugues 
95*44c6e69bSAdrien Destugues 	SetText();
96de9dcd41SStephan Aßmus }
97de9dcd41SStephan Aßmus 
98de9dcd41SStephan Aßmus 
99de9dcd41SStephan Aßmus NotificationView::~NotificationView()
100de9dcd41SStephan Aßmus {
101de9dcd41SStephan Aßmus 	delete fRunner;
102de9dcd41SStephan Aßmus 	delete fBitmap;
1034ec6c3a0SAdrien Destugues 	delete fNotification;
104de9dcd41SStephan Aßmus 
105de9dcd41SStephan Aßmus 	LineInfoList::iterator lIt;
106de9dcd41SStephan Aßmus 	for (lIt = fLines.begin(); lIt != fLines.end(); lIt++)
107de9dcd41SStephan Aßmus 		delete (*lIt);
108de9dcd41SStephan Aßmus }
109de9dcd41SStephan Aßmus 
110de9dcd41SStephan Aßmus 
111de9dcd41SStephan Aßmus void
112de9dcd41SStephan Aßmus NotificationView::AttachedToWindow()
113de9dcd41SStephan Aßmus {
114de9dcd41SStephan Aßmus 	BMessage msg(kRemoveView);
115de9dcd41SStephan Aßmus 	msg.AddPointer("view", this);
116de9dcd41SStephan Aßmus 
1174ec6c3a0SAdrien Destugues 	fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1);
118de9dcd41SStephan Aßmus }
119de9dcd41SStephan Aßmus 
120de9dcd41SStephan Aßmus 
121de9dcd41SStephan Aßmus void
122de9dcd41SStephan Aßmus NotificationView::MessageReceived(BMessage* msg)
123de9dcd41SStephan Aßmus {
124de9dcd41SStephan Aßmus 	switch (msg->what) {
125de9dcd41SStephan Aßmus 		case B_GET_PROPERTY:
126de9dcd41SStephan Aßmus 		{
127de9dcd41SStephan Aßmus 			BMessage specifier;
128de9dcd41SStephan Aßmus 			const char* property;
129de9dcd41SStephan Aßmus 			BMessage reply(B_REPLY);
130de9dcd41SStephan Aßmus 			bool msgOkay = true;
131de9dcd41SStephan Aßmus 
132de9dcd41SStephan Aßmus 			if (msg->FindMessage("specifiers", 0, &specifier) != B_OK)
133de9dcd41SStephan Aßmus 				msgOkay = false;
134de9dcd41SStephan Aßmus 			if (specifier.FindString("property", &property) != B_OK)
135de9dcd41SStephan Aßmus 				msgOkay = false;
136de9dcd41SStephan Aßmus 
137de9dcd41SStephan Aßmus 			if (msgOkay) {
138de9dcd41SStephan Aßmus 				if (strcmp(property, "type") == 0)
1394ec6c3a0SAdrien Destugues 					reply.AddInt32("result", fNotification->Type());
140de9dcd41SStephan Aßmus 
1414ec6c3a0SAdrien Destugues 				if (strcmp(property, "group") == 0)
1424ec6c3a0SAdrien Destugues 					reply.AddString("result", fNotification->Group());
143de9dcd41SStephan Aßmus 
144de9dcd41SStephan Aßmus 				if (strcmp(property, "title") == 0)
1454ec6c3a0SAdrien Destugues 					reply.AddString("result", fNotification->Title());
146de9dcd41SStephan Aßmus 
147de9dcd41SStephan Aßmus 				if (strcmp(property, "content") == 0)
1484ec6c3a0SAdrien Destugues 					reply.AddString("result", fNotification->Content());
149de9dcd41SStephan Aßmus 
150de9dcd41SStephan Aßmus 				if (strcmp(property, "progress") == 0)
1514ec6c3a0SAdrien Destugues 					reply.AddFloat("result", fNotification->Progress());
152de9dcd41SStephan Aßmus 
153de9dcd41SStephan Aßmus 				if ((strcmp(property, "icon") == 0) && fBitmap) {
154de9dcd41SStephan Aßmus 					BMessage archive;
155de9dcd41SStephan Aßmus 					if (fBitmap->Archive(&archive) == B_OK)
156de9dcd41SStephan Aßmus 						reply.AddMessage("result", &archive);
157de9dcd41SStephan Aßmus 				}
158de9dcd41SStephan Aßmus 
159de9dcd41SStephan Aßmus 				reply.AddInt32("error", B_OK);
160de9dcd41SStephan Aßmus 			} else {
161de9dcd41SStephan Aßmus 				reply.what = B_MESSAGE_NOT_UNDERSTOOD;
162de9dcd41SStephan Aßmus 				reply.AddInt32("error", B_ERROR);
163de9dcd41SStephan Aßmus 			}
164de9dcd41SStephan Aßmus 
165de9dcd41SStephan Aßmus 			msg->SendReply(&reply);
166de9dcd41SStephan Aßmus 			break;
167de9dcd41SStephan Aßmus 		}
168de9dcd41SStephan Aßmus 		case B_SET_PROPERTY:
169de9dcd41SStephan Aßmus 		{
170de9dcd41SStephan Aßmus 			BMessage specifier;
171de9dcd41SStephan Aßmus 			const char* property;
172de9dcd41SStephan Aßmus 			BMessage reply(B_REPLY);
173de9dcd41SStephan Aßmus 			bool msgOkay = true;
174de9dcd41SStephan Aßmus 
175de9dcd41SStephan Aßmus 			if (msg->FindMessage("specifiers", 0, &specifier) != B_OK)
176de9dcd41SStephan Aßmus 				msgOkay = false;
177de9dcd41SStephan Aßmus 			if (specifier.FindString("property", &property) != B_OK)
178de9dcd41SStephan Aßmus 				msgOkay = false;
179de9dcd41SStephan Aßmus 
180de9dcd41SStephan Aßmus 			if (msgOkay) {
1814ec6c3a0SAdrien Destugues 				const char* value = NULL;
1824ec6c3a0SAdrien Destugues 
1834ec6c3a0SAdrien Destugues 				if (strcmp(property, "group") == 0)
1844ec6c3a0SAdrien Destugues 					if (msg->FindString("data", &value) == B_OK)
1854ec6c3a0SAdrien Destugues 						fNotification->SetGroup(value);
186de9dcd41SStephan Aßmus 
187de9dcd41SStephan Aßmus 				if (strcmp(property, "title") == 0)
1884ec6c3a0SAdrien Destugues 					if (msg->FindString("data", &value) == B_OK)
1894ec6c3a0SAdrien Destugues 						fNotification->SetTitle(value);
190de9dcd41SStephan Aßmus 
191de9dcd41SStephan Aßmus 				if (strcmp(property, "content") == 0)
1924ec6c3a0SAdrien Destugues 					if (msg->FindString("data", &value) == B_OK)
1934ec6c3a0SAdrien Destugues 						fNotification->SetContent(value);
194de9dcd41SStephan Aßmus 
195de9dcd41SStephan Aßmus 				if (strcmp(property, "icon") == 0) {
196de9dcd41SStephan Aßmus 					BMessage archive;
197de9dcd41SStephan Aßmus 					if (msg->FindMessage("data", &archive) == B_OK) {
198de9dcd41SStephan Aßmus 						delete fBitmap;
199de9dcd41SStephan Aßmus 						fBitmap = new BBitmap(&archive);
200de9dcd41SStephan Aßmus 					}
201de9dcd41SStephan Aßmus 				}
202de9dcd41SStephan Aßmus 
2034ec6c3a0SAdrien Destugues 				SetText();
204de9dcd41SStephan Aßmus 				Invalidate();
205de9dcd41SStephan Aßmus 
206de9dcd41SStephan Aßmus 				reply.AddInt32("error", B_OK);
207de9dcd41SStephan Aßmus 			} else {
208de9dcd41SStephan Aßmus 				reply.what = B_MESSAGE_NOT_UNDERSTOOD;
209de9dcd41SStephan Aßmus 				reply.AddInt32("error", B_ERROR);
210de9dcd41SStephan Aßmus 			}
211de9dcd41SStephan Aßmus 
212de9dcd41SStephan Aßmus 			msg->SendReply(&reply);
213de9dcd41SStephan Aßmus 			break;
214de9dcd41SStephan Aßmus 		}
215de9dcd41SStephan Aßmus 		default:
216de9dcd41SStephan Aßmus 			BView::MessageReceived(msg);
217de9dcd41SStephan Aßmus 	}
218de9dcd41SStephan Aßmus }
219de9dcd41SStephan Aßmus 
220de9dcd41SStephan Aßmus 
221de9dcd41SStephan Aßmus void
222de9dcd41SStephan Aßmus NotificationView::Draw(BRect updateRect)
223de9dcd41SStephan Aßmus {
224de9dcd41SStephan Aßmus 	BRect progRect;
225de9dcd41SStephan Aßmus 
226de9dcd41SStephan Aßmus 	SetDrawingMode(B_OP_ALPHA);
227de9dcd41SStephan Aßmus 	SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
228de9dcd41SStephan Aßmus 
229de9dcd41SStephan Aßmus 	// Icon size
230de9dcd41SStephan Aßmus 	float iconSize = (float)fParent->IconSize();
231de9dcd41SStephan Aßmus 
2329dcd41a8SAdrien Destugues 	BRect stripeRect = Bounds();
2330e07be06SAdrien Destugues 	stripeRect.right = kIconStripeWidth;
2349dcd41a8SAdrien Destugues 	SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
2359dcd41a8SAdrien Destugues 	FillRect(stripeRect);
2369dcd41a8SAdrien Destugues 
2379dcd41a8SAdrien Destugues 	SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
238de9dcd41SStephan Aßmus 	// Rectangle for icon and overlay icon
239de9dcd41SStephan Aßmus 	BRect iconRect(0, 0, 0, 0);
240de9dcd41SStephan Aßmus 
241de9dcd41SStephan Aßmus 	// Draw icon
242de9dcd41SStephan Aßmus 	if (fBitmap) {
2435414f4dcSAdrien Destugues 		float ix = 18;
2445414f4dcSAdrien Destugues 		float iy = (Bounds().Height() - iconSize) / 4.0;
2450e07be06SAdrien Destugues 			// Icon is vertically centered in view
246de9dcd41SStephan Aßmus 
2474ec6c3a0SAdrien Destugues 		if (fNotification->Type() == B_PROGRESS_NOTIFICATION)
2480e07be06SAdrien Destugues 		{
249de9dcd41SStephan Aßmus 			// Move icon up by half progress bar height if it's present
2500e07be06SAdrien Destugues 			iy -= (progRect.Height() + kEdgePadding);
2510e07be06SAdrien Destugues 		}
252de9dcd41SStephan Aßmus 
2537dd47a9bSPhilippe Houdoin 		iconRect.Set(ix, iy, ix + iconSize - 1.0, iy + iconSize - 1.0);
254bdde2d30SPhilippe Houdoin 		DrawBitmapAsync(fBitmap, fBitmap->Bounds(), iconRect);
255de9dcd41SStephan Aßmus 	}
256de9dcd41SStephan Aßmus 
257de9dcd41SStephan Aßmus 	// Draw content
258de9dcd41SStephan Aßmus 	LineInfoList::iterator lIt;
259de9dcd41SStephan Aßmus 	for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) {
260de9dcd41SStephan Aßmus 		LineInfo *l = (*lIt);
261de9dcd41SStephan Aßmus 
262de9dcd41SStephan Aßmus 		SetFont(&l->font);
263de9dcd41SStephan Aßmus 		DrawString(l->text.String(), l->text.Length(), l->location);
264de9dcd41SStephan Aßmus 	}
265de9dcd41SStephan Aßmus 
266de9dcd41SStephan Aßmus 	rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR);
267de9dcd41SStephan Aßmus 	detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT);
268de9dcd41SStephan Aßmus 
269de9dcd41SStephan Aßmus 	// Draw the close widget
270de9dcd41SStephan Aßmus 	BRect closeRect = Bounds();
2710e07be06SAdrien Destugues 	closeRect.InsetBy(2 * kEdgePadding, 2 * kEdgePadding);
272de9dcd41SStephan Aßmus 	closeRect.left = closeRect.right - kCloseSize;
273de9dcd41SStephan Aßmus 	closeRect.bottom = closeRect.top + kCloseSize;
274de9dcd41SStephan Aßmus 
275de9dcd41SStephan Aßmus 	PushState();
276de9dcd41SStephan Aßmus 		SetHighColor(detailCol);
277de9dcd41SStephan Aßmus 		StrokeRoundRect(closeRect, kSmallPadding, kSmallPadding);
278de9dcd41SStephan Aßmus 		BRect closeCross = closeRect.InsetByCopy(kSmallPadding, kSmallPadding);
279de9dcd41SStephan Aßmus 		StrokeLine(closeCross.LeftTop(), closeCross.RightBottom());
280de9dcd41SStephan Aßmus 		StrokeLine(closeCross.LeftBottom(), closeCross.RightTop());
281de9dcd41SStephan Aßmus 	PopState();
282de9dcd41SStephan Aßmus 
2835414f4dcSAdrien Destugues 	SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
284*44c6e69bSAdrien Destugues 	BPoint left(Bounds().left, Bounds().top);
285*44c6e69bSAdrien Destugues 	BPoint right(Bounds().right, Bounds().top);
2865414f4dcSAdrien Destugues 	StrokeLine(left, right);
2875414f4dcSAdrien Destugues 
288de9dcd41SStephan Aßmus 	Sync();
289de9dcd41SStephan Aßmus }
290de9dcd41SStephan Aßmus 
291de9dcd41SStephan Aßmus 
292de9dcd41SStephan Aßmus void
293de9dcd41SStephan Aßmus NotificationView::MouseDown(BPoint point)
294de9dcd41SStephan Aßmus {
295de9dcd41SStephan Aßmus 	int32 buttons;
296de9dcd41SStephan Aßmus 	Window()->CurrentMessage()->FindInt32("buttons", &buttons);
297de9dcd41SStephan Aßmus 
298de9dcd41SStephan Aßmus 	switch (buttons) {
299de9dcd41SStephan Aßmus 		case B_PRIMARY_MOUSE_BUTTON:
300de9dcd41SStephan Aßmus 		{
301de9dcd41SStephan Aßmus 			BRect closeRect = Bounds().InsetByCopy(2,2);
302de9dcd41SStephan Aßmus 			closeRect.left = closeRect.right - kCloseSize;
303de9dcd41SStephan Aßmus 			closeRect.bottom = closeRect.top + kCloseSize;
304de9dcd41SStephan Aßmus 
305de9dcd41SStephan Aßmus 			if (!closeRect.Contains(point)) {
306de9dcd41SStephan Aßmus 				entry_ref launchRef;
307de9dcd41SStephan Aßmus 				BString launchString;
308de9dcd41SStephan Aßmus 				BMessage argMsg(B_ARGV_RECEIVED);
309de9dcd41SStephan Aßmus 				BMessage refMsg(B_REFS_RECEIVED);
310de9dcd41SStephan Aßmus 				entry_ref appRef;
311de9dcd41SStephan Aßmus 				bool useArgv = false;
312de9dcd41SStephan Aßmus 				BList messages;
313de9dcd41SStephan Aßmus 				entry_ref ref;
314de9dcd41SStephan Aßmus 
3154ec6c3a0SAdrien Destugues 				if (fNotification->OnClickApp() != NULL
3164ec6c3a0SAdrien Destugues 					&& be_roster->FindApp(fNotification->OnClickApp(), &appRef)
3174ec6c3a0SAdrien Destugues 				   		== B_OK) {
318de9dcd41SStephan Aßmus 					useArgv = true;
319de9dcd41SStephan Aßmus 				}
320de9dcd41SStephan Aßmus 
3214ec6c3a0SAdrien Destugues 				if (fNotification->OnClickFile() != NULL
3224ec6c3a0SAdrien Destugues 					&& be_roster->FindApp(
3234ec6c3a0SAdrien Destugues 							(entry_ref*)fNotification->OnClickFile(), &appRef)
3244ec6c3a0SAdrien Destugues 				   		== B_OK) {
3254ec6c3a0SAdrien Destugues 					useArgv = true;
3264ec6c3a0SAdrien Destugues 				}
327de9dcd41SStephan Aßmus 
3284ec6c3a0SAdrien Destugues 				for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++)
3294ec6c3a0SAdrien Destugues 					refMsg.AddRef("refs", fNotification->OnClickRefAt(i));
330de9dcd41SStephan Aßmus 				messages.AddItem((void*)&refMsg);
331de9dcd41SStephan Aßmus 
332de9dcd41SStephan Aßmus 				if (useArgv) {
3334ec6c3a0SAdrien Destugues 					int32 argc = fNotification->CountOnClickArgs() + 1;
334de9dcd41SStephan Aßmus 					BString arg;
335de9dcd41SStephan Aßmus 
336de9dcd41SStephan Aßmus 					BPath p(&appRef);
337de9dcd41SStephan Aßmus 					argMsg.AddString("argv", p.Path());
338de9dcd41SStephan Aßmus 
3394ec6c3a0SAdrien Destugues 					argMsg.AddInt32("argc", argc);
340de9dcd41SStephan Aßmus 
3414ec6c3a0SAdrien Destugues 					for (int32 i = 0; i < argc - 1; i++) {
3424ec6c3a0SAdrien Destugues 						argMsg.AddString("argv",
3434ec6c3a0SAdrien Destugues 							fNotification->OnClickArgAt(i));
3444ec6c3a0SAdrien Destugues 					}
345de9dcd41SStephan Aßmus 
346de9dcd41SStephan Aßmus 					messages.AddItem((void*)&argMsg);
347de9dcd41SStephan Aßmus 				}
348de9dcd41SStephan Aßmus 
3494ec6c3a0SAdrien Destugues 				if (fNotification->OnClickApp() != NULL)
3504ec6c3a0SAdrien Destugues 					be_roster->Launch(fNotification->OnClickApp(), &messages);
351de9dcd41SStephan Aßmus 				else
3524ec6c3a0SAdrien Destugues 					be_roster->Launch(fNotification->OnClickFile(), &messages);
353de9dcd41SStephan Aßmus 			}
354de9dcd41SStephan Aßmus 
355de9dcd41SStephan Aßmus 			// Remove the info view after a click
356de9dcd41SStephan Aßmus 			BMessage remove_msg(kRemoveView);
357de9dcd41SStephan Aßmus 			remove_msg.AddPointer("view", this);
358de9dcd41SStephan Aßmus 
359de9dcd41SStephan Aßmus 			BMessenger msgr(Parent());
360de9dcd41SStephan Aßmus 			msgr.SendMessage(&remove_msg);
361de9dcd41SStephan Aßmus 			break;
362de9dcd41SStephan Aßmus 		}
363de9dcd41SStephan Aßmus 	}
364de9dcd41SStephan Aßmus }
365de9dcd41SStephan Aßmus 
366de9dcd41SStephan Aßmus 
367*44c6e69bSAdrien Destugues /*
3684ec6c3a0SAdrien Destugues BSize
3694ec6c3a0SAdrien Destugues NotificationView::MinSize()
370de9dcd41SStephan Aßmus {
371*44c6e69bSAdrien Destugues //	return BLayoutUtils::ComposeSize(ExplicitMinSize(), _CalculateSize());
372*44c6e69bSAdrien Destugues 	return _CalculateSize();
3734ec6c3a0SAdrien Destugues }
3744ec6c3a0SAdrien Destugues 
3754ec6c3a0SAdrien Destugues 
3764ec6c3a0SAdrien Destugues BSize
3774ec6c3a0SAdrien Destugues NotificationView::MaxSize()
3784ec6c3a0SAdrien Destugues {
379*44c6e69bSAdrien Destugues 	return _CalculateSize();
3804ec6c3a0SAdrien Destugues }
3814ec6c3a0SAdrien Destugues 
3824ec6c3a0SAdrien Destugues 
3834ec6c3a0SAdrien Destugues BSize
3844ec6c3a0SAdrien Destugues NotificationView::PreferredSize()
3854ec6c3a0SAdrien Destugues {
3864ec6c3a0SAdrien Destugues 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
3874ec6c3a0SAdrien Destugues 		_CalculateSize());
388de9dcd41SStephan Aßmus }
389*44c6e69bSAdrien Destugues */
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 {
419e0890a26SAdrien Destugues 	if (newMaxWidth < 0) {
420e0890a26SAdrien Destugues 		newMaxWidth = 200;
421e0890a26SAdrien 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.
457e0890a26SAdrien 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 	}
522e0890a26SAdrien Destugues 
523e0890a26SAdrien Destugues 	// Make sure the progress bar is below the text, and the window is big
524e0890a26SAdrien Destugues 	// enough.
525e0890a26SAdrien Destugues 	static_cast<BGroupLayout*>(GetLayout())->SetInsets(kIconStripeWidth + 8,
526e0890a26SAdrien Destugues 		fHeight, 8, 8);
527*44c6e69bSAdrien Destugues 
528*44c6e69bSAdrien Destugues 	_CalculateSize();
529de9dcd41SStephan Aßmus }
530de9dcd41SStephan Aßmus 
531de9dcd41SStephan Aßmus 
532de9dcd41SStephan Aßmus const char*
5334ec6c3a0SAdrien Destugues NotificationView::MessageID() const
534de9dcd41SStephan Aßmus {
5354ec6c3a0SAdrien Destugues 	return fNotification->MessageID();
536de9dcd41SStephan Aßmus }
537de9dcd41SStephan Aßmus 
538de9dcd41SStephan Aßmus 
5394ec6c3a0SAdrien Destugues BSize
5404ec6c3a0SAdrien Destugues NotificationView::_CalculateSize()
541de9dcd41SStephan Aßmus {
5424ec6c3a0SAdrien Destugues 	BSize size;
5434ec6c3a0SAdrien Destugues 
544*44c6e69bSAdrien Destugues 	size.width = 300;
5454ec6c3a0SAdrien Destugues 	size.height = fHeight;
5464ec6c3a0SAdrien Destugues 
5474ec6c3a0SAdrien Destugues 	if (fNotification->Type() == B_PROGRESS_NOTIFICATION) {
5484ec6c3a0SAdrien Destugues 		font_height fh;
5494ec6c3a0SAdrien Destugues 		be_plain_font->GetHeight(&fh);
5504ec6c3a0SAdrien Destugues 		float fontHeight = fh.ascent + fh.descent + fh.leading;
551*44c6e69bSAdrien Destugues 		size.height += 9 + (kSmallPadding * 2) + (kEdgePadding * 1)
552*44c6e69bSAdrien Destugues 			+ fontHeight * 2;
553de9dcd41SStephan Aßmus 	}
554de9dcd41SStephan Aßmus 
555*44c6e69bSAdrien Destugues 	SetExplicitMinSize(size);
556*44c6e69bSAdrien Destugues 	SetExplicitMaxSize(size);
557*44c6e69bSAdrien Destugues 
5584ec6c3a0SAdrien Destugues 	return size;
559de9dcd41SStephan Aßmus }
560