No issues found
1 /*
2 * e-activity.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "e-activity.h"
27
28 #include <stdarg.h>
29 #include <glib/gi18n.h>
30 #include <camel/camel.h>
31
32 #include "e-util/e-util.h"
33 #include "e-util/e-util-enumtypes.h"
34
35 #define E_ACTIVITY_GET_PRIVATE(obj) \
36 (G_TYPE_INSTANCE_GET_PRIVATE \
37 ((obj), E_TYPE_ACTIVITY, EActivityPrivate))
38
39 struct _EActivityPrivate {
40 GCancellable *cancellable;
41 EAlertSink *alert_sink;
42 EActivityState state;
43
44 gchar *icon_name;
45 gchar *text;
46 gdouble percent;
47
48 /* Whether to emit a runtime warning if we
49 * have to suppress a bogus percent value. */
50 gboolean warn_bogus_percent;
51 };
52
53 enum {
54 PROP_0,
55 PROP_ALERT_SINK,
56 PROP_CANCELLABLE,
57 PROP_ICON_NAME,
58 PROP_PERCENT,
59 PROP_STATE,
60 PROP_TEXT
61 };
62
63 G_DEFINE_TYPE (
64 EActivity,
65 e_activity,
66 G_TYPE_OBJECT)
67
68 static void
69 activity_camel_status_cb (EActivity *activity,
70 const gchar *description,
71 gint percent)
72 {
73 /* CamelOperation::status signals are always emitted from idle
74 * callbacks, so we don't have to screw around with locking. */
75
76 g_object_set (
77 activity, "percent", (gdouble) percent,
78 "text", description, NULL);
79 }
80
81 static void
82 activity_set_property (GObject *object,
83 guint property_id,
84 const GValue *value,
85 GParamSpec *pspec)
86 {
87 switch (property_id) {
88 case PROP_ALERT_SINK:
89 e_activity_set_alert_sink (
90 E_ACTIVITY (object),
91 g_value_get_object (value));
92 return;
93
94 case PROP_CANCELLABLE:
95 e_activity_set_cancellable (
96 E_ACTIVITY (object),
97 g_value_get_object (value));
98 return;
99
100 case PROP_ICON_NAME:
101 e_activity_set_icon_name (
102 E_ACTIVITY (object),
103 g_value_get_string (value));
104 return;
105
106 case PROP_PERCENT:
107 e_activity_set_percent (
108 E_ACTIVITY (object),
109 g_value_get_double (value));
110 return;
111
112 case PROP_STATE:
113 e_activity_set_state (
114 E_ACTIVITY (object),
115 g_value_get_enum (value));
116 return;
117
118 case PROP_TEXT:
119 e_activity_set_text (
120 E_ACTIVITY (object),
121 g_value_get_string (value));
122 return;
123 }
124
125 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
126 }
127
128 static void
129 activity_get_property (GObject *object,
130 guint property_id,
131 GValue *value,
132 GParamSpec *pspec)
133 {
134 switch (property_id) {
135 case PROP_ALERT_SINK:
136 g_value_set_object (
137 value, e_activity_get_alert_sink (
138 E_ACTIVITY (object)));
139 return;
140
141 case PROP_CANCELLABLE:
142 g_value_set_object (
143 value, e_activity_get_cancellable (
144 E_ACTIVITY (object)));
145 return;
146
147 case PROP_ICON_NAME:
148 g_value_set_string (
149 value, e_activity_get_icon_name (
150 E_ACTIVITY (object)));
151 return;
152
153 case PROP_PERCENT:
154 g_value_set_double (
155 value, e_activity_get_percent (
156 E_ACTIVITY (object)));
157 return;
158
159 case PROP_STATE:
160 g_value_set_enum (
161 value, e_activity_get_state (
162 E_ACTIVITY (object)));
163 return;
164
165 case PROP_TEXT:
166 g_value_set_string (
167 value, e_activity_get_text (
168 E_ACTIVITY (object)));
169 return;
170 }
171
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
173 }
174
175 static void
176 activity_dispose (GObject *object)
177 {
178 EActivityPrivate *priv;
179
180 priv = E_ACTIVITY_GET_PRIVATE (object);
181
182 if (priv->alert_sink != NULL) {
183 g_object_unref (priv->alert_sink);
184 priv->alert_sink = NULL;
185 }
186
187 if (priv->cancellable != NULL) {
188 g_signal_handlers_disconnect_matched (
189 priv->cancellable,
190 G_SIGNAL_MATCH_DATA,
191 0, 0, NULL, NULL, object);
192 g_object_unref (priv->cancellable);
193 priv->cancellable = NULL;
194 }
195
196 /* Chain up to parent's dispose() method. */
197 G_OBJECT_CLASS (e_activity_parent_class)->dispose (object);
198 }
199
200 static void
201 activity_finalize (GObject *object)
202 {
203 EActivityPrivate *priv;
204
205 priv = E_ACTIVITY_GET_PRIVATE (object);
206
207 g_free (priv->icon_name);
208 g_free (priv->text);
209
210 /* Chain up to parent's finalize() method. */
211 G_OBJECT_CLASS (e_activity_parent_class)->finalize (object);
212 }
213
214 static gchar *
215 activity_describe (EActivity *activity)
216 {
217 GString *string;
218 GCancellable *cancellable;
219 EActivityState state;
220 const gchar *text;
221 gdouble percent;
222
223 text = e_activity_get_text (activity);
224
225 if (text == NULL)
226 return NULL;
227
228 string = g_string_sized_new (256);
229 cancellable = e_activity_get_cancellable (activity);
230 percent = e_activity_get_percent (activity);
231 state = e_activity_get_state (activity);
232
233 /* Sanity check the percentage. */
234 if (percent > 100.0) {
235 if (activity->priv->warn_bogus_percent) {
236 g_warning (
237 "Nonsensical (%d%% complete) reported on "
238 "activity \"%s\"", (gint) (percent), text);
239 activity->priv->warn_bogus_percent = FALSE;
240 }
241 percent = -1.0; /* suppress it */
242 } else {
243 activity->priv->warn_bogus_percent = TRUE;
244 }
245
246 if (state == E_ACTIVITY_CANCELLED) {
247 /* Translators: This is a cancelled activity. */
248 g_string_printf (string, _("%s (cancelled)"), text);
249 } else if (state == E_ACTIVITY_COMPLETED) {
250 /* Translators: This is a completed activity. */
251 g_string_printf (string, _("%s (completed)"), text);
252 } else if (state == E_ACTIVITY_WAITING) {
253 /* Translators: This is an activity waiting to run. */
254 g_string_printf (string, _("%s (waiting)"), text);
255 } else if (g_cancellable_is_cancelled (cancellable)) {
256 /* Translators: This is a running activity which
257 * the user has requested to cancel. */
258 g_string_printf (string, _("%s (cancelling)"), text);
259 } else if (percent <= 0.0) {
260 g_string_printf (string, _("%s"), text);
261 } else {
262 /* Translators: This is a running activity whose
263 * percent complete is known. */
264 g_string_printf (
265 string, _("%s (%d%% complete)"),
266 text, (gint) (percent));
267 }
268
269 return g_string_free (string, FALSE);
270 }
271
272 static void
273 e_activity_class_init (EActivityClass *class)
274 {
275 GObjectClass *object_class;
276
277 g_type_class_add_private (class, sizeof (EActivityPrivate));
278
279 object_class = G_OBJECT_CLASS (class);
280 object_class->set_property = activity_set_property;
281 object_class->get_property = activity_get_property;
282 object_class->dispose = activity_dispose;
283 object_class->finalize = activity_finalize;
284
285 class->describe = activity_describe;
286
287 g_object_class_install_property (
288 object_class,
289 PROP_ALERT_SINK,
290 g_param_spec_object (
291 "alert-sink",
292 NULL,
293 NULL,
294 E_TYPE_ALERT_SINK,
295 G_PARAM_READWRITE |
296 G_PARAM_CONSTRUCT));
297
298 g_object_class_install_property (
299 object_class,
300 PROP_CANCELLABLE,
301 g_param_spec_object (
302 "cancellable",
303 NULL,
304 NULL,
305 G_TYPE_CANCELLABLE,
306 G_PARAM_READWRITE |
307 G_PARAM_CONSTRUCT));
308
309 g_object_class_install_property (
310 object_class,
311 PROP_ICON_NAME,
312 g_param_spec_string (
313 "icon-name",
314 NULL,
315 NULL,
316 NULL,
317 G_PARAM_READWRITE |
318 G_PARAM_CONSTRUCT));
319
320 g_object_class_install_property (
321 object_class,
322 PROP_PERCENT,
323 g_param_spec_double (
324 "percent",
325 NULL,
326 NULL,
327 -G_MAXDOUBLE,
328 G_MAXDOUBLE,
329 -1.0,
330 G_PARAM_READWRITE |
331 G_PARAM_CONSTRUCT));
332
333 g_object_class_install_property (
334 object_class,
335 PROP_STATE,
336 g_param_spec_enum (
337 "state",
338 NULL,
339 NULL,
340 E_TYPE_ACTIVITY_STATE,
341 E_ACTIVITY_RUNNING,
342 G_PARAM_READWRITE |
343 G_PARAM_CONSTRUCT));
344
345 g_object_class_install_property (
346 object_class,
347 PROP_TEXT,
348 g_param_spec_string (
349 "text",
350 NULL,
351 NULL,
352 NULL,
353 G_PARAM_READWRITE |
354 G_PARAM_CONSTRUCT));
355 }
356
357 static void
358 e_activity_init (EActivity *activity)
359 {
360 activity->priv = E_ACTIVITY_GET_PRIVATE (activity);
361 activity->priv->warn_bogus_percent = TRUE;
362 }
363
364 EActivity *
365 e_activity_new (void)
366 {
367 return g_object_new (E_TYPE_ACTIVITY, NULL);
368 }
369
370 gchar *
371 e_activity_describe (EActivity *activity)
372 {
373 EActivityClass *class;
374
375 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
376
377 class = E_ACTIVITY_GET_CLASS (activity);
378 g_return_val_if_fail (class->describe != NULL, NULL);
379
380 return class->describe (activity);
381 }
382
383 EAlertSink *
384 e_activity_get_alert_sink (EActivity *activity)
385 {
386 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
387
388 return activity->priv->alert_sink;
389 }
390
391 void
392 e_activity_set_alert_sink (EActivity *activity,
393 EAlertSink *alert_sink)
394 {
395 g_return_if_fail (E_IS_ACTIVITY (activity));
396
397 if (activity->priv->alert_sink == alert_sink)
398 return;
399
400 if (alert_sink != NULL) {
401 g_return_if_fail (E_IS_ALERT_SINK (alert_sink));
402 g_object_ref (alert_sink);
403 }
404
405 if (activity->priv->alert_sink != NULL)
406 g_object_unref (activity->priv->alert_sink);
407
408 activity->priv->alert_sink = alert_sink;
409
410 g_object_notify (G_OBJECT (activity), "alert-sink");
411 }
412
413 GCancellable *
414 e_activity_get_cancellable (EActivity *activity)
415 {
416 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
417
418 return activity->priv->cancellable;
419 }
420
421 void
422 e_activity_set_cancellable (EActivity *activity,
423 GCancellable *cancellable)
424 {
425 g_return_if_fail (E_IS_ACTIVITY (activity));
426
427 if (activity->priv->cancellable == cancellable)
428 return;
429
430 if (cancellable != NULL) {
431 g_return_if_fail (G_IS_CANCELLABLE (cancellable));
432 g_object_ref (cancellable);
433 }
434
435 if (activity->priv->cancellable != NULL) {
436 g_signal_handlers_disconnect_matched (
437 activity->priv->cancellable,
438 G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, activity);
439 g_object_unref (activity->priv->cancellable);
440 }
441
442 activity->priv->cancellable = cancellable;
443
444 /* If this is a CamelOperation, listen for status updates
445 * from it and propagate them to our own status properties. */
446 if (CAMEL_IS_OPERATION (cancellable))
447 g_signal_connect_swapped (
448 cancellable, "status",
449 G_CALLBACK (activity_camel_status_cb), activity);
450
451 g_object_notify (G_OBJECT (activity), "cancellable");
452 }
453
454 const gchar *
455 e_activity_get_icon_name (EActivity *activity)
456 {
457 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
458
459 return activity->priv->icon_name;
460 }
461
462 void
463 e_activity_set_icon_name (EActivity *activity,
464 const gchar *icon_name)
465 {
466 g_return_if_fail (E_IS_ACTIVITY (activity));
467
468 if (g_strcmp0 (activity->priv->icon_name, icon_name) == 0)
469 return;
470
471 g_free (activity->priv->icon_name);
472 activity->priv->icon_name = g_strdup (icon_name);
473
474 g_object_notify (G_OBJECT (activity), "icon-name");
475 }
476
477 gdouble
478 e_activity_get_percent (EActivity *activity)
479 {
480 g_return_val_if_fail (E_IS_ACTIVITY (activity), -1.0);
481
482 return activity->priv->percent;
483 }
484
485 void
486 e_activity_set_percent (EActivity *activity,
487 gdouble percent)
488 {
489 g_return_if_fail (E_IS_ACTIVITY (activity));
490
491 if (activity->priv->percent == percent)
492 return;
493
494 activity->priv->percent = percent;
495
496 g_object_notify (G_OBJECT (activity), "percent");
497 }
498
499 EActivityState
500 e_activity_get_state (EActivity *activity)
501 {
502 g_return_val_if_fail (E_IS_ACTIVITY (activity), 0);
503
504 return activity->priv->state;
505 }
506
507 void
508 e_activity_set_state (EActivity *activity,
509 EActivityState state)
510 {
511 g_return_if_fail (E_IS_ACTIVITY (activity));
512
513 if (activity->priv->state == state)
514 return;
515
516 activity->priv->state = state;
517
518 g_object_notify (G_OBJECT (activity), "state");
519 }
520
521 const gchar *
522 e_activity_get_text (EActivity *activity)
523 {
524 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
525
526 return activity->priv->text;
527 }
528
529 void
530 e_activity_set_text (EActivity *activity,
531 const gchar *text)
532 {
533 g_return_if_fail (E_IS_ACTIVITY (activity));
534
535 if (g_strcmp0 (activity->priv->text, text) == 0)
536 return;
537
538 g_free (activity->priv->text);
539 activity->priv->text = g_strdup (text);
540
541 g_object_notify (G_OBJECT (activity), "text");
542 }
543
544 gboolean
545 e_activity_handle_cancellation (EActivity *activity,
546 const GError *error)
547 {
548 gboolean handled = FALSE;
549
550 g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
551
552 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
553 e_activity_set_state (activity, E_ACTIVITY_CANCELLED);
554 handled = TRUE;
555 }
556
557 return handled;
558 }