bb162822ba4a920764ea2f388a62aa30bd4ed3df
[modest] / src / gnome / modest-gnome-info-bar.c
1 /* modest-gnome-bar.c */
2
3 /* insert (c)/licensing information) */
4
5 #include "modest-gnome-info-bar.h"
6 #include <gtk/gtkprogressbar.h>
7 #include <gtk/gtkstatusbar.h>
8 /* include other impl specific header files */
9
10 /* 'private'/'protected' functions */
11 static void modest_gnome_info_bar_class_init (ModestGnomeInfoBarClass *klass);
12 static void modest_gnome_info_bar_init       (ModestGnomeInfoBar *obj);
13 static void modest_gnome_info_bar_finalize   (GObject *obj);
14
15 static void modest_gnome_info_bar_add_operation    (ModestProgressObject *self,
16                                                     ModestMailOperation  *mail_op);
17
18 static void modest_gnome_info_bar_remove_operation (ModestProgressObject *self,
19                                                     ModestMailOperation  *mail_op);
20
21 static void on_progress_changed                    (ModestMailOperation  *mail_op, 
22                                                     ModestGnomeInfoBar *self);
23
24 static gboolean     progressbar_clean        (GtkProgressBar *bar);
25 static gboolean     statusbar_clean          (GtkStatusbar *bar);
26
27 /* list my signals  */
28 enum {
29         /* MY_SIGNAL_1, */
30         /* MY_SIGNAL_2, */
31         LAST_SIGNAL
32 };
33
34 typedef struct _ObservableData ObservableData;
35 struct _ObservableData {
36         guint signal_handler;
37         ModestMailOperation *mail_op;
38 };
39
40 typedef struct _ModestGnomeInfoBarPrivate ModestGnomeInfoBarPrivate;
41 struct _ModestGnomeInfoBarPrivate {
42         GSList              *observables;
43         ModestMailOperation *current;
44
45         GtkWidget *status_bar;
46         GtkWidget *progress_bar;
47
48         guint status_bar_timeout;
49         guint progress_bar_timeout;
50 };
51
52 #define MODEST_GNOME_INFO_BAR_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
53                                               MODEST_TYPE_GNOME_INFO_BAR, \
54                                               ModestGnomeInfoBarPrivate))
55 /* globals */
56 static GtkHBoxClass *parent_class = NULL;
57
58 /* uncomment the following if you have defined any signals */
59 /* static guint signals[LAST_SIGNAL] = {0}; */
60
61 static void
62 modest_progress_object_init (gpointer g, gpointer iface_data)
63 {
64         ModestProgressObjectIface *klass = (ModestProgressObjectIface *)g;
65
66         klass->add_operation_func = modest_gnome_info_bar_add_operation;
67         klass->remove_operation_func = modest_gnome_info_bar_remove_operation;
68 }
69
70 GType
71 modest_gnome_info_bar_get_type (void)
72 {
73         static GType my_type = 0;
74         if (!my_type) {
75                 static const GTypeInfo my_info = {
76                         sizeof(ModestGnomeInfoBarClass),
77                         NULL,           /* base init */
78                         NULL,           /* base finalize */
79                         (GClassInitFunc) modest_gnome_info_bar_class_init,
80                         NULL,           /* class finalize */
81                         NULL,           /* class data */
82                         sizeof(ModestGnomeInfoBar),
83                         1,              /* n_preallocs */
84                         (GInstanceInitFunc) modest_gnome_info_bar_init,
85                         NULL
86                 };
87
88                 static const GInterfaceInfo modest_progress_object_info = 
89                 {
90                   (GInterfaceInitFunc) modest_progress_object_init, /* interface_init */
91                   NULL,         /* interface_finalize */
92                   NULL          /* interface_data */
93                 };
94
95                 my_type = g_type_register_static (GTK_TYPE_HBOX,
96                                                   "ModestGnomeInfoBar",
97                                                   &my_info, 0);
98
99                 g_type_add_interface_static (my_type, MODEST_TYPE_PROGRESS_OBJECT, 
100                                              &modest_progress_object_info);
101         }
102         return my_type;
103 }
104
105 static void
106 modest_gnome_info_bar_class_init (ModestGnomeInfoBarClass *klass)
107 {
108         GObjectClass *gobject_class;
109         gobject_class = (GObjectClass*) klass;
110
111         parent_class            = g_type_class_peek_parent (klass);
112         gobject_class->finalize = modest_gnome_info_bar_finalize;
113
114         g_type_class_add_private (gobject_class, sizeof(ModestGnomeInfoBarPrivate));
115 }
116
117 static void
118 modest_gnome_info_bar_init (ModestGnomeInfoBar *obj)
119 {
120         ModestGnomeInfoBarPrivate *priv = MODEST_GNOME_INFO_BAR_GET_PRIVATE(obj);
121
122         priv->observables = NULL;
123         priv->current = NULL;
124
125         /* Status bar */
126         priv->status_bar = gtk_statusbar_new ();
127         gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (priv->status_bar), FALSE);
128
129         /* Progress bar */
130         priv->progress_bar = gtk_progress_bar_new ();
131         gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progress_bar), 1.0);
132         gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR (priv->progress_bar),
133                                         PANGO_ELLIPSIZE_END);
134
135         /* Timeouts */
136         priv->status_bar_timeout = 0;
137         priv->progress_bar_timeout = 0;
138
139         /* Pack */
140         gtk_box_pack_start (GTK_BOX (obj), priv->status_bar, TRUE, TRUE, 0);
141         gtk_box_pack_start (GTK_BOX (obj), priv->progress_bar, FALSE, FALSE, 0);
142 }
143
144 static void
145 destroy_observable_data (ObservableData *data)
146 {
147         g_signal_handler_disconnect (data->mail_op, data->signal_handler);
148         g_object_unref (data->mail_op);
149 }
150
151 static void
152 modest_gnome_info_bar_finalize (GObject *obj)
153 {
154         ModestGnomeInfoBarPrivate *priv;
155
156         priv = MODEST_GNOME_INFO_BAR_GET_PRIVATE(obj);
157         if (priv->observables) {
158                 GSList *tmp;
159
160                 for (tmp = priv->observables; tmp; tmp = g_slist_next (tmp)) {
161                         destroy_observable_data ((ObservableData *) tmp->data);
162                         g_free (tmp->data);
163                 }
164                 g_slist_free (priv->observables);
165                 priv->observables = NULL;
166         }
167
168         if (priv->status_bar_timeout > 0) {
169                 g_source_remove (priv->status_bar_timeout);
170                 priv->status_bar_timeout = 0;
171         }
172
173         if (priv->progress_bar_timeout > 0) {
174                 g_source_remove (priv->progress_bar_timeout);
175                 priv->progress_bar_timeout = 0;
176         }
177
178         G_OBJECT_CLASS(parent_class)->finalize (obj);
179 }
180
181 GtkWidget *
182 modest_gnome_info_bar_new (void)
183 {
184         return GTK_WIDGET (g_object_new (MODEST_TYPE_GNOME_INFO_BAR, NULL));
185 }
186
187 static void 
188 modest_gnome_info_bar_add_operation (ModestProgressObject *self,
189                                      ModestMailOperation  *mail_op)
190 {
191         ModestGnomeInfoBar *me;
192         ObservableData *data;
193         ModestGnomeInfoBarPrivate *priv;
194
195         me = MODEST_GNOME_INFO_BAR (self);
196         priv = MODEST_GNOME_INFO_BAR_GET_PRIVATE (me);
197
198         data = g_malloc0 (sizeof (ObservableData));
199         data->mail_op = g_object_ref (mail_op);
200         data->signal_handler = g_signal_connect (data->mail_op, 
201                                                  "progress-changed",
202                                                  G_CALLBACK (on_progress_changed),
203                                                  me);
204
205         if (priv->observables == NULL) {
206                 priv->current = mail_op;
207         }
208         priv->observables = g_slist_append (priv->observables, data);
209 }
210
211 static gint
212 compare_observable_data (ObservableData *data1, ObservableData *data2)
213 {
214         if (data1->mail_op == data2->mail_op)
215                 return 0;
216         else 
217                 return 1;
218 }
219
220 static void 
221 modest_gnome_info_bar_remove_operation (ModestProgressObject *self,
222                                         ModestMailOperation  *mail_op)
223 {
224         ModestGnomeInfoBar *me;
225         ModestGnomeInfoBarPrivate *priv;
226         GSList *link;
227
228         me = MODEST_GNOME_INFO_BAR (self);
229         priv = MODEST_GNOME_INFO_BAR_GET_PRIVATE (me);
230
231         link = g_slist_find_custom (priv->observables,
232                                     mail_op,
233                                     (GCompareFunc) compare_observable_data);
234
235         /* Remove the item */
236         if (link) {
237                 priv->observables = g_slist_remove_link (priv->observables, link);
238                 destroy_observable_data ((ObservableData *) link->data);
239         }
240
241         /* Update the current mail operation */
242         if (priv->current == mail_op) {
243                 if (priv->observables)
244                         priv->current = ((ObservableData *) priv->observables->data)->mail_op;
245                 else
246                         priv->current = NULL;
247
248                 /* Refresh the view */
249                 progressbar_clean (GTK_PROGRESS_BAR (priv->progress_bar));
250         }
251 }
252
253 static void 
254 on_progress_changed (ModestMailOperation  *mail_op, 
255                      ModestGnomeInfoBar *self)
256 {
257         ModestGnomeInfoBarPrivate *priv;
258
259         priv = MODEST_GNOME_INFO_BAR_GET_PRIVATE (self);
260
261         /* If the mail operation is the currently shown one */
262         if (priv->current == mail_op) {
263                 gchar *msg = NULL;
264
265                 msg = g_strdup_printf ("Mail operation %d of %d",
266                                        modest_mail_operation_get_task_done (mail_op),
267                                        modest_mail_operation_get_task_total (mail_op));
268                 modest_gnome_info_bar_set_message (self, msg);
269                 g_free (msg);
270         }
271 }
272
273 static gboolean
274 progressbar_clean (GtkProgressBar *bar)
275 {
276         gtk_progress_bar_set_fraction (bar, 0);
277         gtk_progress_bar_set_text (bar, 0);
278         return FALSE;
279 }
280
281 static gboolean
282 statusbar_clean (GtkStatusbar *bar)
283 {
284         gtk_statusbar_push (bar, 0, "");
285         return FALSE;
286 }
287
288 void 
289 modest_gnome_info_bar_set_message    (ModestGnomeInfoBar *self,
290                                       const gchar *message)
291 {
292         ModestGnomeInfoBarPrivate *priv;
293
294         priv = MODEST_GNOME_INFO_BAR_GET_PRIVATE (self);
295
296         /* Set a message. Clean it after 2.5 seconds */
297         gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar), 0, message);
298         priv->status_bar_timeout = g_timeout_add (2500, 
299                                                   (GSourceFunc) statusbar_clean, 
300                                                   priv->status_bar);
301 }
302
303 void 
304 modest_gnome_info_bar_set_progress   (ModestGnomeInfoBar *self,
305                                       const gchar *message,
306                                       gint done,
307                                       gint total)
308 {
309         ModestGnomeInfoBarPrivate *priv;
310
311         priv = MODEST_GNOME_INFO_BAR_GET_PRIVATE (self);
312
313         /* Set progress */
314         if (total != 0)
315                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progress_bar),
316                                                (gdouble)done/(gdouble)total);
317         else
318                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (priv->progress_bar));
319
320         /* Set text */
321         gtk_progress_bar_set_text (GTK_PROGRESS_BAR (priv->progress_bar), message);
322 }