evolution-3.6.4/widgets/misc/e-activity-proxy.c

No issues found

  1 /*
  2  * e-activity-proxy.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-proxy.h"
 27 
 28 #include <glib/gi18n.h>
 29 
 30 #define E_ACTIVITY_PROXY_GET_PRIVATE(obj) \
 31 	(G_TYPE_INSTANCE_GET_PRIVATE \
 32 	((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxyPrivate))
 33 
 34 #define FEEDBACK_PERIOD		1 /* seconds */
 35 #define COMPLETED_ICON_NAME	"emblem-default"
 36 
 37 struct _EActivityProxyPrivate {
 38 	EActivity *activity;	/* weak reference */
 39 	GtkWidget *image;	/* not referenced */
 40 	GtkWidget *label;	/* not referenced */
 41 	GtkWidget *cancel;	/* not referenced */
 42 	GtkWidget *spinner;	/* not referenced */
 43 
 44 	/* If the user clicks the Cancel button, keep the cancelled
 45 	 * EActivity object alive for a short duration so the user
 46 	 * gets some visual feedback that cancellation worked. */
 47 	guint timeout_id;
 48 };
 49 
 50 enum {
 51 	PROP_0,
 52 	PROP_ACTIVITY
 53 };
 54 
 55 G_DEFINE_TYPE (
 56 	EActivityProxy,
 57 	e_activity_proxy,
 58 	GTK_TYPE_FRAME)
 59 
 60 static void
 61 activity_proxy_feedback (EActivityProxy *proxy)
 62 {
 63 	EActivity *activity;
 64 	EActivityState state;
 65 
 66 	activity = e_activity_proxy_get_activity (proxy);
 67 	g_return_if_fail (E_IS_ACTIVITY (activity));
 68 
 69 	state = e_activity_get_state (activity);
 70 	if (state != E_ACTIVITY_CANCELLED)
 71 		return;
 72 
 73 	if (proxy->priv->timeout_id > 0)
 74 		g_source_remove (proxy->priv->timeout_id);
 75 
 76 	/* Hold a reference on the EActivity for a short
 77 	 * period so the activity proxy stays visible. */
 78 	proxy->priv->timeout_id = g_timeout_add_seconds_full (
 79 		G_PRIORITY_LOW, FEEDBACK_PERIOD, (GSourceFunc) gtk_false,
 80 		g_object_ref (activity), (GDestroyNotify) g_object_unref);
 81 }
 82 
 83 static void
 84 activity_proxy_update (EActivityProxy *proxy)
 85 {
 86 	EActivity *activity;
 87 	EActivityState state;
 88 	GCancellable *cancellable;
 89 	const gchar *icon_name;
 90 	gboolean sensitive;
 91 	gboolean visible;
 92 	gchar *description;
 93 
 94 	activity = e_activity_proxy_get_activity (proxy);
 95 
 96 	if (activity == NULL) {
 97 		gtk_widget_hide (GTK_WIDGET (proxy));
 98 		return;
 99 	}
100 
101 	cancellable = e_activity_get_cancellable (activity);
102 	icon_name = e_activity_get_icon_name (activity);
103 	state = e_activity_get_state (activity);
104 
105 	description = e_activity_describe (activity);
106 	gtk_widget_set_tooltip_text (GTK_WIDGET (proxy), description);
107 	gtk_label_set_text (GTK_LABEL (proxy->priv->label), description);
108 
109 	if (state == E_ACTIVITY_CANCELLED) {
110 		PangoAttribute *attr;
111 		PangoAttrList *attr_list;
112 
113 		attr_list = pango_attr_list_new ();
114 
115 		attr = pango_attr_strikethrough_new (TRUE);
116 		pango_attr_list_insert (attr_list, attr);
117 
118 		gtk_label_set_attributes (
119 			GTK_LABEL (proxy->priv->label), attr_list);
120 
121 		pango_attr_list_unref (attr_list);
122 	} else
123 		gtk_label_set_attributes (
124 			GTK_LABEL (proxy->priv->label), NULL);
125 
126 	if (state == E_ACTIVITY_COMPLETED)
127 		icon_name = COMPLETED_ICON_NAME;
128 
129 	if (state == E_ACTIVITY_CANCELLED) {
130 		gtk_image_set_from_stock (
131 			GTK_IMAGE (proxy->priv->image),
132 			GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON);
133 		gtk_widget_show (proxy->priv->image);
134 	} else if (icon_name != NULL) {
135 		gtk_image_set_from_icon_name (
136 			GTK_IMAGE (proxy->priv->image),
137 			icon_name, GTK_ICON_SIZE_MENU);
138 		gtk_widget_show (proxy->priv->image);
139 	} else {
140 		gtk_widget_hide (proxy->priv->image);
141 	}
142 
143 	visible = (cancellable != NULL);
144 	gtk_widget_set_visible (proxy->priv->cancel, visible);
145 
146 	sensitive = (state == E_ACTIVITY_RUNNING);
147 	gtk_widget_set_sensitive (proxy->priv->cancel, sensitive);
148 
149 	visible = (description != NULL && *description != '\0');
150 	gtk_widget_set_visible (GTK_WIDGET (proxy), visible);
151 
152 	g_free (description);
153 }
154 
155 static void
156 activity_proxy_cancel (EActivityProxy *proxy)
157 {
158 	EActivity *activity;
159 	GCancellable *cancellable;
160 
161 	activity = e_activity_proxy_get_activity (proxy);
162 	g_return_if_fail (E_IS_ACTIVITY (activity));
163 
164 	cancellable = e_activity_get_cancellable (activity);
165 	g_cancellable_cancel (cancellable);
166 
167 	activity_proxy_update (proxy);
168 }
169 
170 static void
171 activity_proxy_weak_notify_cb (EActivityProxy *proxy,
172                                GObject *where_the_object_was)
173 {
174 	g_return_if_fail (E_IS_ACTIVITY_PROXY (proxy));
175 
176 	proxy->priv->activity = NULL;
177 	e_activity_proxy_set_activity (proxy, NULL);
178 }
179 
180 static void
181 activity_proxy_set_property (GObject *object,
182                              guint property_id,
183                              const GValue *value,
184                              GParamSpec *pspec)
185 {
186 	switch (property_id) {
187 		case PROP_ACTIVITY:
188 			e_activity_proxy_set_activity (
189 				E_ACTIVITY_PROXY (object),
190 				g_value_get_object (value));
191 			return;
192 	}
193 
194 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
195 }
196 
197 static void
198 activity_proxy_get_property (GObject *object,
199                              guint property_id,
200                              GValue *value,
201                              GParamSpec *pspec)
202 {
203 	switch (property_id) {
204 		case PROP_ACTIVITY:
205 			g_value_set_object (
206 				value, e_activity_proxy_get_activity (
207 				E_ACTIVITY_PROXY (object)));
208 			return;
209 	}
210 
211 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
212 }
213 
214 static void
215 activity_proxy_dispose (GObject *object)
216 {
217 	EActivityProxyPrivate *priv;
218 
219 	priv = E_ACTIVITY_PROXY_GET_PRIVATE (object);
220 
221 	if (priv->timeout_id > 0) {
222 		g_source_remove (priv->timeout_id);
223 		priv->timeout_id = 0;
224 	}
225 
226 	if (priv->activity != NULL) {
227 		g_signal_handlers_disconnect_matched (
228 			priv->activity, G_SIGNAL_MATCH_DATA,
229 			0, 0, NULL, NULL, object);
230 		g_object_weak_unref (
231 			G_OBJECT (priv->activity), (GWeakNotify)
232 			activity_proxy_weak_notify_cb, object);
233 		priv->activity = NULL;
234 	}
235 
236 	/* Chain up to parent's dispose() method. */
237 	G_OBJECT_CLASS (e_activity_proxy_parent_class)->dispose (object);
238 }
239 
240 static void
241 e_activity_proxy_class_init (EActivityProxyClass *class)
242 {
243 	GObjectClass *object_class;
244 
245 	g_type_class_add_private (class, sizeof (EActivityProxyPrivate));
246 
247 	object_class = G_OBJECT_CLASS (class);
248 	object_class->set_property = activity_proxy_set_property;
249 	object_class->get_property = activity_proxy_get_property;
250 	object_class->dispose = activity_proxy_dispose;
251 
252 	g_object_class_install_property (
253 		object_class,
254 		PROP_ACTIVITY,
255 		g_param_spec_object (
256 			"activity",
257 			NULL,
258 			NULL,
259 			E_TYPE_ACTIVITY,
260 			G_PARAM_READWRITE |
261 			G_PARAM_CONSTRUCT));
262 }
263 
264 static void
265 e_activity_proxy_init (EActivityProxy *proxy)
266 {
267 	GtkWidget *container;
268 	GtkWidget *widget;
269 
270 	proxy->priv = E_ACTIVITY_PROXY_GET_PRIVATE (proxy);
271 
272 	gtk_frame_set_shadow_type (GTK_FRAME (proxy), GTK_SHADOW_IN);
273 
274 	container = GTK_WIDGET (proxy);
275 
276 	widget = gtk_hbox_new (FALSE, 3);
277 	gtk_container_add (GTK_CONTAINER (container), widget);
278 	gtk_widget_show (widget);
279 
280 	container = widget;
281 
282 	widget = gtk_image_new ();
283 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
284 	proxy->priv->image = widget;
285 
286 	widget = gtk_spinner_new ();
287 	gtk_spinner_start (GTK_SPINNER (widget));
288 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 3);
289 	proxy->priv->spinner = widget;
290 
291 	/* The spinner is only visible when the image is not. */
292 	g_object_bind_property (
293 		proxy->priv->image, "visible",
294 		proxy->priv->spinner, "visible",
295 		G_BINDING_BIDIRECTIONAL |
296 		G_BINDING_SYNC_CREATE |
297 		G_BINDING_INVERT_BOOLEAN);
298 
299 	widget = gtk_label_new (NULL);
300 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
301 	gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
302 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
303 	proxy->priv->label = widget;
304 	gtk_widget_show (widget);
305 
306 	/* This is only shown if the EActivity has a GCancellable. */
307 	widget = gtk_button_new ();
308 	gtk_button_set_image (
309 		GTK_BUTTON (widget), gtk_image_new_from_stock (
310 		GTK_STOCK_CANCEL, GTK_ICON_SIZE_MENU));
311 	gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE);
312 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
313 	gtk_widget_set_tooltip_text (widget, _("Cancel"));
314 	proxy->priv->cancel = widget;
315 	gtk_widget_show (widget);
316 
317 	g_signal_connect_swapped (
318 		widget, "clicked",
319 		G_CALLBACK (activity_proxy_cancel), proxy);
320 }
321 
322 GtkWidget *
323 e_activity_proxy_new (EActivity *activity)
324 {
325 	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
326 
327 	return g_object_new (
328 		E_TYPE_ACTIVITY_PROXY, "activity", activity, NULL);
329 }
330 
331 EActivity *
332 e_activity_proxy_get_activity (EActivityProxy *proxy)
333 {
334 	g_return_val_if_fail (E_IS_ACTIVITY_PROXY (proxy), NULL);
335 
336 	return proxy->priv->activity;
337 }
338 
339 void
340 e_activity_proxy_set_activity (EActivityProxy *proxy,
341                                EActivity *activity)
342 {
343 	g_return_if_fail (E_IS_ACTIVITY_PROXY (proxy));
344 
345 	if (activity != NULL)
346 		g_return_if_fail (E_IS_ACTIVITY (activity));
347 
348 	if (proxy->priv->timeout_id > 0) {
349 		g_source_remove (proxy->priv->timeout_id);
350 		proxy->priv->timeout_id = 0;
351 	}
352 
353 	if (proxy->priv->activity != NULL) {
354 		g_signal_handlers_disconnect_matched (
355 			proxy->priv->activity, G_SIGNAL_MATCH_DATA,
356 			0, 0, NULL, NULL, proxy);
357 		g_object_weak_unref (
358 			G_OBJECT (proxy->priv->activity),
359 			(GWeakNotify) activity_proxy_weak_notify_cb, proxy);
360 	}
361 
362 	proxy->priv->activity = activity;
363 
364 	if (activity != NULL) {
365 		g_object_weak_ref (
366 			G_OBJECT (activity), (GWeakNotify)
367 			activity_proxy_weak_notify_cb, proxy);
368 
369 		g_signal_connect_swapped (
370 			activity, "notify::state",
371 			G_CALLBACK (activity_proxy_feedback), proxy);
372 
373 		g_signal_connect_swapped (
374 			activity, "notify",
375 			G_CALLBACK (activity_proxy_update), proxy);
376 	}
377 
378 	activity_proxy_update (proxy);
379 
380 	g_object_notify (G_OBJECT (proxy), "activity");
381 }