* add functions for easily getting various combo boxes
[modest] / src / modest-widget-factory.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "modest-widget-factory.h"
31 #include <tny-account-store-iface.h>
32 #include <tny-device-iface.h>
33
34 /* 'private'/'protected' functions */
35 static void modest_widget_factory_class_init    (ModestWidgetFactoryClass *klass);
36 static void modest_widget_factory_init          (ModestWidgetFactory *obj);
37 static void modest_widget_factory_finalize      (GObject *obj);
38
39
40 /* callbacks */
41 static void on_folder_selected         (ModestFolderView *folder_view,
42                                         TnyMsgFolderIface *folder,
43                                         ModestWidgetFactory *self);
44 static void on_message_selected        (ModestHeaderView *header_view, TnyMsgIface *msg,
45                                         ModestWidgetFactory *self);
46 static void on_header_status_update    (ModestHeaderView *header_view, const gchar *msg,
47                                         gint status_id, ModestWidgetFactory *self);
48 static void on_msg_link_hover          (ModestMsgView *msgview, const gchar* link,
49                                         ModestWidgetFactory *self);
50 static void on_msg_link_clicked        (ModestMsgView *msgview, const gchar* link,
51                                         ModestWidgetFactory *self);
52 static void on_msg_attachment_clicked  (ModestMsgView *msgview, int index,
53                                         ModestWidgetFactory *self);
54
55 static void on_connection_changed (TnyDeviceIface *device, gboolean online,
56                                    ModestWidgetFactory *self);
57 static void on_online_toggle_toggled (GtkToggleButton *toggle, ModestWidgetFactory *factory);
58
59
60 /* list my signals */
61 enum {
62         /* MY_SIGNAL_1, */
63         /* MY_SIGNAL_2, */
64         LAST_SIGNAL
65 };
66
67
68 enum _StatusID {
69         STATUS_ID_HEADER,
70         STATUS_ID_FOLDER,
71         STATUS_ID_MESSAGE,
72
73         STATUS_ID_NUM
74 };
75 typedef enum _StatusID StatusID;
76
77 typedef struct _ModestWidgetFactoryPrivate ModestWidgetFactoryPrivate;
78 struct _ModestWidgetFactoryPrivate {
79         
80         ModestTnyAccountStore *account_store;
81         ModestAccountMgr      *account_mgr;
82         ModestConf            *conf;
83         
84         ModestHeaderView      *header_view;
85         ModestFolderView      *folder_view;
86         ModestMsgView         *msg_preview;
87
88         GtkWidget             *progress_bar;
89         GtkWidget             *status_bar;
90
91         GtkWidget             *online_toggle;
92         StatusID              status_bar_ctx[STATUS_ID_NUM];
93         
94 };
95 #define MODEST_WIDGET_FACTORY_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
96                                                    MODEST_TYPE_WIDGET_FACTORY, \
97                                                    ModestWidgetFactoryPrivate))
98 /* globals */
99 static GObjectClass *parent_class = NULL;
100
101 /* uncomment the following if you have defined any signals */
102 /* static guint signals[LAST_SIGNAL] = {0}; */
103
104 GType
105 modest_widget_factory_get_type (void)
106 {
107         static GType my_type = 0;
108         if (!my_type) {
109                 static const GTypeInfo my_info = {
110                         sizeof(ModestWidgetFactoryClass),
111                         NULL,           /* base init */
112                         NULL,           /* base finalize */
113                         (GClassInitFunc) modest_widget_factory_class_init,
114                         NULL,           /* class finalize */
115                         NULL,           /* class data */
116                         sizeof(ModestWidgetFactory),
117                         1,              /* n_preallocs */
118                         (GInstanceInitFunc) modest_widget_factory_init,
119                 };
120                 my_type = g_type_register_static (G_TYPE_OBJECT,
121                                                   "ModestWidgetFactory",
122                                                   &my_info, 0);
123         }
124         return my_type;
125 }
126
127 static void
128 modest_widget_factory_class_init (ModestWidgetFactoryClass *klass)
129 {
130         GObjectClass *gobject_class;
131         gobject_class = (GObjectClass*) klass;
132
133         parent_class            = g_type_class_peek_parent (klass);
134         gobject_class->finalize = modest_widget_factory_finalize;
135
136         g_type_class_add_private (gobject_class, sizeof(ModestWidgetFactoryPrivate));
137 }
138
139 static void
140 modest_widget_factory_init (ModestWidgetFactory *obj)
141 {
142         ModestWidgetFactoryPrivate *priv;
143         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(obj);
144
145         priv->conf          = NULL;
146         priv->account_mgr   = NULL;
147         priv->account_store = NULL;
148         
149         priv->progress_bar = gtk_progress_bar_new ();
150         gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(priv->progress_bar),
151                                        1.0);
152         priv->status_bar   = gtk_statusbar_new ();
153         gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR(priv->status_bar),
154                                            FALSE);
155         
156         priv->status_bar_ctx[STATUS_ID_HEADER] =
157                 gtk_statusbar_get_context_id (GTK_STATUSBAR(priv->status_bar),
158                                               "header");
159         priv->status_bar_ctx[STATUS_ID_MESSAGE] =
160                 gtk_statusbar_get_context_id (GTK_STATUSBAR(priv->status_bar),
161                                               "message");       
162         priv->status_bar_ctx[STATUS_ID_FOLDER] =
163                 gtk_statusbar_get_context_id (GTK_STATUSBAR(priv->status_bar),
164                                               "folder");
165 }
166
167 static void
168 modest_widget_factory_finalize (GObject *obj)
169 {
170         ModestWidgetFactoryPrivate *priv;
171         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(obj);
172
173         if (priv->account_mgr) {
174                 g_object_unref (G_OBJECT(priv->account_mgr));
175                 priv->account_mgr = NULL;
176         }
177
178         if (priv->conf) {
179                 g_object_unref (G_OBJECT(priv->conf));
180                 priv->conf = NULL;
181         }
182
183         if (priv->account_store) {
184                 g_object_unref (G_OBJECT(priv->account_store));
185                 priv->account_store = NULL;
186         }
187 }
188
189
190
191 static void
192 init_signals (ModestWidgetFactory *self)
193 {
194         
195         TnyDeviceIface *device;
196         ModestWidgetFactoryPrivate *priv;
197         
198         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
199
200         g_signal_connect (G_OBJECT(priv->header_view), "message_selected",
201                           G_CALLBACK(on_message_selected), self);
202         g_signal_connect (G_OBJECT(priv->folder_view), "folder_selected",
203                           G_CALLBACK(on_folder_selected), self);
204         g_signal_connect (G_OBJECT(priv->header_view), "status_update",
205                           G_CALLBACK(on_header_status_update), self);
206         g_signal_connect (G_OBJECT(priv->msg_preview), "link_clicked",
207                           G_CALLBACK(on_msg_link_clicked), self);
208         g_signal_connect (G_OBJECT(priv->msg_preview), "link_hover",
209                           G_CALLBACK(on_msg_link_hover), self);
210         g_signal_connect (G_OBJECT(priv->msg_preview), "attachment_clicked",
211                           G_CALLBACK(on_msg_attachment_clicked), self);
212         
213         /* FIXME: const casting is evil ==> tinymail */
214         device = (TnyDeviceIface*)tny_account_store_iface_get_device
215                 (TNY_ACCOUNT_STORE_IFACE(priv->account_store));
216         if (device) {
217                 g_signal_connect (G_OBJECT(device), "connection_changed",
218                                   G_CALLBACK(on_connection_changed), self);
219                 g_signal_connect (G_OBJECT(priv->online_toggle), "toggled",
220                                   G_CALLBACK(on_online_toggle_toggled), self);
221                 
222                 /* init toggle in correct state */
223                 on_connection_changed (device,
224                                        tny_device_iface_is_online (device),
225                                        self);
226         }
227 }
228
229 static gboolean
230 init_widgets (ModestWidgetFactory *self)
231 {
232         ModestWidgetFactoryPrivate *priv;
233         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
234
235         /* folder view */
236         if (!(priv->folder_view =
237               MODEST_FOLDER_VIEW(modest_folder_view_new
238                                  (TNY_ACCOUNT_STORE_IFACE(priv->account_store))))) {
239                 g_printerr ("modest: cannot instantiate folder view\n");
240                 return FALSE;
241         }
242
243         /* header view */
244         if (!(priv->header_view =
245               MODEST_HEADER_VIEW(modest_header_view_new
246                                  (NULL, NULL,MODEST_HEADER_VIEW_STYLE_NORMAL)))) {
247                 g_printerr ("modest: cannot instantiate header view\n");
248                 return FALSE;
249         }
250         
251         
252         /* msg preview */
253         if (!(priv->msg_preview = MODEST_MSG_VIEW(modest_msg_view_new (NULL)))) {
254                 g_printerr ("modest: cannot instantiate header view\n");
255                 return FALSE;
256         }
257
258
259         /* online/offline combo */
260         priv->online_toggle = gtk_toggle_button_new ();
261         
262         init_signals (self);
263         
264         return TRUE;
265 }
266
267
268 ModestWidgetFactory*
269 modest_widget_factory_new (ModestConf *conf,
270                            ModestTnyAccountStore *account_store,
271                            ModestAccountMgr *account_mgr)
272 {
273         GObject *obj;
274         ModestWidgetFactoryPrivate *priv;
275
276         g_return_val_if_fail (account_store, NULL);
277         g_return_val_if_fail (account_mgr, NULL);
278         g_return_val_if_fail (conf, NULL);
279         
280         obj  = g_object_new(MODEST_TYPE_WIDGET_FACTORY, NULL);  
281         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(obj);
282
283         g_object_ref (G_OBJECT(conf));
284         priv->conf = conf;
285         
286         g_object_ref (G_OBJECT(account_mgr));
287         priv->account_mgr = account_mgr;
288         
289         g_object_ref (G_OBJECT(account_store));
290         priv->account_store = account_store;
291
292         if (!init_widgets (MODEST_WIDGET_FACTORY(obj))) {
293                 g_printerr ("modest: widget factory failed to init widgets\n");
294                 g_object_unref (obj);
295                 return NULL;
296         }
297         
298         return MODEST_WIDGET_FACTORY(obj);
299 }
300
301
302
303
304 ModestFolderView*
305 modest_widget_factory_get_folder_view (ModestWidgetFactory *self)
306 {
307         g_return_val_if_fail (self, NULL);
308         return MODEST_WIDGET_FACTORY_GET_PRIVATE(self)->folder_view;
309 }
310
311
312 ModestHeaderView*
313 modest_widget_factory_get_header_view (ModestWidgetFactory *self)
314 {
315         g_return_val_if_fail (self, NULL);
316         return MODEST_WIDGET_FACTORY_GET_PRIVATE(self)->header_view;
317 }
318
319
320 ModestMsgView*
321 modest_widget_factory_get_msg_preview (ModestWidgetFactory *self)
322 {
323         g_return_val_if_fail (self, NULL);
324         return MODEST_WIDGET_FACTORY_GET_PRIVATE(self)->msg_preview;
325 }
326
327
328 ModestAccountView*
329 modest_widget_factory_get_account_view (ModestWidgetFactory *self)
330 {
331         ModestWidgetFactoryPrivate *priv;
332         
333         g_return_val_if_fail (self, NULL);
334         priv =  MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
335         
336         return modest_account_view_new (priv->account_mgr);
337 }
338
339
340
341 GtkWidget*
342 modest_widget_factory_get_progress_bar (ModestWidgetFactory *self)
343 {
344         g_return_val_if_fail (self, NULL);
345         return MODEST_WIDGET_FACTORY_GET_PRIVATE(self)->progress_bar;
346 }
347
348
349 GtkWidget*
350 modest_widget_factory_get_status_bar (ModestWidgetFactory *self)
351 {
352         g_return_val_if_fail (self, NULL);
353         return MODEST_WIDGET_FACTORY_GET_PRIVATE(self)->status_bar;
354 }
355
356
357 GtkWidget*
358 modest_widget_factory_get_combo_box (ModestWidgetFactory *self, ModestComboBoxType type)
359 {
360         GtkWidget *combo_box;
361         GtkListStore *model;
362         GtkTreeIter iter;
363         const gchar **protos, **cursor; 
364
365         g_return_val_if_fail (self, NULL);
366
367         combo_box = gtk_combo_box_new_text ();
368         
369         switch (type) {
370         case MODEST_COMBO_BOX_TYPE_STORE_PROTOS:
371                 cursor = protos = modest_proto_store_protos ();
372                 break;
373         case MODEST_COMBO_BOX_TYPE_TRANSPORT_PROTOS:
374                 cursor = protos = modest_proto_transport_protos ();
375                 break;
376         case MODEST_COMBO_BOX_TYPE_SECURITY_PROTOS:
377                 cursor = protos = modest_proto_security_protos ();
378                 break;
379         case MODEST_COMBO_BOX_TYPE_AUTH_PROTOS:
380                 cursor = protos = modest_proto_auth_protos ();
381                 break;
382         default:
383                 g_assert_not_reached ();
384         }
385         while (cursor && *cursor) {
386                 gtk_combo_box_append_text (GTK_COMBO_BOX(combo_box),
387                                            (const gchar*)*cursor);
388                 ++cursor;
389         }
390         gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box), 0);
391         
392         return combo_box;
393 }
394
395
396
397
398 GtkWidget*
399 modest_widget_factory_get_online_toggle (ModestWidgetFactory *self)
400 {
401         g_return_val_if_fail (self, NULL);
402         return MODEST_WIDGET_FACTORY_GET_PRIVATE(self)->online_toggle;
403 }
404
405
406
407 static void
408 on_folder_selected (ModestFolderView *folder_view, TnyMsgFolderIface *folder,
409                     ModestWidgetFactory *self)
410 {
411         ModestWidgetFactoryPrivate *priv;
412         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
413         
414         modest_header_view_set_folder (priv->header_view, folder);
415 }
416
417
418 static void
419 on_message_selected (ModestHeaderView *folder_view, TnyMsgIface *msg,
420                      ModestWidgetFactory *self)
421 {       
422         ModestWidgetFactoryPrivate *priv;
423         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
424         
425         modest_msg_view_set_message (priv->msg_preview, msg);
426 }
427
428
429 static void
430 on_header_status_update (ModestHeaderView *header_view, const gchar *msg,
431                          gint status_id, ModestWidgetFactory *self)
432 {
433         ModestWidgetFactoryPrivate *priv;
434         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
435         
436         if (msg && status_id) {
437                 gchar *msg = g_strdup_printf ("%s", msg);
438                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(priv->progress_bar));
439                 gtk_statusbar_push (GTK_STATUSBAR(priv->status_bar),
440                                        priv->status_bar_ctx[STATUS_ID_HEADER],
441                                        msg);
442                 g_free (msg);
443         } else {
444                 gtk_statusbar_pop (GTK_STATUSBAR(priv->status_bar),
445                                    priv->status_bar_ctx[STATUS_ID_HEADER]);
446                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(priv->progress_bar),
447                                                1.0);
448         }
449 }
450
451
452 static void
453 on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
454                    ModestWidgetFactory *self)
455 {
456         ModestWidgetFactoryPrivate *priv;
457         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
458
459         if (link)
460                 gtk_statusbar_push (GTK_STATUSBAR(priv->status_bar),
461                                     priv->status_bar_ctx[STATUS_ID_MESSAGE],
462                                     link);
463         else
464                 gtk_statusbar_pop (GTK_STATUSBAR(priv->status_bar),
465                                    priv->status_bar_ctx[STATUS_ID_MESSAGE]);
466
467 }       
468
469
470 static void
471 on_msg_link_clicked  (ModestMsgView *msgview, const gchar* link,
472                       ModestWidgetFactory *self)
473 {
474         ModestWidgetFactoryPrivate *priv;
475         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
476
477         if (link) {
478                 gchar *msg = g_strdup_printf (_("Opening %s..."), link);
479                 gtk_statusbar_push (GTK_STATUSBAR(priv->status_bar),
480                                     priv->status_bar_ctx[STATUS_ID_MESSAGE],
481                                     msg);
482                 g_free (msg);
483         }       
484 }
485
486 static void
487 on_msg_attachment_clicked  (ModestMsgView *msgview, int index,
488                             ModestWidgetFactory *self)
489 {
490         ModestWidgetFactoryPrivate *priv;
491         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
492         
493         gchar *msg = g_strdup_printf (_("Opening attachment %d..."), index);
494         gtk_statusbar_push (GTK_STATUSBAR(priv->status_bar),
495                             priv->status_bar_ctx[STATUS_ID_MESSAGE],
496                             msg);
497         g_free (msg);
498 }
499
500
501 static void
502 on_connection_changed (TnyDeviceIface *device, gboolean online,
503                        ModestWidgetFactory *self)
504 {
505         gint item;
506         ModestWidgetFactoryPrivate *priv;
507
508         priv = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
509
510         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(priv->online_toggle),
511                                       online);
512         gtk_button_set_label (GTK_BUTTON(priv->online_toggle),
513                               online ? _("Online") : _("Offline"));
514 }
515
516
517 static void
518 on_online_toggle_toggled (GtkToggleButton *toggle, ModestWidgetFactory *self)
519 {
520         gboolean online;
521         const TnyDeviceIface *device;
522         ModestWidgetFactoryPrivate *priv;
523         
524         priv    = MODEST_WIDGET_FACTORY_GET_PRIVATE(self);
525         online  = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(priv->online_toggle));
526         device  = tny_account_store_iface_get_device
527                 (TNY_ACCOUNT_STORE_IFACE(priv->account_store)); 
528
529         /* FIXME: const casting should not be necessary ==> tinymail */
530         if (online)  /* we're moving to online state */
531                 tny_device_iface_force_online ((TnyDeviceIface*)device);
532         else  /* we're moving to offline state */
533                 tny_device_iface_force_offline ((TnyDeviceIface*)device);
534 }