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