xref: /haiku/src/kits/app/Notification.cpp (revision 211483cb512baaca8b17e0112a360b5a17cde0ca)
1 /*
2  * Copyright 2010, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
7  *		Stephan Aßmus, superstippi@gmx.de
8  */
9 
10 
11 #include <Notification.h>
12 
13 #include <new>
14 
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include <notification/Notifications.h>
19 
20 #include <Bitmap.h>
21 #include <Message.h>
22 
23 
24 BNotification::BNotification(notification_type type)
25 	:
26 	BArchivable(),
27 	fInitStatus(B_OK),
28 	fType(type),
29 	fProgress(0.f),
30 	fFile(NULL),
31 	fBitmap(NULL)
32 {
33 }
34 
35 
36 BNotification::BNotification(BMessage* archive)
37 	:
38 	BArchivable(archive),
39 	fInitStatus(B_OK),
40 	fProgress(0.0f),
41 	fFile(NULL),
42 	fBitmap(NULL)
43 {
44 	int32 type;
45 	if (archive->FindInt32("_type", &type) == B_OK)
46 		fType = (notification_type)type;
47 	else
48 		fInitStatus = B_ERROR;
49 
50 	BString group;
51 	if (archive->FindString("_group", &group) == B_OK)
52 		SetGroup(group);
53 
54 	BString title;
55 	if (archive->FindString("_title", &title) == B_OK)
56 		SetTitle(title);
57 
58 	BString content;
59 	if (archive->FindString("_content", &content) == B_OK)
60 		SetContent(content);
61 
62 	BString messageID;
63 	if (archive->FindString("_messageID", &messageID) == B_OK)
64 		SetMessageID(messageID);
65 
66 	float progress;
67 	if (type == B_PROGRESS_NOTIFICATION
68 		&& archive->FindFloat("_progress", &progress) == B_OK)
69 		SetProgress(progress);
70 
71 	BString onClickApp;
72 	if (archive->FindString("_onClickApp", &onClickApp) == B_OK)
73 		SetOnClickApp(onClickApp);
74 
75 	entry_ref onClickFile;
76 	if (archive->FindRef("_onClickFile", &onClickFile) == B_OK)
77 		SetOnClickFile(&onClickFile);
78 
79 	entry_ref onClickRef;
80 	int32 index = 0;
81 	while (archive->FindRef("_onClickRef", index++, &onClickRef) == B_OK)
82 		AddOnClickRef(&onClickRef);
83 
84 	BString onClickArgv;
85 	index = 0;
86 	while (archive->FindString("_onClickArgv", index++, &onClickArgv) == B_OK)
87 		AddOnClickArg(onClickArgv);
88 
89 	status_t ret = B_OK;
90 	BMessage icon;
91 	if ((ret = archive->FindMessage("_icon", &icon)) == B_OK) {
92 		BBitmap bitmap(&icon);
93 		ret = bitmap.InitCheck();
94 		if (ret == B_OK)
95 			ret = SetIcon(&bitmap);
96 	}
97 }
98 
99 
100 BNotification::~BNotification()
101 {
102 	delete fFile;
103 	delete fBitmap;
104 
105 	for (int32 i = fRefs.CountItems() - 1; i >= 0; i--)
106 		delete (entry_ref*)fRefs.ItemAtFast(i);
107 
108 	for (int32 i = fArgv.CountItems() - 1; i >= 0; i--)
109 		free(fArgv.ItemAtFast(i));
110 }
111 
112 
113 /*! \brief Returns initialization status.
114  */
115 status_t
116 BNotification::InitCheck() const
117 {
118 	return fInitStatus;
119 }
120 
121 
122 /*! \brief Returns a new BNotification object from @archive.
123 
124 	Returns a new BNotification object, allocated by new and created
125 	with the version of the constructor that takes BMessage archive.
126 	However, if the message doesn't contain an archived data for a
127 	BNotification object, this method returns NULL.
128 
129 	\return BNotification object from @archive or NULL if it doesn't
130 			contain a valid BNotification object.
131 */
132 BArchivable*
133 BNotification::Instantiate(BMessage* archive)
134 {
135 	if (validate_instantiation(archive, "BNotification"))
136 		return new(std::nothrow) BNotification(archive);
137 
138 	return NULL;
139 }
140 
141 
142 /*! \brief Archives the BNotification in the BMessages @archive.
143 
144 	\sa BArchivable::Archive(), Instantiate() static function.
145 	\return
146 	- \c B_OK: Everything went fine.
147 	- \c Other errors: Archiving has failed.
148 */
149 status_t
150 BNotification::Archive(BMessage* archive, bool deep) const
151 {
152 	status_t status = BArchivable::Archive(archive, deep);
153 
154 	if (status == B_OK)
155 		status = archive->AddInt32("_type", (int32)fType);
156 
157 	if (status == B_OK && Group() != NULL)
158 		status = archive->AddString("_group", Group());
159 
160 	if (status == B_OK && Title() != NULL)
161 		status = archive->AddString("_title", Title());
162 
163 	if (status == B_OK && Content() != NULL)
164 		status = archive->AddString("_content", Content());
165 
166 	if (status == B_OK && MessageID() != NULL)
167 		status = archive->AddString("_messageID", MessageID());
168 
169 	if (status == B_OK && Type() == B_PROGRESS_NOTIFICATION)
170 		status = archive->AddFloat("_progress", Progress());
171 
172 	if (status == B_OK && OnClickApp() != NULL)
173 		status = archive->AddString("_onClickApp", OnClickApp());
174 
175 	if (status == B_OK && OnClickFile() != NULL)
176 		status = archive->AddRef("_onClickFile", OnClickFile());
177 
178 	if (status == B_OK) {
179 		for (int32 i = 0; i < CountOnClickRefs(); i++) {
180 			status = archive->AddRef("_onClickRef", OnClickRefAt(i));
181 			if (status != B_OK)
182 				break;
183 		}
184 	}
185 
186 	if (status == B_OK) {
187 		for (int32 i = 0; i < CountOnClickArgs(); i++) {
188 			status = archive->AddString("_onClickArgv", OnClickArgAt(i));
189 			if (status != B_OK)
190 				break;
191 		}
192 	}
193 
194 	if (status == B_OK) {
195 		const BBitmap* icon = Icon();
196 		if (icon != NULL) {
197 			BMessage iconArchive;
198 			status = icon->Archive(&iconArchive);
199 			if (status == B_OK)
200 				archive->AddMessage("_icon", &iconArchive);
201 		}
202 	}
203 
204 	return status;
205 }
206 
207 
208 /*! \brief Notification's type.
209 
210 	\return A value of the notification_type enum that represents
211 			notification type.
212 */
213 notification_type
214 BNotification::Type() const
215 {
216 	return fType;
217 }
218 
219 
220 /*! \brief Returns notification's group.
221 
222 	\return Notification's group.
223 */
224 const char*
225 BNotification::Group() const
226 {
227 	if (fGroup == "")
228 		return NULL;
229 	return fGroup;
230 }
231 
232 
233 /*! \brief Sets notification's group.
234 
235 	Notifications can be grouped together setting the same group.
236 */
237 void
238 BNotification::SetGroup(const BString& group)
239 {
240 	fGroup = group;
241 }
242 
243 
244 /*! \brief Returns notification's title.
245 
246 	\return Notification's title.
247 */
248 const char*
249 BNotification::Title() const
250 {
251 	if (fTitle == "")
252 		return NULL;
253 	return fTitle;
254 }
255 
256 
257 /*! \brief Set notification's title.
258 */
259 void
260 BNotification::SetTitle(const BString& title)
261 {
262 	fTitle = title;
263 }
264 
265 
266 /*! \brief Returns notification's message.
267 
268 	\return Notification's message.
269 */
270 const char*
271 BNotification::Content() const
272 {
273 	if (fContent == "")
274 		return NULL;
275 	return fContent;
276 }
277 
278 
279 /*! \brief Sets notification's message.
280 */
281 void
282 BNotification::SetContent(const BString& content)
283 {
284 	fContent = content;
285 }
286 
287 
288 /*! \brief Returns notification's message identifier.
289 
290 	\return Notification's message identifier.
291 */
292 const char*
293 BNotification::MessageID() const
294 {
295 	if (fID == "")
296 		return NULL;
297 	return fID;
298 }
299 
300 
301 /*! \brief Sets notification's message identifier.
302 */
303 void
304 BNotification::SetMessageID(const BString& id)
305 {
306 	fID = id;
307 }
308 
309 
310 /*! \brief Returns progress information.
311 
312 	If notification's type is \c B_PROGRESS_NOTIFICATION, returns a value
313 	between 0.0 and 1.0 that represent progress percentage.
314 
315 	If notification's type is not \c B_PROGRESS_NOTIFICATION, returns -1.
316 
317 	\return Percentage if notification's type is B_PROGRESS_NOTIFICATION
318 			or otherwise -1.
319 */
320 float
321 BNotification::Progress() const
322 {
323 	if (fType != B_PROGRESS_NOTIFICATION)
324 		return -1;
325 	return fProgress;
326 }
327 
328 
329 /*! \brief Sets progress information.
330 
331 	Sets progress percentage, this information will be used only
332 	if notification's type is \c B_PROGRESS_NOTIFICATION.
333 
334 	The value of @progress must be between 0.0 and 1.0.
335 */
336 void
337 BNotification::SetProgress(float progress)
338 {
339 	if (progress < 0)
340 		fProgress = 0;
341 	else if (progress > 1)
342 		fProgress = 1;
343 	else
344 		fProgress = progress;
345 }
346 
347 
348 const char*
349 BNotification::OnClickApp() const
350 {
351 	if (fApp == "")
352 		return NULL;
353 	return fApp;
354 }
355 
356 
357 void
358 BNotification::SetOnClickApp(const BString& app)
359 {
360 	fApp = app;
361 }
362 
363 
364 const entry_ref*
365 BNotification::OnClickFile() const
366 {
367 	return fFile;
368 }
369 
370 
371 status_t
372 BNotification::SetOnClickFile(const entry_ref* file)
373 {
374 	delete fFile;
375 
376 	if (file != NULL) {
377 		fFile = new(std::nothrow) entry_ref(*file);
378 		if (fFile == NULL)
379 			return B_NO_MEMORY;
380 	} else
381 		fFile = NULL;
382 
383 	return B_OK;
384 }
385 
386 
387 status_t
388 BNotification::AddOnClickRef(const entry_ref* ref)
389 {
390 	if (ref == NULL)
391 		return B_BAD_VALUE;
392 
393 	entry_ref* clonedRef = new(std::nothrow) entry_ref(*ref);
394 	if (clonedRef == NULL || !fRefs.AddItem(clonedRef))
395 		return B_NO_MEMORY;
396 
397 	return B_OK;
398 }
399 
400 
401 int32
402 BNotification::CountOnClickRefs() const
403 {
404 	return fRefs.CountItems();
405 }
406 
407 
408 const entry_ref*
409 BNotification::OnClickRefAt(int32 index) const
410 {
411 	return (entry_ref*)fArgv.ItemAt(index);
412 }
413 
414 
415 status_t
416 BNotification::AddOnClickArg(const BString& arg)
417 {
418 	char* clonedArg = strdup(arg.String());
419 	if (clonedArg == NULL || !fArgv.AddItem(clonedArg))
420 		return B_NO_MEMORY;
421 
422 	return B_OK;
423 }
424 
425 
426 int32
427 BNotification::CountOnClickArgs() const
428 {
429 	return fArgv.CountItems();
430 }
431 
432 
433 const char*
434 BNotification::OnClickArgAt(int32 index) const
435 {
436 	return (char*)fArgv.ItemAt(index);
437 }
438 
439 
440 /*! \brief Notification's icon.
441 
442 	\return Notification's icon.
443 */
444 const BBitmap*
445 BNotification::Icon() const
446 {
447 	return fBitmap;
448 }
449 
450 
451 /*! \brief Sets notification's icon.
452 
453 	Sets notification's icon.
454 	This method does not assume ownership of @icon.
455 
456 	\param icon Icon
457 	\return
458 	- \c B_OK: Everything went fine.
459 	- \c B_NO_MEMORY: Allocation of @icon copy has failed.
460 	- \c Other errors: Creation of @icon copy failed for some reason.
461 */
462 status_t
463 BNotification::SetIcon(const BBitmap* icon)
464 {
465 	delete fBitmap;
466 
467 	if (icon != NULL) {
468 		fBitmap = new(std::nothrow) BBitmap(icon);
469 		if (fBitmap == NULL)
470 			return B_NO_MEMORY;
471 		return fBitmap->InitCheck();
472 	}
473 
474 	fBitmap = NULL;
475 	return B_OK;
476 }
477 
478 
479 /*! \brief Sends a notification to the notification_server.
480 
481 	The notification is delivered asynchronously to the notification_server,
482 	which will display it according to its settings and filters.
483 
484 	\param timeout Microseconds after the message fades out.
485 	\return
486 	- \c B_OK: Everything went fine.
487 	- \c B_BAD_PORT_ID: A connection to notification_server could not be
488 	  established or the server is not up and running anymore.
489 	- \c Other errors: Building the message from the notification failed.
490 */
491 status_t
492 BNotification::Send(bigtime_t timeout)
493 {
494 	BMessage msg(kNotificationMessage);
495 
496 	// Archive notification
497 	status_t ret = Archive(&msg);
498 
499 	// Custom time out
500 	if (ret == B_OK && timeout > 0)
501 		ret = msg.AddInt64("timeout", timeout);
502 
503 	// Send message
504 	if (ret == B_OK) {
505 		BMessenger server(kNotificationServerSignature);
506 		ret = server.SendMessage(&msg);
507 	}
508 
509 	return ret;
510 }
511