1 /*
2 * e-activity.c
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 /**
19 * SECTION: e-activity
20 * @include: e-util/e-util.h
21 * @short_description: Describe activities in progress
22 *
23 * #EActivity is used to track and describe application activities in
24 * progress. An #EActivity usually manifests in a user interface as a
25 * status bar message (see #EActivityProxy) or information bar message
26 * (see #EActivityBar), with optional progress indication and a cancel
27 * button which is linked to a #GCancellable.
28 **/
29
30 #include "evolution-config.h"
31
32 #include "e-activity.h"
33
34 #include <stdarg.h>
35 #include <glib/gi18n.h>
36 #include <camel/camel.h>
37 #include <libedataserver/libedataserver.h>
38
39 #include "e-util-enumtypes.h"
40
41 #define E_ACTIVITY_GET_PRIVATE(obj) \
42 (G_TYPE_INSTANCE_GET_PRIVATE \
43 ((obj), E_TYPE_ACTIVITY, EActivityPrivate))
44
45 struct _EActivityPrivate {
46 GCancellable *cancellable;
47 EAlertSink *alert_sink;
48 EActivityState state;
49
50 gchar *icon_name;
51 gchar *text;
52 gchar *last_known_text;
53 gdouble percent;
54
55 /* Whether to emit a runtime warning if we
56 * have to suppress a bogus percent value. */
57 gboolean warn_bogus_percent;
58 };
59
60 enum {
61 PROP_0,
62 PROP_ALERT_SINK,
63 PROP_CANCELLABLE,
64 PROP_ICON_NAME,
65 PROP_PERCENT,
66 PROP_STATE,
67 PROP_TEXT
68 };
69
G_DEFINE_TYPE(EActivity,e_activity,G_TYPE_OBJECT)70 G_DEFINE_TYPE (
71 EActivity,
72 e_activity,
73 G_TYPE_OBJECT)
74
75 static void
76 activity_camel_status_cb (EActivity *activity,
77 const gchar *description,
78 gint percent)
79 {
80 /* CamelOperation::status signals are always emitted from idle
81 * callbacks, so we don't have to screw around with locking. */
82
83 g_object_set (
84 activity, "percent", (gdouble) percent,
85 "text", description, NULL);
86 }
87
88 static void
activity_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)89 activity_set_property (GObject *object,
90 guint property_id,
91 const GValue *value,
92 GParamSpec *pspec)
93 {
94 switch (property_id) {
95 case PROP_ALERT_SINK:
96 e_activity_set_alert_sink (
97 E_ACTIVITY (object),
98 g_value_get_object (value));
99 return;
100
101 case PROP_CANCELLABLE:
102 e_activity_set_cancellable (
103 E_ACTIVITY (object),
104 g_value_get_object (value));
105 return;
106
107 case PROP_ICON_NAME:
108 e_activity_set_icon_name (
109 E_ACTIVITY (object),
110 g_value_get_string (value));
111 return;
112
113 case PROP_PERCENT:
114 e_activity_set_percent (
115 E_ACTIVITY (object),
116 g_value_get_double (value));
117 return;
118
119 case PROP_STATE:
120 e_activity_set_state (
121 E_ACTIVITY (object),
122 g_value_get_enum (value));
123 return;
124
125 case PROP_TEXT:
126 e_activity_set_text (
127 E_ACTIVITY (object),
128 g_value_get_string (value));
129 return;
130 }
131
132 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
133 }
134
135 static void
activity_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)136 activity_get_property (GObject *object,
137 guint property_id,
138 GValue *value,
139 GParamSpec *pspec)
140 {
141 switch (property_id) {
142 case PROP_ALERT_SINK:
143 g_value_set_object (
144 value, e_activity_get_alert_sink (
145 E_ACTIVITY (object)));
146 return;
147
148 case PROP_CANCELLABLE:
149 g_value_set_object (
150 value, e_activity_get_cancellable (
151 E_ACTIVITY (object)));
152 return;
153
154 case PROP_ICON_NAME:
155 g_value_set_string (
156 value, e_activity_get_icon_name (
157 E_ACTIVITY (object)));
158 return;
159
160 case PROP_PERCENT:
161 g_value_set_double (
162 value, e_activity_get_percent (
163 E_ACTIVITY (object)));
164 return;
165
166 case PROP_STATE:
167 g_value_set_enum (
168 value, e_activity_get_state (
169 E_ACTIVITY (object)));
170 return;
171
172 case PROP_TEXT:
173 g_value_set_string (
174 value, e_activity_get_text (
175 E_ACTIVITY (object)));
176 return;
177 }
178
179 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
180 }
181
182 static void
activity_dispose(GObject * object)183 activity_dispose (GObject *object)
184 {
185 EActivityPrivate *priv;
186
187 priv = E_ACTIVITY_GET_PRIVATE (object);
188 g_clear_object (&priv->alert_sink);
189
190 if (priv->cancellable != NULL) {
191 g_signal_handlers_disconnect_matched (
192 priv->cancellable,
193 G_SIGNAL_MATCH_DATA,
194 0, 0, NULL, NULL, object);
195 g_object_unref (priv->cancellable);
196 priv->cancellable = NULL;
197 }
198
199 /* Chain up to parent's dispose() method. */
200 G_OBJECT_CLASS (e_activity_parent_class)->dispose (object);
201 }
202
203 static void
activity_finalize(GObject * object)204 activity_finalize (GObject *object)
205 {
206 EActivityPrivate *priv;
207
208 priv = E_ACTIVITY_GET_PRIVATE (object);
209
210 g_free (priv->icon_name);
211 g_free (priv->text);
212 g_free (priv->last_known_text);
213
214 /* Chain up to parent's finalize() method. */
215 G_OBJECT_CLASS (e_activity_parent_class)->finalize (object);
216 }
217
218 static gchar *
activity_describe(EActivity * activity)219 activity_describe (EActivity *activity)
220 {
221 GString *string;
222 GCancellable *cancellable;
223 EActivityState state;
224 const gchar *text;
225 gdouble percent;
226
227 text = e_activity_get_text (activity);
228
229 if (text == NULL)
230 return NULL;
231
232 string = g_string_sized_new (256);
233 cancellable = e_activity_get_cancellable (activity);
234 percent = e_activity_get_percent (activity);
235 state = e_activity_get_state (activity);
236
237 /* Sanity check the percentage. */
238 if (percent > 100.0) {
239 if (activity->priv->warn_bogus_percent) {
240 g_warning (
241 "Nonsensical (%d%% complete) reported on "
242 "activity \"%s\"", (gint) (percent), text);
243 activity->priv->warn_bogus_percent = FALSE;
244 }
245 percent = -1.0; /* suppress it */
246 } else {
247 activity->priv->warn_bogus_percent = TRUE;
248 }
249
250 if (state == E_ACTIVITY_CANCELLED) {
251 /* Translators: This is a cancelled activity. */
252 g_string_printf (string, _("%s (cancelled)"), text);
253 } else if (state == E_ACTIVITY_COMPLETED) {
254 /* Translators: This is a completed activity. */
255 g_string_printf (string, _("%s (completed)"), text);
256 } else if (state == E_ACTIVITY_WAITING) {
257 /* Translators: This is an activity waiting to run. */
258 g_string_printf (string, _("%s (waiting)"), text);
259 } else if (g_cancellable_is_cancelled (cancellable)) {
260 /* Translators: This is a running activity which
261 * the user has requested to cancel. */
262 g_string_printf (string, _("%s (cancelling)"), text);
263 } else if (percent <= 0.0) {
264 g_string_printf (string, _("%s"), text);
265 } else {
266 g_string_printf (
267 /* Translators: This is a running activity whose
268 * percent complete is known. */
269 string, _("%s (%d%% complete)"),
270 text, (gint) (percent));
271 }
272
273 return g_string_free (string, FALSE);
274 }
275
276 static void
e_activity_class_init(EActivityClass * class)277 e_activity_class_init (EActivityClass *class)
278 {
279 GObjectClass *object_class;
280
281 g_type_class_add_private (class, sizeof (EActivityPrivate));
282
283 object_class = G_OBJECT_CLASS (class);
284 object_class->set_property = activity_set_property;
285 object_class->get_property = activity_get_property;
286 object_class->dispose = activity_dispose;
287 object_class->finalize = activity_finalize;
288
289 class->describe = activity_describe;
290
291 g_object_class_install_property (
292 object_class,
293 PROP_ALERT_SINK,
294 g_param_spec_object (
295 "alert-sink",
296 NULL,
297 NULL,
298 E_TYPE_ALERT_SINK,
299 G_PARAM_READWRITE |
300 G_PARAM_CONSTRUCT));
301
302 g_object_class_install_property (
303 object_class,
304 PROP_CANCELLABLE,
305 g_param_spec_object (
306 "cancellable",
307 NULL,
308 NULL,
309 G_TYPE_CANCELLABLE,
310 G_PARAM_READWRITE |
311 G_PARAM_CONSTRUCT));
312
313 g_object_class_install_property (
314 object_class,
315 PROP_ICON_NAME,
316 g_param_spec_string (
317 "icon-name",
318 NULL,
319 NULL,
320 NULL,
321 G_PARAM_READWRITE |
322 G_PARAM_CONSTRUCT));
323
324 g_object_class_install_property (
325 object_class,
326 PROP_PERCENT,
327 g_param_spec_double (
328 "percent",
329 NULL,
330 NULL,
331 -G_MAXDOUBLE,
332 G_MAXDOUBLE,
333 -1.0,
334 G_PARAM_READWRITE |
335 G_PARAM_CONSTRUCT));
336
337 g_object_class_install_property (
338 object_class,
339 PROP_STATE,
340 g_param_spec_enum (
341 "state",
342 NULL,
343 NULL,
344 E_TYPE_ACTIVITY_STATE,
345 E_ACTIVITY_RUNNING,
346 G_PARAM_READWRITE |
347 G_PARAM_CONSTRUCT));
348
349 g_object_class_install_property (
350 object_class,
351 PROP_TEXT,
352 g_param_spec_string (
353 "text",
354 NULL,
355 NULL,
356 NULL,
357 G_PARAM_READWRITE |
358 G_PARAM_CONSTRUCT));
359 }
360
361 static void
e_activity_init(EActivity * activity)362 e_activity_init (EActivity *activity)
363 {
364 activity->priv = E_ACTIVITY_GET_PRIVATE (activity);
365 activity->priv->warn_bogus_percent = TRUE;
366 }
367
368 /**
369 * e_activity_new:
370 *
371 * Creates a new #EActivity.
372 *
373 * Returns: an #EActivity
374 **/
375 EActivity *
e_activity_new(void)376 e_activity_new (void)
377 {
378 return g_object_new (E_TYPE_ACTIVITY, NULL);
379 }
380
381 /**
382 * e_activity_cancel:
383 * @activity: an #EActivity
384 *
385 * Convenience function cancels @activity's #EActivity:cancellable.
386 *
387 * <para>
388 * <note>
389 * This function will not set @activity's #EActivity:state to
390 * @E_ACTIVITY_CANCELLED. It merely requests that the associated
391 * operation be cancelled. Only after the operation finishes with
392 * a @G_IO_ERROR_CANCELLED should the @activity's #EActivity:state
393 * be changed (see e_activity_handle_cancellation()). During this
394 * interim period e_activity_describe() will indicate the activity
395 * is "cancelling".
396 * </note>
397 * </para>
398 **/
399 void
e_activity_cancel(EActivity * activity)400 e_activity_cancel (EActivity *activity)
401 {
402 g_return_if_fail (E_IS_ACTIVITY (activity));
403
404 /* This function handles NULL gracefully. */
405 g_cancellable_cancel (activity->priv->cancellable);
406 }
407
408 /**
409 * e_activity_describe:
410 * @activity: an #EActivity
411 *
412 * Returns a description of the current state of the @activity based on
413 * the #EActivity:text, #EActivity:percent and #EActivity:state properties.
414 * Suitable for displaying in a status bar or similar widget.
415 *
416 * Free the returned string with g_free() when finished with it.
417 *
418 * Returns: a description of @activity
419 **/
420 gchar *
e_activity_describe(EActivity * activity)421 e_activity_describe (EActivity *activity)
422 {
423 EActivityClass *class;
424
425 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
426
427 class = E_ACTIVITY_GET_CLASS (activity);
428 g_return_val_if_fail (class != NULL, NULL);
429 g_return_val_if_fail (class->describe != NULL, NULL);
430
431 return class->describe (activity);
432 }
433
434 /**
435 * e_activity_get_alert_sink:
436 * @activity: an #EActivity
437 *
438 * Returns the #EAlertSink for @activity, if one was provided.
439 *
440 * The #EActivity:alert-sink property is convenient for when the user
441 * should be alerted about a failed asynchronous operation. Generally
442 * an #EActivity:alert-sink is set prior to dispatching the operation,
443 * and retrieved by a callback function when the operation completes.
444 *
445 * Returns: an #EAlertSink, or %NULL
446 **/
447 EAlertSink *
e_activity_get_alert_sink(EActivity * activity)448 e_activity_get_alert_sink (EActivity *activity)
449 {
450 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
451
452 return activity->priv->alert_sink;
453 }
454
455 /**
456 * e_activity_set_alert_sink:
457 * @activity: an #EActivity
458 * @alert_sink: an #EAlertSink, or %NULL
459 *
460 * Sets (or clears) the #EAlertSink for @activity.
461 *
462 * The #EActivity:alert-sink property is convenient for when the user
463 * should be alerted about a failed asynchronous operation. Generally
464 * an #EActivity:alert-sink is set prior to dispatching the operation,
465 * and retrieved by a callback function when the operation completes.
466 **/
467 void
e_activity_set_alert_sink(EActivity * activity,EAlertSink * alert_sink)468 e_activity_set_alert_sink (EActivity *activity,
469 EAlertSink *alert_sink)
470 {
471 g_return_if_fail (E_IS_ACTIVITY (activity));
472
473 if (activity->priv->alert_sink == alert_sink)
474 return;
475
476 if (alert_sink != NULL) {
477 g_return_if_fail (E_IS_ALERT_SINK (alert_sink));
478 g_object_ref (alert_sink);
479 }
480
481 if (activity->priv->alert_sink != NULL)
482 g_object_unref (activity->priv->alert_sink);
483
484 activity->priv->alert_sink = alert_sink;
485
486 g_object_notify (G_OBJECT (activity), "alert-sink");
487 }
488
489 /**
490 * e_activity_get_cancellable:
491 * @activity: an #EActivity
492 *
493 * Returns the #GCancellable for @activity, if one was provided.
494 *
495 * Generally the @activity's #EActivity:cancellable property holds the same
496 * #GCancellable instance passed to a cancellable function, so widgets like
497 * #EActivityBar can bind the #GCancellable to a cancel button.
498 *
499 * Returns: a #GCancellable, or %NULL
500 **/
501 GCancellable *
e_activity_get_cancellable(EActivity * activity)502 e_activity_get_cancellable (EActivity *activity)
503 {
504 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
505
506 return activity->priv->cancellable;
507 }
508
509 /**
510 * e_activity_set_cancellable:
511 * @activity: an #EActivity
512 * @cancellable: a #GCancellable, or %NULL
513 *
514 * Sets (or clears) the #GCancellable for @activity.
515 *
516 * Generally the @activity's #EActivity:cancellable property holds the same
517 * #GCancellable instance passed to a cancellable function, so widgets like
518 * #EActivityBar can bind the #GCancellable to a cancel button.
519 **/
520 void
e_activity_set_cancellable(EActivity * activity,GCancellable * cancellable)521 e_activity_set_cancellable (EActivity *activity,
522 GCancellable *cancellable)
523 {
524 g_return_if_fail (E_IS_ACTIVITY (activity));
525
526 if (activity->priv->cancellable == cancellable)
527 return;
528
529 if (cancellable != NULL) {
530 g_return_if_fail (G_IS_CANCELLABLE (cancellable));
531 g_object_ref (cancellable);
532 }
533
534 if (activity->priv->cancellable != NULL) {
535 g_signal_handlers_disconnect_matched (
536 activity->priv->cancellable,
537 G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, activity);
538 g_object_unref (activity->priv->cancellable);
539 }
540
541 activity->priv->cancellable = cancellable;
542
543 /* If this is a CamelOperation, listen for status updates
544 * from it and propagate them to our own status properties. */
545 if (CAMEL_IS_OPERATION (cancellable))
546 g_signal_connect_swapped (
547 cancellable, "status",
548 G_CALLBACK (activity_camel_status_cb), activity);
549
550 g_object_notify (G_OBJECT (activity), "cancellable");
551 }
552
553 /**
554 * e_activity_get_icon_name:
555 * @activity: an #EActivity
556 *
557 * Returns the themed icon name for @activity, if one was provided.
558 *
559 * Generally widgets like #EActivityBar will honor the #EActivity:icon-name
560 * property while the @activity's #EActivity:state is @E_ACTIVITY_RUNNING or
561 * @E_ACTIVITY_WAITING, but will override the icon for @E_ACTIVITY_CANCELLED
562 * and @E_ACTIVITY_COMPLETED.
563 *
564 * Returns: a themed icon name, or %NULL
565 **/
566 const gchar *
e_activity_get_icon_name(EActivity * activity)567 e_activity_get_icon_name (EActivity *activity)
568 {
569 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
570
571 return activity->priv->icon_name;
572 }
573
574 /**
575 * e_activity_set_icon_name:
576 * @activity: an #EActivity
577 * @icon_name: a themed icon name, or %NULL
578 *
579 * Sets (or clears) the themed icon name for @activity.
580 *
581 * Generally widgets like #EActivityBar will honor the #EActivity:icon-name
582 * property while the @activity's #EActivity:state is @E_ACTIVITY_RUNNING or
583 * @E_ACTIVITY_WAITING, but will override the icon for @E_ACTIVITY_CANCELLED
584 * and @E_ACTIVITY_COMPLETED.
585 **/
586 void
e_activity_set_icon_name(EActivity * activity,const gchar * icon_name)587 e_activity_set_icon_name (EActivity *activity,
588 const gchar *icon_name)
589 {
590 g_return_if_fail (E_IS_ACTIVITY (activity));
591
592 if (g_strcmp0 (activity->priv->icon_name, icon_name) == 0)
593 return;
594
595 g_free (activity->priv->icon_name);
596 activity->priv->icon_name = g_strdup (icon_name);
597
598 g_object_notify (G_OBJECT (activity), "icon-name");
599 }
600
601 /**
602 * e_activity_get_percent:
603 * @activity: an #EActivity
604 *
605 * Returns the percent complete for @activity as a value between 0 and 100,
606 * or a negative value if the percent complete is unknown.
607 *
608 * Generally widgets like #EActivityBar will display the percent complete by
609 * way of e_activity_describe(), but only if the value is between 0 and 100.
610 *
611 * Returns: the percent complete, or a negative value if unknown
612 **/
613 gdouble
e_activity_get_percent(EActivity * activity)614 e_activity_get_percent (EActivity *activity)
615 {
616 g_return_val_if_fail (E_IS_ACTIVITY (activity), -1.0);
617
618 return activity->priv->percent;
619 }
620
621 /**
622 * e_activity_set_percent:
623 * @activity: an #EActivity
624 * @percent: the percent complete, or a negative value if unknown
625 *
626 * Sets the percent complete for @activity. The value should be between 0
627 * and 100, or negative if the percent complete is unknown.
628 *
629 * Generally widgets like #EActivityBar will display the percent complete by
630 * way of e_activity_describe(), but only if the value is between 0 and 100.
631 **/
632 void
e_activity_set_percent(EActivity * activity,gdouble percent)633 e_activity_set_percent (EActivity *activity,
634 gdouble percent)
635 {
636 g_return_if_fail (E_IS_ACTIVITY (activity));
637
638 if (activity->priv->percent == percent)
639 return;
640
641 activity->priv->percent = percent;
642
643 g_object_notify (G_OBJECT (activity), "percent");
644 }
645
646 /**
647 * e_activity_get_state:
648 * @activity: an #EActivity
649 *
650 * Returns the state of @activity.
651 *
652 * Generally widgets like #EActivityBar will display the activity state by
653 * way of e_activity_describe() and possibly an icon. The activity state is
654 * @E_ACTIVITY_RUNNING by default, and is usually only changed once when the
655 * associated operation is finished.
656 *
657 * Returns: an #EActivityState
658 **/
659 EActivityState
e_activity_get_state(EActivity * activity)660 e_activity_get_state (EActivity *activity)
661 {
662 g_return_val_if_fail (E_IS_ACTIVITY (activity), 0);
663
664 return activity->priv->state;
665 }
666
667 /**
668 * e_activity_set_state:
669 * @activity: an #EActivity
670 * @state: an #EActivityState
671 *
672 * Sets the state of @activity.
673 *
674 * Generally widgets like #EActivityBar will display the activity state by
675 * way of e_activity_describe() and possibly an icon. The activity state is
676 * @E_ACTIVITY_RUNNING by default, and is usually only changed once when the
677 * associated operation is finished.
678 **/
679 void
e_activity_set_state(EActivity * activity,EActivityState state)680 e_activity_set_state (EActivity *activity,
681 EActivityState state)
682 {
683 g_return_if_fail (E_IS_ACTIVITY (activity));
684
685 if (activity->priv->state == state)
686 return;
687
688 activity->priv->state = state;
689
690 g_object_notify (G_OBJECT (activity), "state");
691 }
692
693 /**
694 * e_activity_get_text:
695 * @activity: an #EActivity
696 *
697 * Returns a message describing what @activity is doing.
698 *
699 * Generally widgets like #EActivityBar will display the message by way of
700 * e_activity_describe().
701 *
702 * Returns: a descriptive message
703 **/
704 const gchar *
e_activity_get_text(EActivity * activity)705 e_activity_get_text (EActivity *activity)
706 {
707 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
708
709 return activity->priv->text;
710 }
711
712 /**
713 * e_activity_set_text:
714 * @activity: an #EActivity
715 * @text: a descriptive message, or %NULL
716 *
717 * Sets (or clears) a message describing what @activity is doing.
718 *
719 * Generally widgets like #EActivityBar will display the message by way of
720 * e_activity_describe().
721 **/
722 void
e_activity_set_text(EActivity * activity,const gchar * text)723 e_activity_set_text (EActivity *activity,
724 const gchar *text)
725 {
726 gchar *last_known_text = NULL;
727
728 g_return_if_fail (E_IS_ACTIVITY (activity));
729
730 if (g_strcmp0 (activity->priv->text, text) == 0)
731 return;
732
733 g_free (activity->priv->text);
734 activity->priv->text = g_strdup (text);
735
736 /* See e_activity_get_last_known_text(). */
737 last_known_text = e_util_strdup_strip (text);
738 if (last_known_text != NULL) {
739 g_free (activity->priv->last_known_text);
740 activity->priv->last_known_text = last_known_text;
741 }
742
743 g_object_notify (G_OBJECT (activity), "text");
744 }
745
746 /**
747 * e_activity_get_last_known_text:
748 * @activity: an #EActivity
749 *
750 * Returns the last non-empty #EActivity:text value, so it's possible to
751 * identify what the @activity <emphasis>was</emphasis> doing even if it
752 * currently has no description.
753 *
754 * Mostly useful for debugging.
755 *
756 * Returns: a descriptive message, or %NULL
757 **/
758 const gchar *
e_activity_get_last_known_text(EActivity * activity)759 e_activity_get_last_known_text (EActivity *activity)
760 {
761 g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
762
763 return activity->priv->last_known_text;
764 }
765
766 /**
767 * e_activity_handle_cancellation:
768 * @activity: an #EActivity
769 * @error: a #GError, or %NULL
770 *
771 * Convenience function sets @activity's #EActivity:state to
772 * @E_ACTIVITY_CANCELLED if @error is @G_IO_ERROR_CANCELLED.
773 *
774 * Returns: %TRUE if @activity was set to @E_ACTIVITY_CANCELLED
775 **/
776 gboolean
e_activity_handle_cancellation(EActivity * activity,const GError * error)777 e_activity_handle_cancellation (EActivity *activity,
778 const GError *error)
779 {
780 gboolean handled = FALSE;
781
782 g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
783
784 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
785 e_activity_set_state (activity, E_ACTIVITY_CANCELLED);
786 handled = TRUE;
787 }
788
789 return handled;
790 }
791