382 lines
9.8 KiB
C
382 lines
9.8 KiB
C
/*
|
|
* e-activity-proxy.c
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with the program; if not, see <http://www.gnu.org/licenses/>
|
|
*
|
|
*
|
|
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include "e-activity-proxy.h"
|
|
|
|
#include <glib/gi18n.h>
|
|
|
|
#define E_ACTIVITY_PROXY_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE \
|
|
((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxyPrivate))
|
|
|
|
#define FEEDBACK_PERIOD 1 /* seconds */
|
|
#define COMPLETED_ICON_NAME "emblem-default"
|
|
|
|
struct _EActivityProxyPrivate {
|
|
EActivity *activity; /* weak reference */
|
|
GtkWidget *image; /* not referenced */
|
|
GtkWidget *label; /* not referenced */
|
|
GtkWidget *cancel; /* not referenced */
|
|
GtkWidget *spinner; /* not referenced */
|
|
|
|
/* If the user clicks the Cancel button, keep the cancelled
|
|
* EActivity object alive for a short duration so the user
|
|
* gets some visual feedback that cancellation worked. */
|
|
guint timeout_id;
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_ACTIVITY
|
|
};
|
|
|
|
G_DEFINE_TYPE (
|
|
EActivityProxy,
|
|
e_activity_proxy,
|
|
GTK_TYPE_FRAME)
|
|
|
|
static void
|
|
activity_proxy_feedback (EActivityProxy *proxy)
|
|
{
|
|
EActivity *activity;
|
|
EActivityState state;
|
|
|
|
activity = e_activity_proxy_get_activity (proxy);
|
|
g_return_if_fail (E_IS_ACTIVITY (activity));
|
|
|
|
state = e_activity_get_state (activity);
|
|
if (state != E_ACTIVITY_CANCELLED)
|
|
return;
|
|
|
|
if (proxy->priv->timeout_id > 0)
|
|
g_source_remove (proxy->priv->timeout_id);
|
|
|
|
/* Hold a reference on the EActivity for a short
|
|
* period so the activity proxy stays visible. */
|
|
proxy->priv->timeout_id = g_timeout_add_seconds_full (
|
|
G_PRIORITY_LOW, FEEDBACK_PERIOD, (GSourceFunc) gtk_false,
|
|
g_object_ref (activity), (GDestroyNotify) g_object_unref);
|
|
}
|
|
|
|
static void
|
|
activity_proxy_update (EActivityProxy *proxy)
|
|
{
|
|
EActivity *activity;
|
|
EActivityState state;
|
|
GCancellable *cancellable;
|
|
const gchar *icon_name;
|
|
gboolean sensitive;
|
|
gboolean visible;
|
|
gchar *description;
|
|
|
|
activity = e_activity_proxy_get_activity (proxy);
|
|
|
|
if (activity == NULL) {
|
|
gtk_widget_hide (GTK_WIDGET (proxy));
|
|
return;
|
|
}
|
|
|
|
cancellable = e_activity_get_cancellable (activity);
|
|
icon_name = e_activity_get_icon_name (activity);
|
|
state = e_activity_get_state (activity);
|
|
|
|
description = e_activity_describe (activity);
|
|
gtk_widget_set_tooltip_text (GTK_WIDGET (proxy), description);
|
|
gtk_label_set_text (GTK_LABEL (proxy->priv->label), description);
|
|
|
|
if (state == E_ACTIVITY_CANCELLED) {
|
|
PangoAttribute *attr;
|
|
PangoAttrList *attr_list;
|
|
|
|
attr_list = pango_attr_list_new ();
|
|
|
|
attr = pango_attr_strikethrough_new (TRUE);
|
|
pango_attr_list_insert (attr_list, attr);
|
|
|
|
gtk_label_set_attributes (
|
|
GTK_LABEL (proxy->priv->label), attr_list);
|
|
|
|
pango_attr_list_unref (attr_list);
|
|
} else
|
|
gtk_label_set_attributes (
|
|
GTK_LABEL (proxy->priv->label), NULL);
|
|
|
|
if (state == E_ACTIVITY_COMPLETED)
|
|
icon_name = COMPLETED_ICON_NAME;
|
|
|
|
if (state == E_ACTIVITY_CANCELLED) {
|
|
gtk_image_set_from_stock (
|
|
GTK_IMAGE (proxy->priv->image),
|
|
GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON);
|
|
gtk_widget_show (proxy->priv->image);
|
|
} else if (icon_name != NULL) {
|
|
gtk_image_set_from_icon_name (
|
|
GTK_IMAGE (proxy->priv->image),
|
|
icon_name, GTK_ICON_SIZE_MENU);
|
|
gtk_widget_show (proxy->priv->image);
|
|
} else {
|
|
gtk_widget_hide (proxy->priv->image);
|
|
}
|
|
|
|
visible = (cancellable != NULL);
|
|
gtk_widget_set_visible (proxy->priv->cancel, visible);
|
|
|
|
sensitive = (state == E_ACTIVITY_RUNNING);
|
|
gtk_widget_set_sensitive (proxy->priv->cancel, sensitive);
|
|
|
|
visible = (description != NULL && *description != '\0');
|
|
gtk_widget_set_visible (GTK_WIDGET (proxy), visible);
|
|
|
|
g_free (description);
|
|
}
|
|
|
|
static void
|
|
activity_proxy_cancel (EActivityProxy *proxy)
|
|
{
|
|
EActivity *activity;
|
|
GCancellable *cancellable;
|
|
|
|
activity = e_activity_proxy_get_activity (proxy);
|
|
g_return_if_fail (E_IS_ACTIVITY (activity));
|
|
|
|
cancellable = e_activity_get_cancellable (activity);
|
|
g_cancellable_cancel (cancellable);
|
|
|
|
activity_proxy_update (proxy);
|
|
}
|
|
|
|
static void
|
|
activity_proxy_weak_notify_cb (EActivityProxy *proxy,
|
|
GObject *where_the_object_was)
|
|
{
|
|
g_return_if_fail (E_IS_ACTIVITY_PROXY (proxy));
|
|
|
|
proxy->priv->activity = NULL;
|
|
e_activity_proxy_set_activity (proxy, NULL);
|
|
}
|
|
|
|
static void
|
|
activity_proxy_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
switch (property_id) {
|
|
case PROP_ACTIVITY:
|
|
e_activity_proxy_set_activity (
|
|
E_ACTIVITY_PROXY (object),
|
|
g_value_get_object (value));
|
|
return;
|
|
}
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
}
|
|
|
|
static void
|
|
activity_proxy_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
switch (property_id) {
|
|
case PROP_ACTIVITY:
|
|
g_value_set_object (
|
|
value, e_activity_proxy_get_activity (
|
|
E_ACTIVITY_PROXY (object)));
|
|
return;
|
|
}
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
}
|
|
|
|
static void
|
|
activity_proxy_dispose (GObject *object)
|
|
{
|
|
EActivityProxyPrivate *priv;
|
|
|
|
priv = E_ACTIVITY_PROXY_GET_PRIVATE (object);
|
|
|
|
if (priv->timeout_id > 0) {
|
|
g_source_remove (priv->timeout_id);
|
|
priv->timeout_id = 0;
|
|
}
|
|
|
|
if (priv->activity != NULL) {
|
|
g_signal_handlers_disconnect_matched (
|
|
priv->activity, G_SIGNAL_MATCH_DATA,
|
|
0, 0, NULL, NULL, object);
|
|
g_object_weak_unref (
|
|
G_OBJECT (priv->activity), (GWeakNotify)
|
|
activity_proxy_weak_notify_cb, object);
|
|
priv->activity = NULL;
|
|
}
|
|
|
|
/* Chain up to parent's dispose() method. */
|
|
G_OBJECT_CLASS (e_activity_proxy_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
e_activity_proxy_class_init (EActivityProxyClass *class)
|
|
{
|
|
GObjectClass *object_class;
|
|
|
|
g_type_class_add_private (class, sizeof (EActivityProxyPrivate));
|
|
|
|
object_class = G_OBJECT_CLASS (class);
|
|
object_class->set_property = activity_proxy_set_property;
|
|
object_class->get_property = activity_proxy_get_property;
|
|
object_class->dispose = activity_proxy_dispose;
|
|
|
|
g_object_class_install_property (
|
|
object_class,
|
|
PROP_ACTIVITY,
|
|
g_param_spec_object (
|
|
"activity",
|
|
NULL,
|
|
NULL,
|
|
E_TYPE_ACTIVITY,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT));
|
|
}
|
|
|
|
static void
|
|
e_activity_proxy_init (EActivityProxy *proxy)
|
|
{
|
|
GtkWidget *container;
|
|
GtkWidget *widget;
|
|
|
|
proxy->priv = E_ACTIVITY_PROXY_GET_PRIVATE (proxy);
|
|
|
|
gtk_frame_set_shadow_type (GTK_FRAME (proxy), GTK_SHADOW_IN);
|
|
|
|
container = GTK_WIDGET (proxy);
|
|
|
|
widget = gtk_hbox_new (FALSE, 3);
|
|
gtk_container_add (GTK_CONTAINER (container), widget);
|
|
gtk_widget_show (widget);
|
|
|
|
container = widget;
|
|
|
|
widget = gtk_image_new ();
|
|
gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
|
|
proxy->priv->image = widget;
|
|
|
|
widget = gtk_spinner_new ();
|
|
gtk_spinner_start (GTK_SPINNER (widget));
|
|
gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 3);
|
|
proxy->priv->spinner = widget;
|
|
|
|
/* The spinner is only visible when the image is not. */
|
|
g_object_bind_property (
|
|
proxy->priv->image, "visible",
|
|
proxy->priv->spinner, "visible",
|
|
G_BINDING_BIDIRECTIONAL |
|
|
G_BINDING_SYNC_CREATE |
|
|
G_BINDING_INVERT_BOOLEAN);
|
|
|
|
widget = gtk_label_new (NULL);
|
|
gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
|
|
gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
|
|
gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
|
|
proxy->priv->label = widget;
|
|
gtk_widget_show (widget);
|
|
|
|
/* This is only shown if the EActivity has a GCancellable. */
|
|
widget = gtk_button_new ();
|
|
gtk_button_set_image (
|
|
GTK_BUTTON (widget), gtk_image_new_from_stock (
|
|
GTK_STOCK_CANCEL, GTK_ICON_SIZE_MENU));
|
|
gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE);
|
|
gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
|
|
gtk_widget_set_tooltip_text (widget, _("Cancel"));
|
|
proxy->priv->cancel = widget;
|
|
gtk_widget_show (widget);
|
|
|
|
g_signal_connect_swapped (
|
|
widget, "clicked",
|
|
G_CALLBACK (activity_proxy_cancel), proxy);
|
|
}
|
|
|
|
GtkWidget *
|
|
e_activity_proxy_new (EActivity *activity)
|
|
{
|
|
g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
|
|
|
|
return g_object_new (
|
|
E_TYPE_ACTIVITY_PROXY, "activity", activity, NULL);
|
|
}
|
|
|
|
EActivity *
|
|
e_activity_proxy_get_activity (EActivityProxy *proxy)
|
|
{
|
|
g_return_val_if_fail (E_IS_ACTIVITY_PROXY (proxy), NULL);
|
|
|
|
return proxy->priv->activity;
|
|
}
|
|
|
|
void
|
|
e_activity_proxy_set_activity (EActivityProxy *proxy,
|
|
EActivity *activity)
|
|
{
|
|
g_return_if_fail (E_IS_ACTIVITY_PROXY (proxy));
|
|
|
|
if (activity != NULL)
|
|
g_return_if_fail (E_IS_ACTIVITY (activity));
|
|
|
|
if (proxy->priv->timeout_id > 0) {
|
|
g_source_remove (proxy->priv->timeout_id);
|
|
proxy->priv->timeout_id = 0;
|
|
}
|
|
|
|
if (proxy->priv->activity != NULL) {
|
|
g_signal_handlers_disconnect_matched (
|
|
proxy->priv->activity, G_SIGNAL_MATCH_DATA,
|
|
0, 0, NULL, NULL, proxy);
|
|
g_object_weak_unref (
|
|
G_OBJECT (proxy->priv->activity),
|
|
(GWeakNotify) activity_proxy_weak_notify_cb, proxy);
|
|
}
|
|
|
|
proxy->priv->activity = activity;
|
|
|
|
if (activity != NULL) {
|
|
g_object_weak_ref (
|
|
G_OBJECT (activity), (GWeakNotify)
|
|
activity_proxy_weak_notify_cb, proxy);
|
|
|
|
g_signal_connect_swapped (
|
|
activity, "notify::state",
|
|
G_CALLBACK (activity_proxy_feedback), proxy);
|
|
|
|
g_signal_connect_swapped (
|
|
activity, "notify",
|
|
G_CALLBACK (activity_proxy_update), proxy);
|
|
}
|
|
|
|
activity_proxy_update (proxy);
|
|
|
|
g_object_notify (G_OBJECT (proxy), "activity");
|
|
}
|