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

No issues found

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