1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
32 #endif /*HAVE_CONFIG_H*/
34 #include <glib/gi18n.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>
52 #define MODEST_UI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
56 typedef struct _GetMsgAsyncHelper {
57 ModestMainWindow *main_window;
63 typedef enum _ReplyForwardAction {
69 typedef struct _ReplyForwardHelper {
70 guint reply_forward_type;
71 ReplyForwardAction action;
76 static GObjectClass *parent_class = NULL;
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);
83 static void register_stock_icons ();
84 static void connect_signals (ModestUI *self);
86 static void reply_forward_func (gpointer data,
88 static void read_msg_func (gpointer data,
90 static void get_msg_cb (TnyFolder *folder,
95 static void reply_forward (GtkWidget *widget,
96 ReplyForwardAction action,
97 ModestMainWindow *main_window);
99 static gchar* ask_for_folder_name (GtkWindow *parent_window,
102 static void _modest_ui_actions_on_connection_changed (TnyDevice *device,
104 ModestUI *modest_ui);
107 static void _modest_ui_actions_on_accounts_reloaded (TnyAccountStore *store,
111 modest_ui_get_type (void)
113 static GType my_type = 0;
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 */
124 (GInstanceInitFunc) modest_ui_init,
127 my_type = g_type_register_static (G_TYPE_OBJECT,
136 modest_ui_class_init (ModestUIClass *klass)
138 GObjectClass *gobject_class;
139 gobject_class = (GObjectClass*) klass;
141 parent_class = g_type_class_peek_parent (klass);
142 gobject_class->finalize = modest_ui_finalize;
144 g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
150 modest_ui_init (ModestUI *obj)
152 ModestUIPrivate *priv;
154 priv = MODEST_UI_GET_PRIVATE(obj);
156 priv->main_window = NULL;
161 modest_ui_finalize (GObject *obj)
163 ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
165 if (priv->ui_manager) {
166 g_object_unref (G_OBJECT(priv->ui_manager));
167 priv->ui_manager = NULL;
170 priv->main_window = NULL;
172 G_OBJECT_CLASS(parent_class)->finalize (obj);
180 ModestUIPrivate *priv;
182 obj = g_object_new(MODEST_TYPE_UI, NULL);
183 priv = MODEST_UI_GET_PRIVATE(obj);
185 /* Register our own icons as stock icons in order to
186 use them with the UI manager */
187 register_stock_icons ();
189 return MODEST_UI(obj);
193 on_main_window_destroy (GtkObject *widget, ModestUI *self)
195 /* FIXME: check if there any viewer/editing windows opened */
202 modest_ui_main_window (ModestUI *self)
204 ModestUIPrivate *priv;
206 g_return_val_if_fail (self, NULL);
207 priv = MODEST_UI_GET_PRIVATE(self);
209 if (!priv->main_window) {
210 priv->main_window = modest_main_window_new ();
211 connect_signals (self);
214 if (!priv->main_window)
215 g_printerr ("modest: could not create main window\n");
217 return priv->main_window;
221 modest_ui_edit_window (ModestUI *self, ModestEditType edit_type)
223 ModestUIPrivate *priv;
224 ModestWindow *edit_window;
226 g_return_val_if_fail (self, NULL);
227 priv = MODEST_UI_GET_PRIVATE(self);
230 edit_window = modest_edit_msg_window_new (edit_type);
232 /* Connect Edit Window signals */
233 /* connect_edit_window_signals (self); */
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
243 register_stock_icons ()
245 static gboolean registered = FALSE;
249 GtkIconFactory *factory;
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 } */
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 */
280 /* Register our stock items */
281 gtk_stock_add (items, G_N_ELEMENTS (items));
283 /* Add our custom icon factory to the list of defaults */
284 factory = gtk_icon_factory_new ();
285 gtk_icon_factory_add_default (factory);
287 /* Register icons to accompany stock items */
288 for (i = 0; i < G_N_ELEMENTS (items); i++) {
290 pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
292 if (pixbuf != NULL) {
293 GtkIconSet *icon_set;
294 GdkPixbuf *transparent;
296 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
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);
305 g_warning ("failed to load %s icon", items_names[i]);
307 /* Drop our reference to the factory, GTK will hold a reference. */
308 g_object_unref (factory);
312 /* FIXME: uninit these as well */
314 connect_signals (ModestUI *self)
317 TnyAccountStore *account_store;
318 ModestUIPrivate *priv;
319 ModestFolderView *folder_view;
320 ModestHeaderView *header_view;
321 ModestMsgView *msg_view;
323 ModestWidgetFactory *widget_factory;
325 priv = MODEST_UI_GET_PRIVATE(self);
327 widget_factory = modest_runtime_get_widget_factory ();
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);
337 g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
338 G_CALLBACK(_modest_ui_actions_on_folder_selection_changed),
341 g_signal_connect (G_OBJECT(header_view), "status_update",
342 G_CALLBACK(_modest_ui_actions_on_header_status_update),
344 g_signal_connect (G_OBJECT(header_view), "header_selected",
345 G_CALLBACK(_modest_ui_actions_on_header_selected),
347 g_signal_connect (G_OBJECT(header_view), "item_not_found",
348 G_CALLBACK(_modest_ui_actions_on_item_not_found),
351 g_signal_connect (G_OBJECT(msg_view), "link_clicked",
352 G_CALLBACK(_modest_ui_actions_on_msg_link_clicked),
354 g_signal_connect (G_OBJECT(msg_view), "link_hover",
355 G_CALLBACK(_modest_ui_actions_on_msg_link_hover),
357 g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
358 G_CALLBACK(_modest_ui_actions_on_msg_attachment_clicked),
362 g_signal_connect (G_OBJECT (account_store), "accounts_reloaded",
363 G_CALLBACK (_modest_ui_actions_on_accounts_reloaded),
367 g_signal_connect (G_OBJECT(device), "connection_changed",
368 G_CALLBACK(_modest_ui_actions_on_connection_changed),
371 priv->toggle_button_signal=
372 g_signal_connect (G_OBJECT(toggle), "toggled",
373 G_CALLBACK(_modest_ui_actions_on_online_toggle_toggled),
377 g_signal_connect (G_OBJECT(priv->main_window),
379 G_CALLBACK(on_main_window_destroy),
382 /* Init toggle in correct state */
383 _modest_ui_actions_on_connection_changed (device,
384 tny_device_is_online (device),
389 /* ***************************************************************** */
390 /* M O D E S T U I A C T I O N S */
391 /* ***************************************************************** */
393 _modest_ui_actions_on_about (GtkWidget *widget,
394 ModestMainWindow *main_window)
397 const gchar *authors[] = {
398 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
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");
415 gtk_dialog_run (GTK_DIALOG (about));
416 gtk_widget_destroy(about);
420 _modest_ui_actions_on_delete (GtkWidget *widget,
421 ModestMainWindow *main_window)
423 ModestWidgetFactory *widget_factory;
424 ModestHeaderView *header_view;
425 TnyList *header_list;
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);
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));
440 ModestMailOperation *mail_op;
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 ();
447 /* TODO: add confirmation dialog */
450 modest_mail_operation_remove_msg (mail_op, header, TRUE);
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));
457 /* TODO: error handling management */
459 error = modest_mail_operation_get_error (mail_op);
460 g_warning (error->message);
463 g_object_unref (G_OBJECT (mail_op));
464 g_object_unref (header);
465 tny_iterator_next (iter);
467 } while (!tny_iterator_is_done (iter));
472 _modest_ui_actions_on_quit (GtkWidget *widget,
473 ModestMainWindow *main_window)
475 /* FIXME: save size of main window */
476 /* save_sizes (main_window); */
477 gtk_widget_destroy (GTK_WIDGET (main_window));
481 _modest_ui_actions_on_accounts (GtkWidget *widget,
482 ModestMainWindow *main_window)
484 GtkWidget *account_win;
485 account_win = modest_account_view_window_new (modest_runtime_get_widget_factory());
487 gtk_window_set_transient_for (GTK_WINDOW (account_win),
488 GTK_WINDOW (main_window));
490 gtk_widget_show (account_win);
494 _modest_ui_actions_on_new_msg (GtkWidget *widget,
495 ModestMainWindow *main_window)
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));
503 reply_forward_func (gpointer data, gpointer user_data)
505 TnyMsg *msg, *new_msg;
506 GetMsgAsyncHelper *helper;
507 ReplyForwardHelper *rf_helper;
508 ModestWindow *msg_win;
509 ModestEditType edit_type;
511 msg = TNY_MSG (data);
512 helper = (GetMsgAsyncHelper *) user_data;
513 rf_helper = (ReplyForwardHelper *) helper->user_data;
515 /* Create reply mail */
516 switch (rf_helper->action) {
519 modest_mail_operation_create_reply_mail (msg,
521 rf_helper->reply_forward_type,
522 MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
524 case ACTION_REPLY_TO_ALL:
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;
532 modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
533 edit_type = MODEST_EDIT_TYPE_FORWARD;
536 g_return_if_reached ();
540 g_warning ("Unable to create a message");
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),
548 gtk_widget_show_all (GTK_WIDGET (msg_win));
551 g_object_unref (G_OBJECT (new_msg));
554 g_free (rf_helper->from);
555 g_slice_free (ReplyForwardHelper, rf_helper);
559 * Common code for the reply and forward actions
562 reply_forward (GtkWidget *widget,
563 ReplyForwardAction action,
564 ModestMainWindow *main_window)
566 ModestHeaderView *header_view;
567 ModestAccountMgr *account_mgr;
568 TnyList *header_list;
569 guint reply_forward_type;
571 ModestAccountData *default_account_data;
574 gchar *from, *key, *default_account_name;
575 GetMsgAsyncHelper *helper;
576 ReplyForwardHelper *rf_helper;
578 conf = modest_runtime_get_conf ();
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);
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);
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);
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;
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;
617 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
618 folder = tny_header_get_folder (header);
620 /* The callback will call it per each header */
621 tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
624 g_object_unref (G_OBJECT (folder));
628 _modest_ui_actions_on_reply (GtkWidget *widget,
629 ModestMainWindow *main_window)
631 reply_forward (widget, ACTION_REPLY, main_window);
635 _modest_ui_actions_on_forward (GtkWidget *widget,
636 ModestMainWindow *main_window)
638 reply_forward (widget, ACTION_FORWARD, main_window);
642 _modest_ui_actions_on_reply_all (GtkWidget *widget,
643 ModestMainWindow *main_window)
645 reply_forward (widget, ACTION_REPLY_TO_ALL, main_window);
649 _modest_ui_actions_on_next (GtkWidget *widget,
650 ModestMainWindow *main_window)
652 ModestHeaderView *header_view;
654 header_view = modest_widget_factory_get_header_view
655 (modest_runtime_get_widget_factory());
657 modest_header_view_select_next (header_view);
661 _modest_ui_actions_toggle_view (GtkWidget *widget,
662 ModestMainWindow *main_window)
665 ModestHeaderView *header_view;
667 header_view = modest_widget_factory_get_header_view
668 (modest_runtime_get_widget_factory());
670 conf = modest_runtime_get_conf ();
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");
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);
679 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_DETAILS);
681 modest_widget_memory_restore (conf, G_OBJECT(header_view), "header-view");
687 * Marks a message as read and passes it to the msg preview widget
690 read_msg_func (gpointer data, gpointer user_data)
692 ModestMsgView *msg_view;
695 GetMsgAsyncHelper *helper;
696 TnyHeaderFlags header_flags;
698 msg = TNY_MSG (data);
699 helper = (GetMsgAsyncHelper *) user_data;
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));
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);
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
723 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
725 GetMsgAsyncHelper *helper;
727 helper = (GetMsgAsyncHelper *) user_data;
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);
739 /* Call user function */
740 helper->func (msg, user_data);
742 /* Process next element (if exists) */
743 tny_iterator_next (helper->iter);
744 if (tny_iterator_is_done (helper->iter)) {
746 headers = tny_iterator_get_list (helper->iter);
748 g_object_unref (G_OBJECT (headers));
749 g_object_unref (G_OBJECT (helper->iter));
750 g_slice_free (GetMsgAsyncHelper, helper);
752 tny_folder_get_msg_async (folder,
753 TNY_HEADER (tny_iterator_get_current (helper->iter)),
758 _modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,
760 ModestMainWindow *main_window)
763 GetMsgAsyncHelper *helper;
766 /* when there's no header, clear the msgview */
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);
775 folder = tny_header_get_folder (TNY_HEADER(header));
778 list = tny_simple_list_new ();
779 tny_list_prepend (list, G_OBJECT (header));
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;
787 tny_folder_get_msg_async (TNY_FOLDER(folder),
792 g_object_unref (G_OBJECT (folder));
796 _modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
799 ModestMainWindow *main_window)
801 GtkLabel *folder_info_label;
804 ModestHeaderView *header_view;
807 GTK_LABEL (modest_widget_factory_get_folder_info_label
808 (modest_runtime_get_widget_factory()));
811 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
815 header_view = modest_widget_factory_get_header_view (modest_runtime_get_widget_factory());
816 conf = modest_runtime_get_conf ();
818 if (!selected) { /* the folder was unselected; save it's settings */
819 modest_widget_memory_save (conf, G_OBJECT (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 */
828 num = tny_folder_get_all_count (folder);
829 unread = tny_folder_get_unread_count (folder);
831 title = g_strdup_printf ("Modest: %s",
832 tny_folder_get_name (folder));
834 gtk_window_set_title (GTK_WINDOW(main_window), title);
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);
842 modest_header_view_set_folder (header_view, folder);
843 modest_widget_memory_restore (conf, G_OBJECT(header_view),
849 /****************************************************/
851 * below some stuff to clearup statusbar messages after 1,5 seconds....
854 GtkWidget *status_bar;
855 GtkWidget *progress_bar;
861 progress_bar_clean (GtkWidget *bar)
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);
871 statusbar_clean (GtkWidget *bar)
873 if (GTK_IS_STATUSBAR(bar))
874 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
880 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
882 GtkWidget *status_bar, *progress_bar;
887 progress_bar = modest_widget_factory_get_progress_bar (factory);
888 status_bar = modest_widget_factory_get_status_bar (factory);
890 gtk_widget_show (GTK_WIDGET(status_bar));
891 gtk_widget_show (GTK_WIDGET(progress_bar));
893 gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
895 g_timeout_add (1500, (GSourceFunc)statusbar_clean, status_bar);
896 g_timeout_add (3000, (GSourceFunc)progress_bar_clean, progress_bar);
898 /****************************************************************************/
901 _modest_ui_actions_on_connection_changed (TnyDevice *device,
905 GtkWidget *online_toggle;
906 ModestHeaderView *header_view;
907 ModestWidgetFactory *widget_factory;
908 ModestUIPrivate *priv;
910 const gchar *icon_name;
912 g_return_if_fail (device);
913 g_return_if_fail (self);
915 priv = MODEST_UI_GET_PRIVATE (self);
917 icon_name = online ? GTK_STOCK_CONNECT : GTK_STOCK_DISCONNECT;
918 icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
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);
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);
929 gtk_button_set_image (GTK_BUTTON(online_toggle), icon);
930 statusbar_push (widget_factory, 0,
931 online ? _("Modest went online") : _("Modest went offline"));
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 */
939 /* GtkTreeSelection *selected; */
941 /* selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view)); */
942 /* _modest_header_view_change_selection (selected, header_view); */
947 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
948 ModestMainWindow *main_window)
953 device = tny_account_store_get_device
954 (TNY_ACCOUNT_STORE(modest_runtime_get_account_store()));
956 online = gtk_toggle_button_get_active (toggle);
959 tny_device_force_online (device);
961 tny_device_force_offline (device);
965 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
967 ModestMainWindow *main_window)
973 TnyAccountStore *account_store;
975 item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
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);
982 if (g_main_depth > 0)
983 gdk_threads_enter ();
984 online = tny_device_is_online (device);
987 /* already online -- the item is simply not there... */
988 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
992 _("The %s you selected cannot be found"),
994 gtk_dialog_run (GTK_DIALOG(dialog));
997 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
998 GTK_WINDOW (main_window),
1001 GTK_RESPONSE_REJECT,
1003 GTK_RESPONSE_ACCEPT,
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));
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);
1018 gtk_widget_destroy (dialog);
1019 if (g_main_depth > 0)
1020 gdk_threads_leave ();
1026 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view,
1030 ModestMainWindow *main_window)
1032 GtkWidget *progress_bar;
1035 progress_bar = modest_widget_factory_get_progress_bar
1036 (modest_runtime_get_widget_factory());
1038 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1039 (gdouble)num/(gdouble)total);
1041 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1043 txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
1044 gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
1047 statusbar_push (modest_runtime_get_widget_factory(), 0, msg);
1053 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview,
1055 ModestMainWindow *main_window)
1057 statusbar_push (modest_runtime_get_widget_factory(), 0, link);
1059 /* TODO: do something */
1064 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview,
1066 ModestMainWindow *main_window)
1070 msg = g_strdup_printf (_("Opening %s..."), link);
1071 statusbar_push (modest_runtime_get_widget_factory(), 0, msg);
1074 /* TODO: do something */
1078 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview,
1080 ModestMainWindow *main_window)
1084 msg = g_strdup_printf (_("Opening attachment %d..."), index);
1085 statusbar_push (modest_runtime_get_widget_factory(), 0, msg);
1088 /* TODO: do something */
1092 _modest_ui_actions_on_send (GtkWidget *widget,
1093 ModestEditMsgWindow *edit_window)
1095 TnyTransportAccount *transport_account;
1096 ModestMailOperation *mail_operation;
1099 data = modest_edit_msg_window_get_msg_data (edit_window);
1101 /* FIXME: Code added just for testing. The final version will
1102 use the send queue provided by tinymail and some
1108 accounts = TNY_LIST(tny_simple_list_new ());
1109 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(modest_runtime_get_account_store()),
1111 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
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);
1121 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1122 g_object_ref (transport_account);
1124 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1125 g_object_unref (G_OBJECT (accounts));
1126 g_object_unref (G_OBJECT (iter));
1129 mail_operation = modest_mail_operation_new ();
1131 modest_mail_operation_send_new_mail (mail_operation,
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);
1145 /* Save settings and close the window */
1146 /* save_settings (edit_window) */
1147 gtk_widget_destroy (GTK_WIDGET (edit_window));
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
1156 ask_for_folder_name (GtkWindow *parent_window,
1159 GtkWidget *dialog, *entry;
1160 gchar *folder_name = NULL;
1162 /* Ask for folder name */
1163 dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1167 GTK_RESPONSE_REJECT,
1169 GTK_RESPONSE_ACCEPT,
1171 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1172 gtk_label_new(title),
1175 entry = gtk_entry_new_with_max_length (40);
1176 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1180 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1182 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1183 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1185 gtk_widget_destroy (dialog);
1191 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1192 ModestMainWindow *main_window)
1194 TnyFolder *parent_folder;
1195 ModestFolderView *folder_view;
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);
1201 if (parent_folder) {
1204 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1205 _("Please enter a name for the new folder"));
1207 if (folder_name != NULL && strlen (folder_name) > 0) {
1208 TnyFolder *new_folder;
1209 ModestMailOperation *mail_op;
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);
1216 /* Do anything more? The model
1217 is automatically updated */
1218 g_object_unref (new_folder);
1220 g_object_unref (mail_op);
1222 g_object_unref (parent_folder);
1227 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1228 ModestMainWindow *main_window)
1231 ModestFolderView *folder_view;
1233 folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory());
1234 folder = modest_folder_view_get_selected (folder_view);
1239 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1240 _("Please enter a new name for the folder"));
1242 if (folder_name != NULL && strlen (folder_name) > 0) {
1243 ModestMailOperation *mail_op;
1245 mail_op = modest_mail_operation_new ();
1246 modest_mail_operation_rename_folder (mail_op,
1248 (const gchar *) folder_name);
1249 g_object_unref (mail_op);
1251 g_object_unref (folder);
1256 delete_folder (ModestMainWindow *main_window,
1257 gboolean move_to_trash)
1260 ModestFolderView *folder_view;
1261 ModestMailOperation *mail_op;
1263 folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory());
1264 folder = modest_folder_view_get_selected (folder_view);
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);
1272 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1273 ModestMainWindow *main_window)
1275 delete_folder (main_window, FALSE);
1279 _modest_ui_actions_on_move_to_trash_folder (GtkWidget *widget,
1280 ModestMainWindow *main_window)
1282 delete_folder (main_window, TRUE);
1286 _modest_ui_actions_on_accounts_reloaded (TnyAccountStore *store, gpointer user_data)
1288 ModestFolderView *folder_view;
1290 folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory());
1291 modest_folder_view_update_model (folder_view, store);