Modified the signature of the connection changed handler
[modest] / src / modest-ui.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 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif /*HAVE_CONFIG_H*/
33
34 #include <glib/gi18n.h>
35 #include <string.h>
36 #include <modest-runtime.h>
37 #include "modest-ui-priv.h"
38 #include "modest-ui.h"
39 #include "modest-ui-actions.h"
40 #include "modest-icon-names.h"
41 #include "modest-tny-platform-factory.h"
42 #include "modest-account-view-window.h"
43 #include "modest-account-mgr-helpers.h"
44 #include "modest-main-window.h"
45 #include "modest-mail-operation.h"
46 #include <modest-widget-memory.h>
47 #include <tny-error.h>
48 #include <tny-simple-list.h>
49 #include <tny-msg-view.h>
50 #include <tny-device.h>
51
52 #define MODEST_UI_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
53                                        MODEST_TYPE_UI, \
54                                        ModestUIPrivate))
55
56 typedef struct _GetMsgAsyncHelper {
57         ModestMainWindow *main_window;
58         TnyIterator *iter;
59         GFunc func;
60         gpointer user_data;
61 } GetMsgAsyncHelper;
62
63 typedef enum _ReplyForwardAction {
64         ACTION_REPLY,
65         ACTION_REPLY_TO_ALL,
66         ACTION_FORWARD
67 } ReplyForwardAction;
68
69 typedef struct _ReplyForwardHelper {
70         guint reply_forward_type;
71         ReplyForwardAction action;
72         gchar *from;
73 } ReplyForwardHelper;
74
75 /* globals */
76 static GObjectClass *parent_class = NULL;
77
78 /* 'private'/'protected' functions */
79 static void     modest_ui_class_init   (ModestUIClass *klass);
80 static void     modest_ui_init         (ModestUI *obj);
81 static void     modest_ui_finalize     (GObject *obj);
82
83 static void     register_stock_icons   ();
84 static void     connect_signals        (ModestUI *self);
85
86 static void     reply_forward_func     (gpointer data, 
87                                         gpointer user_data);
88 static void     read_msg_func          (gpointer data, 
89                                         gpointer user_data);
90 static void     get_msg_cb             (TnyFolder *folder, 
91                                         TnyMsg *msg, 
92                                         GError **err, 
93                                         gpointer user_data);
94
95 static void     reply_forward          (GtkWidget *widget,
96                                         ReplyForwardAction action,
97                                         ModestMainWindow *main_window);
98
99 static gchar*   ask_for_folder_name    (GtkWindow *parent_window,
100                                         const gchar *title);
101
102 static void     _modest_ui_actions_on_connection_changed    (TnyDevice *device,
103                                                              gboolean online,
104                                                              ModestUI *modest_ui);
105
106
107 static void     _modest_ui_actions_on_accounts_reloaded     (TnyAccountStore *store, 
108                                                              gpointer user_data);
109
110 GType
111 modest_ui_get_type (void)
112 {
113         static GType my_type = 0;
114         if (!my_type) {
115                 static const GTypeInfo my_info = {
116                         sizeof(ModestUIClass),
117                         NULL,           /* base init */
118                         NULL,           /* base finalize */
119                         (GClassInitFunc) modest_ui_class_init,
120                         NULL,           /* class finalize */
121                         NULL,           /* class data */
122                         sizeof(ModestUI),
123                         1,              /* n_preallocs */
124                         (GInstanceInitFunc) modest_ui_init,
125                         NULL
126                 };
127                 my_type = g_type_register_static (G_TYPE_OBJECT,
128                                                   "ModestUI",
129                                                   &my_info, 0);
130         }
131         return my_type;
132 }
133
134
135 static void
136 modest_ui_class_init (ModestUIClass *klass)
137 {
138         GObjectClass *gobject_class;
139         gobject_class = (GObjectClass*) klass;
140
141         parent_class            = g_type_class_peek_parent (klass);
142         gobject_class->finalize = modest_ui_finalize;
143
144         g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
145
146 }
147
148
149 static void
150 modest_ui_init (ModestUI *obj)
151 {
152         ModestUIPrivate *priv;
153
154         priv = MODEST_UI_GET_PRIVATE(obj);
155
156         priv->main_window    = NULL;
157 }
158
159
160 static void
161 modest_ui_finalize (GObject *obj)
162 {
163         ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
164         
165         if (priv->ui_manager) {
166                 g_object_unref (G_OBJECT(priv->ui_manager));
167                 priv->ui_manager = NULL;
168         }
169
170         priv->main_window = NULL;
171
172         G_OBJECT_CLASS(parent_class)->finalize (obj);
173 }
174
175
176 ModestUI*
177 modest_ui_new (void)
178 {
179         GObject *obj;
180         ModestUIPrivate *priv;
181
182         obj  = g_object_new(MODEST_TYPE_UI, NULL);
183         priv = MODEST_UI_GET_PRIVATE(obj);
184         
185         /* Register our own icons as stock icons in order to
186            use them with the UI manager */
187         register_stock_icons ();
188                 
189         return MODEST_UI(obj);
190 }
191
192 static gboolean
193 on_main_window_destroy (GtkObject *widget, ModestUI *self)
194 {
195         /* FIXME: check if there any viewer/editing windows opened */
196         gtk_main_quit ();
197         return FALSE;
198 }
199
200
201 ModestWindow *
202 modest_ui_main_window (ModestUI *self)
203 {
204         ModestUIPrivate *priv;
205
206         g_return_val_if_fail (self, NULL);
207         priv = MODEST_UI_GET_PRIVATE(self);
208
209         if (!priv->main_window) {
210                 priv->main_window = modest_main_window_new ();
211                 connect_signals (self);
212         }
213                 
214         if (!priv->main_window)
215                 g_printerr ("modest: could not create main window\n");
216         
217         return priv->main_window;
218 }
219
220 ModestWindow *
221 modest_ui_edit_window (ModestUI *self, ModestEditType edit_type)
222 {
223         ModestUIPrivate *priv;
224         ModestWindow *edit_window;
225
226         g_return_val_if_fail (self, NULL);
227         priv = MODEST_UI_GET_PRIVATE(self);
228
229         /* Create window */
230         edit_window = modest_edit_msg_window_new (edit_type);
231         
232         /* Connect Edit Window signals */
233 /*      connect_edit_window_signals (self); */
234                 
235         return edit_window;
236 }
237
238 /* 
239  *  This function registers our custom toolbar icons, so they can be
240  *  themed. The idea of this function was taken from the gtk-demo
241  */
242 static void
243 register_stock_icons ()
244 {
245         static gboolean registered = FALSE;
246   
247         if (!registered) {
248                 GdkPixbuf *pixbuf;
249                 GtkIconFactory *factory;
250                 gint i;
251
252                 static GtkStockItem items[] = {
253                         { MODEST_STOCK_MAIL_SEND, "send mail", 0, 0, NULL },
254                         { MODEST_STOCK_NEW_MAIL, "new mail", 0, 0, NULL },
255                         { MODEST_STOCK_SEND_RECEIVE, "send receive", 0, 0, NULL },
256                         { MODEST_STOCK_REPLY, "reply", 0, 0, NULL },
257                         { MODEST_STOCK_REPLY_ALL, "reply all", 0, 0, NULL },
258                         { MODEST_STOCK_FORWARD, "forward", 0, 0, NULL },
259                         { MODEST_STOCK_DELETE, "delete", 0, 0, NULL },
260                         { MODEST_STOCK_NEXT, "next", 0, 0, NULL },
261                         { MODEST_STOCK_PREV, "prev", 0, 0, NULL },
262 /*                      { MODEST_STOCK_STOP, "stop", 0, 0, NULL } */
263                 };
264       
265                 static gchar *items_names [] = {
266                         MODEST_TOOLBAR_ICON_MAIL_SEND,
267                         MODEST_TOOLBAR_ICON_NEW_MAIL,           
268                         MODEST_TOOLBAR_ICON_SEND_RECEIVE,
269                         MODEST_TOOLBAR_ICON_REPLY,      
270                         MODEST_TOOLBAR_ICON_REPLY_ALL,
271                         MODEST_TOOLBAR_ICON_FORWARD,
272                         MODEST_TOOLBAR_ICON_DELETE,
273                         MODEST_TOOLBAR_ICON_NEXT,
274                         MODEST_TOOLBAR_ICON_PREV,
275 /*                      MODEST_TOOLBAR_ICON_STOP */
276                 };
277
278                 registered = TRUE;
279
280                 /* Register our stock items */
281                 gtk_stock_add (items, G_N_ELEMENTS (items));
282       
283                 /* Add our custom icon factory to the list of defaults */
284                 factory = gtk_icon_factory_new ();
285                 gtk_icon_factory_add_default (factory);
286
287                 /* Register icons to accompany stock items */
288                 for (i = 0; i < G_N_ELEMENTS (items); i++) {
289                         pixbuf = NULL;
290                         pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
291
292                         if (pixbuf != NULL) {
293                                 GtkIconSet *icon_set;
294                                 GdkPixbuf *transparent;
295
296                                 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
297
298                                 icon_set = gtk_icon_set_new_from_pixbuf (transparent);
299                                 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
300                                 gtk_icon_set_unref (icon_set);
301                                 g_object_unref (pixbuf);
302                                 g_object_unref (transparent);
303                         }
304                         else
305                                 g_warning ("failed to load %s icon", items_names[i]);
306                 }
307                 /* Drop our reference to the factory, GTK will hold a reference. */
308                 g_object_unref (factory);
309         }
310 }
311
312 /* FIXME: uninit these as well */
313 static void
314 connect_signals (ModestUI *self)
315 {
316         TnyDevice *device;
317         TnyAccountStore *account_store;
318         ModestUIPrivate *priv;
319         ModestFolderView *folder_view;
320         ModestHeaderView *header_view;
321         ModestMsgView *msg_view;
322         GtkWidget *toggle;
323         ModestWidgetFactory *widget_factory;
324         
325         priv = MODEST_UI_GET_PRIVATE(self);
326
327         widget_factory = modest_runtime_get_widget_factory (); 
328         
329         folder_view   = modest_widget_factory_get_folder_view (widget_factory);
330         header_view   = modest_widget_factory_get_header_view (widget_factory);
331         msg_view      = modest_widget_factory_get_msg_preview (widget_factory);
332         toggle        = modest_widget_factory_get_online_toggle (widget_factory);
333         account_store = TNY_ACCOUNT_STORE(modest_runtime_get_account_store());
334         device        = tny_account_store_get_device (account_store);
335
336         /* folder view */
337         g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
338                           G_CALLBACK(_modest_ui_actions_on_folder_selection_changed),
339                           priv->main_window);   
340         /* header view */
341         g_signal_connect (G_OBJECT(header_view), "status_update",
342                           G_CALLBACK(_modest_ui_actions_on_header_status_update), 
343                           priv->main_window);
344         g_signal_connect (G_OBJECT(header_view), "header_selected",
345                           G_CALLBACK(_modest_ui_actions_on_header_selected), 
346                           priv->main_window);
347         g_signal_connect (G_OBJECT(header_view), "item_not_found",
348                           G_CALLBACK(_modest_ui_actions_on_item_not_found), 
349                           priv->main_window);
350         /* msg preview */
351         g_signal_connect (G_OBJECT(msg_view), "link_clicked",
352                           G_CALLBACK(_modest_ui_actions_on_msg_link_clicked), 
353                           priv->main_window);
354         g_signal_connect (G_OBJECT(msg_view), "link_hover",
355                           G_CALLBACK(_modest_ui_actions_on_msg_link_hover), 
356                           priv->main_window);
357         g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
358                           G_CALLBACK(_modest_ui_actions_on_msg_attachment_clicked), 
359                           priv->main_window);
360
361         /* Account store */
362         g_signal_connect (G_OBJECT (account_store), "accounts_reloaded",
363                           G_CALLBACK (_modest_ui_actions_on_accounts_reloaded),
364                           priv->main_window);
365
366         /* Device */
367         g_signal_connect (G_OBJECT(device), "connection_changed",
368                           G_CALLBACK(_modest_ui_actions_on_connection_changed), 
369                           self);
370
371         priv->toggle_button_signal=
372                 g_signal_connect (G_OBJECT(toggle), "toggled",
373                                   G_CALLBACK(_modest_ui_actions_on_online_toggle_toggled),
374                                   priv->main_window);
375                 
376         /* Destroy window */
377         g_signal_connect (G_OBJECT(priv->main_window), 
378                           "destroy",
379                           G_CALLBACK(on_main_window_destroy), 
380                           NULL);
381
382         /* Init toggle in correct state */
383         _modest_ui_actions_on_connection_changed (device,
384                                                  tny_device_is_online (device),
385                                                  self);
386 }
387
388
389 /* ***************************************************************** */
390 /*                M O D E S T    U I    A C T I O N S                */
391 /* ***************************************************************** */
392 void   
393 _modest_ui_actions_on_about (GtkWidget *widget, 
394                              ModestMainWindow *main_window)
395 {
396         GtkWidget *about;
397         const gchar *authors[] = {
398                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
399                 NULL
400         };
401         about = gtk_about_dialog_new ();
402         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
403         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
404         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
405                                         _("Copyright (c) 2006, Nokia Corporation\n"
406                                           "All rights reserved."));
407         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
408                                        _("a modest e-mail client\n\n"
409                                          "design and implementation: Dirk-Jan C. Binnema\n"
410                                          "contributions from the fine people at KernelConcepts and Igalia\n"
411                                          "uses the tinymail email framework written by Philip van Hoof"));
412         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
413         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
414
415         gtk_dialog_run (GTK_DIALOG (about));
416         gtk_widget_destroy(about);
417 }
418
419 void
420 _modest_ui_actions_on_delete (GtkWidget *widget, 
421                              ModestMainWindow *main_window)
422 {
423         ModestWidgetFactory *widget_factory;
424         ModestHeaderView *header_view;
425         TnyList *header_list;
426         TnyIterator *iter;
427         GtkTreeModel *model;
428
429         widget_factory = modest_runtime_get_widget_factory ();
430         header_view = modest_widget_factory_get_header_view (widget_factory);
431         header_list = modest_header_view_get_selected_headers (header_view);
432         
433         if (header_list) {
434                 iter = tny_list_create_iterator (header_list);
435                 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
436                 if (GTK_IS_TREE_MODEL_SORT (model))
437                         model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
438                 do {
439                         TnyHeader *header;
440                         ModestMailOperation *mail_op;
441
442                         header = TNY_HEADER (tny_iterator_get_current (iter));
443                         /* TODO: thick grain mail operation involving
444                            a list of objects. Composite pattern ??? */
445                         mail_op = modest_mail_operation_new ();
446
447                         /* TODO: add confirmation dialog */
448
449                         /* Move to trash */
450                         modest_mail_operation_remove_msg (mail_op, header, TRUE);
451
452                         /* Remove from tree model */
453                         if (modest_mail_operation_get_status (mail_op) == 
454                             MODEST_MAIL_OPERATION_STATUS_SUCCESS)
455                                 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
456                         else {
457                                 /* TODO: error handling management */
458                                 const GError *error;
459                                 error = modest_mail_operation_get_error (mail_op);
460                                 g_warning (error->message);
461                         }
462
463                         g_object_unref (G_OBJECT (mail_op));
464                         g_object_unref (header);
465                         tny_iterator_next (iter);
466
467                 } while (!tny_iterator_is_done (iter));
468         }
469 }
470
471 void
472 _modest_ui_actions_on_quit (GtkWidget *widget, 
473                            ModestMainWindow *main_window)
474 {
475         /* FIXME: save size of main window */
476 /*      save_sizes (main_window); */
477         gtk_widget_destroy (GTK_WIDGET (main_window));
478 }
479
480 void
481 _modest_ui_actions_on_accounts (GtkWidget *widget, 
482                                 ModestMainWindow *main_window)
483 {
484         GtkWidget *account_win;
485         account_win = modest_account_view_window_new (modest_runtime_get_widget_factory());
486
487         gtk_window_set_transient_for (GTK_WINDOW (account_win),
488                                       GTK_WINDOW (main_window));
489                                       
490         gtk_widget_show (account_win);
491 }
492
493 void
494 _modest_ui_actions_on_new_msg (GtkWidget *widget, 
495                                ModestMainWindow *main_window)
496 {
497         ModestWindow *msg_win;
498         msg_win = modest_edit_msg_window_new (MODEST_EDIT_TYPE_NEW);
499         gtk_widget_show_all (GTK_WIDGET (msg_win));
500 }
501
502 static void
503 reply_forward_func (gpointer data, gpointer user_data)
504 {
505         TnyMsg *msg, *new_msg;
506         GetMsgAsyncHelper *helper;
507         ReplyForwardHelper *rf_helper;
508         ModestWindow *msg_win;
509         ModestEditType edit_type;
510
511         msg = TNY_MSG (data);
512         helper = (GetMsgAsyncHelper *) user_data;
513         rf_helper = (ReplyForwardHelper *) helper->user_data;
514
515         /* Create reply mail */
516         switch (rf_helper->action) {
517         case ACTION_REPLY:
518                 new_msg = 
519                         modest_mail_operation_create_reply_mail (msg, 
520                                                                  rf_helper->from, 
521                                                                  rf_helper->reply_forward_type,
522                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
523                 break;
524         case ACTION_REPLY_TO_ALL:
525                 new_msg = 
526                         modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
527                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
528                 edit_type = MODEST_EDIT_TYPE_REPLY;
529                 break;
530         case ACTION_FORWARD:
531                 new_msg = 
532                         modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
533                 edit_type = MODEST_EDIT_TYPE_FORWARD;
534                 break;
535         default:
536                 g_return_if_reached ();
537         }
538
539         if (!new_msg) {
540                 g_warning ("Unable to create a message");
541                 goto cleanup;
542         }
543                 
544         /* Show edit window */
545         msg_win = modest_edit_msg_window_new (MODEST_EDIT_TYPE_NEW);
546         modest_edit_msg_window_set_msg (MODEST_EDIT_MSG_WINDOW (msg_win),
547                                         new_msg);
548         gtk_widget_show_all (GTK_WIDGET (msg_win));
549         
550         /* Clean */
551         g_object_unref (G_OBJECT (new_msg));
552
553  cleanup:
554         g_free (rf_helper->from);
555         g_slice_free (ReplyForwardHelper, rf_helper);
556 }
557
558 /*
559  * Common code for the reply and forward actions
560  */
561 static void
562 reply_forward (GtkWidget *widget,
563                ReplyForwardAction action,
564                ModestMainWindow *main_window)
565 {
566         ModestHeaderView *header_view;
567         ModestAccountMgr *account_mgr;
568         TnyList *header_list;
569         guint reply_forward_type;
570         ModestConf *conf;       
571         ModestAccountData *default_account_data;
572         TnyHeader *header;
573         TnyFolder *folder;
574         gchar *from, *key, *default_account_name;
575         GetMsgAsyncHelper *helper;
576         ReplyForwardHelper *rf_helper;
577
578         conf = modest_runtime_get_conf ();
579         
580         /* Get reply or forward type */
581         key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, 
582                                (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE);
583         reply_forward_type = modest_conf_get_int (conf, key, NULL);
584         g_free (key);
585
586         /* Get the list of headers */
587         header_view = modest_widget_factory_get_header_view (modest_runtime_get_widget_factory());
588         header_list = modest_header_view_get_selected_headers (header_view);    
589         if (!header_list)
590                 return;
591
592         /* We assume that we can only select messages of the
593            same folder and that we reply all of them from the
594            same account. In fact the interface currently only
595            allows single selection */
596         account_mgr = modest_runtime_get_account_mgr();
597         default_account_name = modest_account_mgr_get_default_account (account_mgr);
598         default_account_data = 
599                 modest_account_mgr_get_account_data (account_mgr,
600                                                      (const gchar*) default_account_name);
601         from = g_strdup (default_account_data->email);
602         modest_account_mgr_free_account_data (account_mgr, default_account_data);
603         g_free (default_account_name);
604         
605         /* Fill helpers */
606         rf_helper = g_slice_new0 (ReplyForwardHelper);
607         rf_helper->reply_forward_type = reply_forward_type;
608         rf_helper->action = action;
609         rf_helper->from = from;
610         
611         helper = g_slice_new0 (GetMsgAsyncHelper);
612         helper->main_window = main_window;
613         helper->func = reply_forward_func;
614         helper->iter = tny_list_create_iterator (header_list);
615         helper->user_data = rf_helper;
616         
617         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
618         folder = tny_header_get_folder (header);
619         
620         /* The callback will call it per each header */
621         tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
622         
623         /* Clean */
624         g_object_unref (G_OBJECT (folder));
625 }
626
627 void
628 _modest_ui_actions_on_reply (GtkWidget *widget,
629                             ModestMainWindow *main_window)
630 {
631         reply_forward (widget, ACTION_REPLY, main_window);
632 }
633
634 void
635 _modest_ui_actions_on_forward (GtkWidget *widget,
636                               ModestMainWindow *main_window)
637 {
638         reply_forward (widget, ACTION_FORWARD, main_window);
639 }
640
641 void
642 _modest_ui_actions_on_reply_all (GtkWidget *widget,
643                                 ModestMainWindow *main_window)
644 {
645         reply_forward (widget, ACTION_REPLY_TO_ALL, main_window);
646 }
647
648 void 
649 _modest_ui_actions_on_next (GtkWidget *widget, 
650                            ModestMainWindow *main_window)
651 {
652         ModestHeaderView *header_view;
653
654         header_view = modest_widget_factory_get_header_view
655                 (modest_runtime_get_widget_factory());
656
657         modest_header_view_select_next (header_view);
658 }
659
660 void
661 _modest_ui_actions_toggle_view (GtkWidget *widget,
662                                 ModestMainWindow *main_window)
663 {
664         ModestConf *conf;
665         ModestHeaderView *header_view;
666
667         header_view = modest_widget_factory_get_header_view
668                 (modest_runtime_get_widget_factory());
669
670         conf = modest_runtime_get_conf ();
671         
672         /* what is saved/restored is depending on the style; thus; we save with
673          * old style, then update the style, and restore for this new style*/
674         modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
675         
676         if (modest_header_view_get_style (header_view) == MODEST_HEADER_VIEW_STYLE_DETAILS)
677                 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
678         else
679                 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_DETAILS);
680
681         modest_widget_memory_restore (conf, G_OBJECT(header_view), "header-view");
682 }
683
684
685
686 /*
687  * Marks a message as read and passes it to the msg preview widget
688  */
689 static void
690 read_msg_func (gpointer data, gpointer user_data)
691 {
692         ModestMsgView *msg_view;
693         TnyMsg *msg;
694         TnyHeader *header;
695         GetMsgAsyncHelper *helper;
696         TnyHeaderFlags header_flags;
697
698         msg = TNY_MSG (data);
699         helper = (GetMsgAsyncHelper *) user_data;
700
701         /* mark message as seen; _set_flags crashes, bug in tinymail? */
702         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
703         header_flags = tny_header_get_flags (header);
704         tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
705         g_object_unref (G_OBJECT (header));
706
707         /* Set message on msg view */
708         msg_view = modest_widget_factory_get_msg_preview
709                 (modest_runtime_get_widget_factory());
710         modest_msg_view_set_message (msg_view, msg);
711 }
712
713 /*
714  * This function is a generic handler for the tny_folder_get_msg_async
715  * call. It expects as user_data a #GetMsgAsyncHelper. This helper
716  * contains a user provided function that is called inside this
717  * method. This will allow us to use this callback in many different
718  * places. This callback performs the common actions for the
719  * get_msg_async call, more specific actions will be done by the user
720  * function
721  */
722 static void
723 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
724 {
725         GetMsgAsyncHelper *helper;
726
727         helper = (GetMsgAsyncHelper *) user_data;
728
729         if ((*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) || !msg) {
730                 ModestHeaderView *header_view;
731                 header_view = modest_widget_factory_get_header_view
732                         (modest_runtime_get_widget_factory());
733                 _modest_ui_actions_on_item_not_found (header_view,
734                                                       MODEST_ITEM_TYPE_MESSAGE,
735                                                       helper->main_window);
736                 return;
737         }
738
739         /* Call user function */
740         helper->func (msg, user_data);
741
742         /* Process next element (if exists) */
743         tny_iterator_next (helper->iter);
744         if (tny_iterator_is_done (helper->iter)) {
745                 TnyList *headers;
746                 headers = tny_iterator_get_list (helper->iter);
747                 /* Free resources */
748                 g_object_unref (G_OBJECT (headers));
749                 g_object_unref (G_OBJECT (helper->iter));
750                 g_slice_free (GetMsgAsyncHelper, helper);
751         } else
752                 tny_folder_get_msg_async (folder, 
753                                           TNY_HEADER (tny_iterator_get_current (helper->iter)), 
754                                           get_msg_cb, helper);
755 }
756
757 void 
758 _modest_ui_actions_on_header_selected (ModestHeaderView *folder_view, 
759                                       TnyHeader *header,
760                                       ModestMainWindow *main_window)
761 {
762         TnyFolder *folder;
763         GetMsgAsyncHelper *helper;
764         TnyList *list;
765
766         /* when there's no header, clear the msgview */
767         if (!header) {
768                 ModestMsgView *msg_view;
769                 msg_view       = modest_widget_factory_get_msg_preview
770                         (modest_runtime_get_widget_factory());
771                 modest_msg_view_set_message (msg_view, NULL);
772                 return;
773         }
774
775         folder = tny_header_get_folder (TNY_HEADER(header));
776
777         /* Create list */
778         list = tny_simple_list_new ();
779         tny_list_prepend (list, G_OBJECT (header));
780
781         /* Fill helper data */
782         helper = g_slice_new0 (GetMsgAsyncHelper);
783         helper->main_window = main_window;
784         helper->iter = tny_list_create_iterator (list);
785         helper->func = read_msg_func;
786
787         tny_folder_get_msg_async (TNY_FOLDER(folder),
788                                   header, get_msg_cb,
789                                   helper);
790
791         /* Frees */
792         g_object_unref (G_OBJECT (folder));
793 }
794
795 void 
796 _modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
797                                                TnyFolder *folder, 
798                                                gboolean selected,
799                                                ModestMainWindow *main_window)
800 {
801         GtkLabel *folder_info_label;
802         gchar *txt;     
803         ModestConf *conf;
804         ModestHeaderView *header_view;
805
806         folder_info_label = 
807                 GTK_LABEL (modest_widget_factory_get_folder_info_label
808                            (modest_runtime_get_widget_factory()));
809
810         if (!folder) {
811                 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
812                 return;
813         }
814         
815         header_view = modest_widget_factory_get_header_view (modest_runtime_get_widget_factory());
816         conf = modest_runtime_get_conf ();
817
818         if (!selected) { /* the folder was unselected; save it's settings  */
819                 modest_widget_memory_save (conf, G_OBJECT (header_view),
820                                            "header-view");
821                 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
822                 modest_header_view_set_folder (header_view, NULL);
823         } else {  /* the folder was selected */
824                 if (folder) { /* folder may be NULL */
825                         guint num, unread;
826                         gchar *title;
827
828                         num    = tny_folder_get_all_count    (folder);
829                         unread = tny_folder_get_unread_count (folder);
830                         
831                         title = g_strdup_printf ("Modest: %s",
832                                                  tny_folder_get_name (folder));
833                         
834                         gtk_window_set_title (GTK_WINDOW(main_window), title);
835                         g_free (title);
836                         
837                         txt = g_strdup_printf (_("%d %s, %d unread"),
838                                        num, num==1 ? _("item") : _("items"), unread);           
839                         gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
840                         g_free (txt);
841                 }
842                 modest_header_view_set_folder (header_view, folder);
843                 modest_widget_memory_restore (conf, G_OBJECT(header_view),
844                                               "header-view");
845         }
846 }
847
848
849 /****************************************************/
850 /*
851  * below some stuff to clearup statusbar messages after 1,5 seconds....
852  */
853 typedef struct {
854         GtkWidget *status_bar;
855         GtkWidget *progress_bar;
856         guint     msg_id;
857 } StatusRemoveData;
858
859
860 static gboolean
861 progress_bar_clean (GtkWidget *bar)
862 {
863         if (GTK_IS_PROGRESS_BAR(bar)) {
864                 gtk_progress_bar_set_text     (GTK_PROGRESS_BAR(bar), "");
865                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
866         }
867         return FALSE;
868 }
869
870 static gboolean
871 statusbar_clean (GtkWidget *bar)
872 {
873         if (GTK_IS_STATUSBAR(bar))
874                 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
875         return FALSE;
876 }
877
878
879 static void
880 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
881 {
882         GtkWidget *status_bar, *progress_bar;
883         
884         if (!msg)
885                 return;
886
887         progress_bar = modest_widget_factory_get_progress_bar (factory);
888         status_bar   = modest_widget_factory_get_status_bar (factory);
889
890         gtk_widget_show (GTK_WIDGET(status_bar));
891         gtk_widget_show (GTK_WIDGET(progress_bar));
892
893         gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
894
895         g_timeout_add (1500, (GSourceFunc)statusbar_clean, status_bar);
896         g_timeout_add (3000, (GSourceFunc)progress_bar_clean, progress_bar);
897 }
898 /****************************************************************************/
899
900 static void
901 _modest_ui_actions_on_connection_changed (TnyDevice *device, 
902                                           gboolean online,
903                                           ModestUI *self)
904 {
905         GtkWidget *online_toggle;
906         ModestHeaderView *header_view;
907         ModestWidgetFactory *widget_factory;
908         ModestUIPrivate *priv;
909         GtkWidget *icon;
910         const gchar *icon_name;
911
912         g_return_if_fail (device);
913         g_return_if_fail (self);
914
915         priv = MODEST_UI_GET_PRIVATE (self);
916
917         icon_name = online ? GTK_STOCK_CONNECT : GTK_STOCK_DISCONNECT;
918         icon      = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
919
920         widget_factory = modest_runtime_get_widget_factory ();
921         header_view   = modest_widget_factory_get_header_view (widget_factory);
922         online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
923
924         /* Block handlers in order to avoid unnecessary calls */
925         g_signal_handler_block (G_OBJECT (online_toggle), priv->toggle_button_signal);
926         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle), online);
927         g_signal_handler_unblock (G_OBJECT (online_toggle), priv->toggle_button_signal);
928
929         gtk_button_set_image (GTK_BUTTON(online_toggle), icon);
930         statusbar_push (widget_factory, 0, 
931                         online ? _("Modest went online") : _("Modest went offline"));
932         
933         /* If Modest has became online and the header view has a
934            header selected then show it */
935         /* FIXME: there is a race condition if some account needs to
936            ask the user for a password */
937
938 /*      if (online) { */
939 /*              GtkTreeSelection *selected; */
940
941 /*              selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view)); */
942 /*              _modest_header_view_change_selection (selected, header_view); */
943 /*      } */
944 }
945
946 void
947 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
948                                              ModestMainWindow *main_window)
949 {
950         gboolean online;
951         TnyDevice *device;
952
953         device = tny_account_store_get_device
954                 (TNY_ACCOUNT_STORE(modest_runtime_get_account_store()));
955
956         online  = gtk_toggle_button_get_active (toggle);
957
958         if (online)
959                 tny_device_force_online (device);
960         else
961                 tny_device_force_offline (device);
962 }
963
964 void 
965 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
966                                      ModestItemType type,
967                                      ModestMainWindow *main_window)
968 {
969         GtkWidget *dialog;
970         gchar *txt, *item;
971         gboolean online;
972         TnyDevice *device;
973         TnyAccountStore *account_store;
974
975         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
976
977         /* Get device. Do not ask the platform factory for it, because
978            it returns always a new one */
979         account_store = TNY_ACCOUNT_STORE (modest_runtime_get_account_store ());
980         device = tny_account_store_get_device (account_store);
981
982         if (g_main_depth > 0)   
983                 gdk_threads_enter ();
984         online = tny_device_is_online (device);
985
986         if (online) {
987                 /* already online -- the item is simply not there... */
988                 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
989                                                  GTK_DIALOG_MODAL,
990                                                  GTK_MESSAGE_WARNING,
991                                                  GTK_BUTTONS_OK,
992                                                  _("The %s you selected cannot be found"),
993                                                  item);
994                 gtk_dialog_run (GTK_DIALOG(dialog));
995         } else {
996
997                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
998                                                       GTK_WINDOW (main_window),
999                                                       GTK_DIALOG_MODAL,
1000                                                       GTK_STOCK_CANCEL,
1001                                                       GTK_RESPONSE_REJECT,
1002                                                       GTK_STOCK_OK,
1003                                                       GTK_RESPONSE_ACCEPT,
1004                                                       NULL);
1005
1006                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1007                                          "Do you want to get online?"), item);
1008                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1009                                     gtk_label_new (txt), FALSE, FALSE, 0);
1010                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1011                 g_free (txt);
1012
1013                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1014                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1015                         tny_device_force_online (device);
1016                 }
1017         }
1018         gtk_widget_destroy (dialog);
1019         if (g_main_depth > 0)   
1020                 gdk_threads_leave ();
1021 }
1022
1023
1024
1025 void
1026 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
1027                                             const gchar *msg,
1028                                             gint num, 
1029                                             gint total, 
1030                                             ModestMainWindow *main_window)
1031 {
1032         GtkWidget *progress_bar;
1033         char* txt;
1034         
1035         progress_bar = modest_widget_factory_get_progress_bar
1036                 (modest_runtime_get_widget_factory());
1037         if (total != 0)
1038                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1039                                                (gdouble)num/(gdouble)total);
1040         else
1041                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1042
1043         txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
1044         gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
1045         g_free (txt);
1046         
1047         statusbar_push (modest_runtime_get_widget_factory(), 0, msg);
1048 }
1049
1050
1051
1052 void
1053 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, 
1054                                       const gchar* link,
1055                                       ModestMainWindow *main_window)
1056 {
1057         statusbar_push (modest_runtime_get_widget_factory(), 0, link);
1058
1059         /* TODO: do something */
1060 }       
1061
1062
1063 void
1064 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, 
1065                                         const gchar* link,
1066                                         ModestMainWindow *main_window)
1067 {
1068         gchar *msg;
1069
1070         msg = g_strdup_printf (_("Opening %s..."), link);
1071         statusbar_push (modest_runtime_get_widget_factory(), 0, msg);
1072         g_free (msg);
1073
1074         /* TODO: do something */
1075 }
1076
1077 void
1078 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, 
1079                                               int index,
1080                                               ModestMainWindow *main_window)
1081 {
1082         gchar *msg;
1083         
1084         msg = g_strdup_printf (_("Opening attachment %d..."), index);
1085         statusbar_push (modest_runtime_get_widget_factory(), 0, msg);
1086         
1087         g_free (msg);
1088         /* TODO: do something */
1089 }
1090
1091 void
1092 _modest_ui_actions_on_send (GtkWidget *widget, 
1093                             ModestEditMsgWindow *edit_window)
1094 {
1095         TnyTransportAccount *transport_account;
1096         ModestMailOperation *mail_operation;
1097         MsgData *data;
1098
1099         data = modest_edit_msg_window_get_msg_data (edit_window);
1100
1101         /* FIXME: Code added just for testing. The final version will
1102            use the send queue provided by tinymail and some
1103            classifier */
1104         {
1105                 TnyList *accounts;
1106                 TnyIterator *iter;
1107                 
1108                 accounts = TNY_LIST(tny_simple_list_new ());
1109                 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(modest_runtime_get_account_store()),
1110                                                 accounts,
1111                                                 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1112
1113                 iter = tny_list_create_iterator(accounts);
1114                 tny_iterator_first (iter);
1115                 if (tny_iterator_is_done (iter)) {
1116                         /* FIXME: Add error handling through mail operation */
1117                         g_printerr("modest: no transport accounts defined\n");
1118                         modest_edit_msg_window_free_msg_data (edit_window, data);
1119                         return;
1120                 }
1121                 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1122                 g_object_ref (transport_account);
1123
1124                 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1125                 g_object_unref (G_OBJECT (accounts));
1126                 g_object_unref (G_OBJECT (iter));
1127         }
1128
1129         mail_operation = modest_mail_operation_new ();
1130
1131         modest_mail_operation_send_new_mail (mail_operation,
1132                                              transport_account,
1133                                              data->from, 
1134                                              data->to, 
1135                                              data->cc, 
1136                                              data->bcc,
1137                                              data->subject, 
1138                                              data->body, 
1139                                              NULL);
1140         /* Frees */
1141         g_object_unref (G_OBJECT (mail_operation));
1142         g_object_unref (G_OBJECT (transport_account));
1143         modest_edit_msg_window_free_msg_data (edit_window, data);
1144
1145         /* Save settings and close the window */
1146         /* save_settings (edit_window) */
1147         gtk_widget_destroy (GTK_WIDGET (edit_window));
1148 }
1149
1150 /*
1151  * Shows a dialog with an entry that asks for some text. The returned
1152  * value must be freed by the caller. The dialog window title will be
1153  * set to @title.
1154  */
1155 static gchar *
1156 ask_for_folder_name (GtkWindow *parent_window,
1157                      const gchar *title)
1158 {
1159         GtkWidget *dialog, *entry;
1160         gchar *folder_name = NULL;
1161
1162         /* Ask for folder name */
1163         dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1164                                               parent_window,
1165                                               GTK_DIALOG_MODAL,
1166                                               GTK_STOCK_CANCEL,
1167                                               GTK_RESPONSE_REJECT,
1168                                               GTK_STOCK_OK,
1169                                               GTK_RESPONSE_ACCEPT,
1170                                               NULL);
1171         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1172                             gtk_label_new(title),
1173                             FALSE, FALSE, 0);
1174                 
1175         entry = gtk_entry_new_with_max_length (40);
1176         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1177                             entry,
1178                             TRUE, FALSE, 0);    
1179         
1180         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1181         
1182         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)         
1183                 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1184
1185         gtk_widget_destroy (dialog);
1186
1187         return folder_name;
1188 }
1189         
1190 void 
1191 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1192                                   ModestMainWindow *main_window)
1193 {
1194         TnyFolder *parent_folder;
1195         ModestFolderView *folder_view;
1196
1197         folder_view = modest_widget_factory_get_folder_view
1198                 (modest_runtime_get_widget_factory());
1199         parent_folder = modest_folder_view_get_selected (folder_view);
1200         
1201         if (parent_folder) {
1202                 gchar *folder_name;
1203
1204                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1205                                                    _("Please enter a name for the new folder"));
1206
1207                 if (folder_name != NULL && strlen (folder_name) > 0) {
1208                         TnyFolder *new_folder;
1209                         ModestMailOperation *mail_op;
1210
1211                         mail_op = modest_mail_operation_new ();
1212                         new_folder = modest_mail_operation_create_folder (mail_op,
1213                                                                           TNY_FOLDER_STORE (parent_folder),
1214                                                                           (const gchar *) folder_name);
1215                         if (new_folder) {
1216                                 /* Do anything more? The model
1217                                    is automatically updated */
1218                                 g_object_unref (new_folder);
1219                         }
1220                         g_object_unref (mail_op);
1221                 }
1222                 g_object_unref (parent_folder);
1223         }
1224 }
1225
1226 void 
1227 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1228                                      ModestMainWindow *main_window)
1229 {
1230         TnyFolder *folder;
1231         ModestFolderView *folder_view;
1232         
1233         folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory());
1234         folder = modest_folder_view_get_selected (folder_view);
1235
1236         if (folder) {
1237                 gchar *folder_name;
1238
1239                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1240                                                    _("Please enter a new name for the folder"));
1241
1242                 if (folder_name != NULL && strlen (folder_name) > 0) {
1243                         ModestMailOperation *mail_op;
1244
1245                         mail_op = modest_mail_operation_new ();
1246                         modest_mail_operation_rename_folder (mail_op,
1247                                                              folder,
1248                                                              (const gchar *) folder_name);
1249                         g_object_unref (mail_op);
1250                 }
1251                 g_object_unref (folder);
1252         }
1253 }
1254
1255 static void
1256 delete_folder (ModestMainWindow *main_window,
1257                gboolean move_to_trash) 
1258 {
1259         TnyFolder *folder;
1260         ModestFolderView *folder_view;
1261         ModestMailOperation *mail_op;
1262         
1263         folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory());
1264         folder = modest_folder_view_get_selected (folder_view);
1265
1266         mail_op = modest_mail_operation_new ();
1267         modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1268         g_object_unref (mail_op);
1269 }
1270
1271 void 
1272 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1273                                      ModestMainWindow *main_window)
1274 {
1275         delete_folder (main_window, FALSE);
1276 }
1277
1278 void 
1279 _modest_ui_actions_on_move_to_trash_folder (GtkWidget *widget,
1280                                             ModestMainWindow *main_window)
1281 {
1282         delete_folder (main_window, TRUE);
1283 }
1284
1285 static void
1286 _modest_ui_actions_on_accounts_reloaded (TnyAccountStore *store, gpointer user_data)
1287 {
1288         ModestFolderView *folder_view;
1289         
1290         folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory());
1291         modest_folder_view_update_model (folder_view, store);
1292 }