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