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.
31 #include <glade/glade.h>
32 #include <glib/gi18n.h>
37 #endif /*HAVE_CONFIG_H*/
39 #include <glib/gi18n.h>
40 #include <gtk/gtkuimanager.h>
41 #include <tny-error.h>
42 #include <tny-simple-list.h>
43 #include "modest-ui.h"
44 #include "modest-tny-account-store.h"
45 #include "modest-account-mgr.h"
46 #include "modest-widget-factory.h"
47 #include "modest-tny-platform-factory.h"
49 #include "modest-edit-msg-window.h"
50 #include "modest-account-view-window.h"
51 #include "modest-icon-names.h"
52 #include "modest-main-window.h"
54 typedef struct _ModestUIPrivate ModestUIPrivate;
55 struct _ModestUIPrivate {
56 ModestWidgetFactory *widget_factory;
57 TnyAccountStore *account_store;
58 GtkWidget *main_window;
61 #define MODEST_UI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
65 typedef struct _GetMsgAsyncHelper {
66 ModestUIPrivate *priv;
72 typedef enum _ReplyForwardAction {
78 typedef struct _ReplyForwardHelper {
79 guint reply_forward_type;
80 ReplyForwardAction action;
85 static GObjectClass *parent_class = NULL;
87 /* 'private'/'protected' functions */
88 static void modest_ui_class_init (ModestUIClass *klass);
89 static void modest_ui_init (ModestUI *obj);
90 static void modest_ui_finalize (GObject *obj);
92 static void register_stock_icons ();
93 static void connect_signals (ModestUI *self);
94 static void connect_main_window_signals (ModestUI *self);
95 static GtkUIManager *create_ui_manager ();
97 static void reply_forward_func (gpointer data, gpointer user_data);
98 static void read_msg_func (gpointer data, gpointer user_data);
99 static void get_msg_cb (TnyFolder *folder,
104 static void reply_forward (GtkWidget *widget,
105 ReplyForwardAction action,
106 ModestUIPrivate *priv);
108 /* Menu & toolbar actions */
109 static void modest_ui_actions_on_about (GtkWidget *widget, ModestUIPrivate *priv);
111 static void modest_ui_actions_on_delete (GtkWidget *widget, ModestUIPrivate *priv);
113 static void modest_ui_actions_on_quit (GtkWidget *widget, ModestUIPrivate *priv);
115 static void modest_ui_actions_on_accounts (GtkWidget *widget, ModestUIPrivate *priv);
117 static void modest_ui_actions_on_new_msg (GtkWidget *widget, ModestUIPrivate *priv);
119 static void modest_ui_actions_on_reply (GtkWidget *widget, ModestUIPrivate *priv);
121 static void modest_ui_actions_on_forward (GtkWidget *widget, ModestUIPrivate *priv);
123 static void modest_ui_actions_on_reply_all (GtkWidget *widget, ModestUIPrivate *priv);
125 static void modest_ui_actions_on_next (GtkWidget *widget, ModestUIPrivate *priv);
128 static void modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,
130 ModestUIPrivate *priv);
132 static void modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
135 ModestUIPrivate *priv);
137 static void modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
138 const gchar* account_name,
142 ModestUIPrivate *priv);
144 static void modest_ui_actions_on_connection_changed (TnyDevice *device,
146 ModestUIPrivate *priv);
148 static void modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
149 ModestUIPrivate *priv);
151 static void modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
153 ModestUIPrivate *priv);
155 static void modest_ui_actions_on_header_status_update (ModestHeaderView *header_view,
159 ModestUIPrivate *priv);
161 static void modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview,
163 ModestUIPrivate *priv);
166 static void modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview,
168 ModestUIPrivate *priv);
170 static void modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview,
172 ModestUIPrivate *priv);
176 static const GtkActionEntry modest_action_entries [] = {
179 { "File", NULL, N_("_File") },
180 { "Edit", NULL, N_("_Edit") },
181 { "Actions", NULL, N_("_Actions") },
182 { "Options", NULL, N_("_Options") },
183 { "Help", NULL, N_("_Help") },
186 { "FileNew", GTK_STOCK_NEW, N_("_New"), "<CTRL>N", N_("Compose new message"), G_CALLBACK (modest_ui_actions_on_new_msg) },
187 { "FileOpen", GTK_STOCK_OPEN, N_("_Open"), "<CTRL>O", N_("Open a message"), NULL },
188 { "FileSave", GTK_STOCK_SAVE, N_("_Save"), "<CTRL>S", N_("Save a message"), NULL },
189 { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("Save _As"), NULL, N_("Save a message as"), NULL },
190 { "FileQuit", GTK_STOCK_QUIT, N_("_Quit"), "<CTRL>Q", N_("Exit the application"), G_CALLBACK (modest_ui_actions_on_quit) },
193 { "EditUndo", GTK_STOCK_UNDO, N_("_Undo"), "<CTRL>Z", N_("Undo last action"), NULL },
194 { "EditRedo", GTK_STOCK_REDO, N_("_Redo"), "<shift><CTRL>Z", N_("Redo previous action"), NULL },
195 { "EditCut", GTK_STOCK_CUT, N_("Cut"), "<CTRL>X", N_("_Cut"), NULL },
196 { "EditCopy", GTK_STOCK_COPY, N_("Copy"), "<CTRL>C", N_("Copy"), NULL },
197 { "EditPaste", GTK_STOCK_PASTE, N_("Paste"), "<CTRL>V", N_("Paste"), NULL },
198 { "EditDelete", GTK_STOCK_DELETE, N_("_Delete"), "<CTRL>Q", N_("Delete"), NULL },
199 { "EditSelectAll", NULL, N_("Select all"), "<CTRL>A", N_("Select all"), NULL },
200 { "EditDeselectAll", NULL, N_("Deselect all"), "<Shift><CTRL>A", N_("Deselect all"), NULL },
203 { "ActionsNew", MODEST_STOCK_MAIL_SEND, N_("_New Message"), NULL, N_("Compose a new message"), G_CALLBACK (modest_ui_actions_on_new_msg) },
204 { "ActionsReply", MODEST_STOCK_REPLY, N_("_Reply"), NULL, N_("Reply to a message"), G_CALLBACK (modest_ui_actions_on_reply) },
205 { "ActionsReplyAll", MODEST_STOCK_REPLY_ALL, N_("Reply to all"), NULL, N_("Reply to all"), G_CALLBACK (modest_ui_actions_on_reply_all) },
206 { "ActionsForward", MODEST_STOCK_FORWARD, N_("_Forward"), NULL, N_("Forward a message"), G_CALLBACK (modest_ui_actions_on_forward) },
207 { "ActionsBounce", NULL, N_("_Bounce"), NULL, N_("Bounce a message"), NULL },
208 { "ActionsSendReceive", MODEST_STOCK_SEND_RECEIVE, N_("Send/Receive"), NULL, N_("Send and receive messages"), NULL },
209 { "ActionsDelete", MODEST_STOCK_DELETE, N_("Delete message"), NULL, N_("Delete messages"), G_CALLBACK (modest_ui_actions_on_delete) },
212 { "GotoPrevious", MODEST_STOCK_PREV, N_("Previous"), NULL, N_("Go to previous message"), NULL },
213 { "GotoNext", MODEST_STOCK_NEXT, N_("Next"), NULL, N_("Go to next message"), G_CALLBACK (modest_ui_actions_on_next) },
216 { "OptionsAccounts", NULL, N_("_Accounts"), NULL, N_("Manage accounts"), G_CALLBACK (modest_ui_actions_on_accounts) },
217 { "OptionsContacts", NULL, N_("_Contacts"), NULL, N_("Manage contacts"), NULL },
220 { "HelpAbout", GTK_STOCK_ABOUT, N_("About"), NULL, N_("About Modest"), G_CALLBACK (modest_ui_actions_on_about) },
224 modest_ui_get_type (void)
226 static GType my_type = 0;
228 static const GTypeInfo my_info = {
229 sizeof(ModestUIClass),
230 NULL, /* base init */
231 NULL, /* base finalize */
232 (GClassInitFunc) modest_ui_class_init,
233 NULL, /* class finalize */
234 NULL, /* class data */
237 (GInstanceInitFunc) modest_ui_init,
240 my_type = g_type_register_static (G_TYPE_OBJECT,
249 modest_ui_class_init (ModestUIClass *klass)
251 GObjectClass *gobject_class;
252 gobject_class = (GObjectClass*) klass;
254 parent_class = g_type_class_peek_parent (klass);
255 gobject_class->finalize = modest_ui_finalize;
257 g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
263 modest_ui_init (ModestUI *obj)
265 ModestUIPrivate *priv;
267 priv = MODEST_UI_GET_PRIVATE(obj);
269 priv->widget_factory = NULL;
270 priv->main_window = NULL;
271 priv->account_store = NULL;
276 modest_ui_finalize (GObject *obj)
279 ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
281 if (priv->widget_factory) {
282 g_object_unref (G_OBJECT(priv->widget_factory));
283 priv->widget_factory = NULL;
286 G_OBJECT_CLASS(parent_class)->finalize (obj);
291 modest_ui_new (TnyAccountStore *account_store)
294 ModestUIPrivate *priv;
295 TnyPlatformFactory *fact;
296 ModestAccountMgr *account_mgr;
298 obj = g_object_new(MODEST_TYPE_UI, NULL);
299 priv = MODEST_UI_GET_PRIVATE(obj);
301 /* Get the platform-dependent instances */
302 fact = modest_tny_platform_factory_get_instance ();
304 priv->account_store = account_store;
306 account_mgr = modest_tny_platform_factory_get_modest_account_mgr_instance (fact);
308 g_printerr ("modest: could not create ModestAccountMgr instance\n");
309 g_object_unref (obj);
313 priv->widget_factory = modest_widget_factory_new ();
314 if (!priv->widget_factory) {
315 g_printerr ("modest: could not initialize widget factory\n");
319 /* Connect signals */
320 connect_signals (MODEST_UI (obj));
322 return MODEST_UI(obj);
326 on_main_window_destroy (GtkObject *widget, ModestUI *self)
328 /* FIXME: check if there any viewer/editing windows opened */
335 modest_ui_main_window (ModestUI *self)
337 ModestUIPrivate *priv;
338 GtkUIManager *ui_manager;
340 g_return_val_if_fail (self, NULL);
341 priv = MODEST_UI_GET_PRIVATE(self);
343 if (!priv->main_window) {
346 /* Register our own icons as stock icons in order to
347 use them with the UI manager */
348 register_stock_icons ();
350 /* Create UI manager */
351 ui_manager = create_ui_manager (self);
353 /* Create main window */
354 priv->main_window = modest_main_window_new (priv->widget_factory, ui_manager);
355 g_signal_connect (G_OBJECT(priv->main_window), "destroy",
356 G_CALLBACK(on_main_window_destroy), self);
358 /* Connect Main Window signals */
359 connect_main_window_signals (self);
361 g_object_unref (G_OBJECT (ui_manager));
364 if (!priv->main_window)
365 g_printerr ("modest: could not create main window\n");
367 return priv->main_window;
370 static GtkUIManager *
371 create_ui_manager (ModestUI *self)
373 GtkUIManager *ui_manager;
374 GtkActionGroup *action_group;
375 GError *error = NULL;
376 ModestUIPrivate *priv;
378 priv = MODEST_UI_GET_PRIVATE(self);
380 /* Create UI manager */
381 ui_manager = gtk_ui_manager_new();
383 /* Create action group */
384 action_group = gtk_action_group_new ("ModestMainWindowActions");
385 gtk_action_group_add_actions (action_group,
386 modest_action_entries,
387 G_N_ELEMENTS (modest_action_entries),
389 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
390 g_object_unref (action_group);
392 /* Load the UI definition */
393 gtk_ui_manager_add_ui_from_file (ui_manager, MODEST_UIDIR "modest-ui.xml", &error);
395 g_warning ("Could not merge modest-ui.xml: %s", error->message);
396 g_error_free (error);
402 * This function registers our custom toolbar icons, so they can be
403 * themed. The idea of this function was taken from the gtk-demo
406 register_stock_icons ()
408 static gboolean registered = FALSE;
412 GtkIconFactory *factory;
416 static GtkStockItem items[] = {
417 { MODEST_STOCK_MAIL_SEND, "send mail", 0, 0, NULL },
418 { MODEST_STOCK_NEW_MAIL, "new mail", 0, 0, NULL },
419 { MODEST_STOCK_SEND_RECEIVE, "send receive", 0, 0, NULL },
420 { MODEST_STOCK_REPLY, "reply", 0, 0, NULL },
421 { MODEST_STOCK_REPLY_ALL, "reply all", 0, 0, NULL },
422 { MODEST_STOCK_FORWARD, "forward", 0, 0, NULL },
423 { MODEST_STOCK_DELETE, "delete", 0, 0, NULL },
424 { MODEST_STOCK_NEXT, "next", 0, 0, NULL },
425 { MODEST_STOCK_PREV, "prev", 0, 0, NULL },
426 { MODEST_STOCK_STOP, "stop", 0, 0, NULL }
429 static gchar *items_names [] = {
430 MODEST_TOOLBAR_ICON_MAIL_SEND,
431 MODEST_TOOLBAR_ICON_NEW_MAIL,
432 MODEST_TOOLBAR_ICON_SEND_RECEIVE,
433 MODEST_TOOLBAR_ICON_REPLY,
434 MODEST_TOOLBAR_ICON_REPLY_ALL,
435 MODEST_TOOLBAR_ICON_FORWARD,
436 MODEST_TOOLBAR_ICON_DELETE,
437 MODEST_TOOLBAR_ICON_NEXT,
438 MODEST_TOOLBAR_ICON_PREV,
439 MODEST_TOOLBAR_ICON_STOP
444 /* Register our stock items */
445 gtk_stock_add (items, G_N_ELEMENTS (items));
447 /* Add our custom icon factory to the list of defaults */
448 factory = gtk_icon_factory_new ();
449 gtk_icon_factory_add_default (factory);
451 /* Register icons to accompany stock items */
452 for (i = 0; i < G_N_ELEMENTS (items); i++) {
454 pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
456 if (pixbuf != NULL) {
457 GtkIconSet *icon_set;
458 GdkPixbuf *transparent;
460 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
462 icon_set = gtk_icon_set_new_from_pixbuf (transparent);
463 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
464 gtk_icon_set_unref (icon_set);
465 g_object_unref (pixbuf);
466 g_object_unref (transparent);
469 g_warning ("failed to load %s icon", items_names[i]);
471 /* Drop our reference to the factory, GTK will hold a reference. */
472 g_object_unref (factory);
476 /* FIXME: uninit these as well */
478 connect_signals (ModestUI *self)
481 ModestUIPrivate *priv;
482 ModestFolderView *folder_view;
483 ModestHeaderView *header_view;
484 ModestMsgView *msg_view;
487 priv = MODEST_UI_GET_PRIVATE(self);
489 folder_view = modest_widget_factory_get_folder_view (priv->widget_factory);
490 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
491 msg_view = modest_widget_factory_get_msg_preview (priv->widget_factory);
492 toggle = modest_widget_factory_get_online_toggle (priv->widget_factory);
493 device = tny_account_store_get_device (priv->account_store);
496 g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
497 G_CALLBACK(modest_ui_actions_on_folder_selection_changed),
499 /* g_signal_connect (G_OBJECT(folder_view), "key-press-event", */
500 /* G_CALLBACK(on_folder_key_press_event), priv->widget_factory); */
503 g_signal_connect (G_OBJECT(header_view), "status_update",
504 G_CALLBACK(modest_ui_actions_on_header_status_update),
506 g_signal_connect (G_OBJECT(header_view), "header_selected",
507 G_CALLBACK(modest_ui_actions_on_header_selected),
509 g_signal_connect (G_OBJECT(header_view), "item_not_found",
510 G_CALLBACK(modest_ui_actions_on_item_not_found),
515 g_signal_connect (G_OBJECT(msg_view), "link_clicked",
516 G_CALLBACK(modest_ui_actions_on_msg_link_clicked),
518 g_signal_connect (G_OBJECT(msg_view), "link_hover",
519 G_CALLBACK(modest_ui_actions_on_msg_link_hover),
521 g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
522 G_CALLBACK(modest_ui_actions_on_msg_attachment_clicked),
526 g_signal_connect (G_OBJECT(device), "connection_changed",
527 G_CALLBACK(modest_ui_actions_on_connection_changed),
529 g_signal_connect (G_OBJECT(toggle), "toggled",
530 G_CALLBACK(modest_ui_actions_on_online_toggle_toggled),
533 /* Init toggle in correct state */
534 modest_ui_actions_on_connection_changed (device,
535 tny_device_is_online (device),
541 connect_main_window_signals (ModestUI *self)
543 ModestUIPrivate *priv;
545 priv = MODEST_UI_GET_PRIVATE(self);
548 g_signal_connect (G_OBJECT (priv->account_store),
549 "password_requested",
550 G_CALLBACK(modest_ui_actions_on_password_requested),
554 /* ***************************************************************** */
555 /* M O D E S T U I A C T I O N S */
556 /* ***************************************************************** */
558 modest_ui_actions_on_about (GtkWidget *widget,
559 ModestUIPrivate *priv)
562 const gchar *authors[] = {
563 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
566 about = gtk_about_dialog_new ();
567 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
568 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
569 gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
570 _("Copyright (c) 2006, Nokia Corporation\n"
571 "All rights reserved."));
572 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
573 _("a modest e-mail client\n\n"
574 "design and implementation: Dirk-Jan C. Binnema\n"
575 "contributions from the fine people at KernelConcepts and Igalia\n"
576 "uses the tinymail email framework written by Philip van Hoof"));
577 gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
578 gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
580 gtk_dialog_run (GTK_DIALOG (about));
581 gtk_widget_destroy(about);
585 modest_ui_actions_on_delete (GtkWidget *widget,
586 ModestUIPrivate *priv)
588 ModestWidgetFactory *widget_factory;
589 ModestHeaderView *header_view;
590 TnyList *header_list;
594 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
595 header_list = modest_header_view_get_selected_headers (header_view);
598 iter = tny_list_create_iterator (header_list);
599 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
600 if (GTK_IS_TREE_MODEL_SORT (model))
601 model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
604 ModestMailOperation *mail_op;
606 header = TNY_HEADER (tny_iterator_get_current (iter));
607 /* TODO: thick grain mail operation involving
608 a list of objects. Composite pattern ??? */
609 mail_op = modest_mail_operation_new ();
611 /* TODO: add confirmation dialog */
614 modest_mail_operation_remove_msg (mail_op, header, TRUE);
616 /* Remove from tree model */
617 if (modest_mail_operation_get_status (mail_op) ==
618 MODEST_MAIL_OPERATION_STATUS_SUCCESS)
619 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
621 /* TODO: error handling management */
623 error = modest_mail_operation_get_error (mail_op);
624 g_warning (error->message);
627 g_object_unref (G_OBJECT (mail_op));
628 g_object_unref (header);
629 tny_iterator_next (iter);
631 } while (!tny_iterator_is_done (iter));
636 modest_ui_actions_on_quit (GtkWidget *widget,
637 ModestUIPrivate *priv)
639 /* FIXME: save size of main window */
640 /* save_sizes (main_window); */
641 gtk_widget_destroy (GTK_WIDGET (priv->main_window));
645 modest_ui_actions_on_accounts (GtkWidget *widget,
646 ModestUIPrivate *priv)
648 GtkWidget *account_win;
650 account_win = modest_account_view_window_new (priv->widget_factory);
652 gtk_window_set_transient_for (GTK_WINDOW (account_win),
653 GTK_WINDOW (priv->main_window));
655 gtk_widget_show (account_win);
659 modest_ui_actions_on_new_msg (GtkWidget *widget,
660 ModestUIPrivate *priv)
664 msg_win = modest_edit_msg_window_new (priv->widget_factory,
665 MODEST_EDIT_TYPE_NEW);
666 gtk_widget_show (msg_win);
670 reply_forward_func (gpointer data, gpointer user_data)
672 TnyHeader *new_header;
673 TnyMsg *msg, *new_msg;
674 GetMsgAsyncHelper *helper;
675 ReplyForwardHelper *rf_helper;
677 ModestEditType edit_type;
679 msg = TNY_MSG (data);
680 helper = (GetMsgAsyncHelper *) user_data;
681 rf_helper = (ReplyForwardHelper *) helper->user_data;
683 /* Create reply mail */
684 switch (rf_helper->action) {
687 modest_mail_operation_create_reply_mail (msg,
689 rf_helper->reply_forward_type,
690 MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
691 case ACTION_REPLY_TO_ALL:
693 modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
694 MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
695 edit_type = MODEST_EDIT_TYPE_REPLY;
699 modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
700 edit_type = MODEST_EDIT_TYPE_FORWARD;
705 new_header = tny_msg_get_header (new_msg);
706 tny_header_set_from (new_header, rf_helper->from);
707 g_object_unref (G_OBJECT (new_header));
709 /* Show edit window */
710 msg_win = modest_edit_msg_window_new (helper->priv->widget_factory,
712 modest_edit_msg_window_set_msg (MODEST_EDIT_MSG_WINDOW (msg_win),
714 gtk_widget_show (msg_win);
717 g_object_unref (new_msg);
718 g_free (rf_helper->from);
719 g_slice_free (ReplyForwardHelper, rf_helper);
723 * Common code for the reply and forward actions
726 reply_forward (GtkWidget *widget,
727 ReplyForwardAction action,
728 ModestUIPrivate *priv)
730 ModestHeaderView *header_view;
731 TnyList *header_list;
732 guint reply_forward_type;
734 TnyPlatformFactory *plat_factory;
738 ModestFolderView *folder_view;
739 GetMsgAsyncHelper *helper;
740 ReplyForwardHelper *rf_helper;
743 plat_factory = modest_tny_platform_factory_get_instance ();
744 conf = modest_tny_platform_factory_get_modest_conf_instance (plat_factory);
746 /* Get reply or forward type */
747 key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE,
748 (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE);
749 reply_forward_type = modest_conf_get_int (conf, key, NULL);
752 /* Get the list of headers */
753 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
754 header_list = modest_header_view_get_selected_headers (header_view);
759 /* We assume that we can only select messages of the
760 same folder and that we reply all of them from the
761 same account. In fact the interface currently only
762 allows single selection */
764 /* TODO: get the from string from account */
765 from = g_strdup ("Invalid");
768 rf_helper = g_slice_new0 (ReplyForwardHelper);
769 rf_helper->reply_forward_type = reply_forward_type;
770 rf_helper->action = action;
771 rf_helper->from = from;
773 helper = g_slice_new0 (GetMsgAsyncHelper);
775 helper->func = reply_forward_func;
776 helper->iter = tny_list_create_iterator (header_list);
777 helper->user_data = rf_helper;
779 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
780 folder = tny_header_get_folder (header);
782 /* The callback will call it per each header */
783 tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
786 g_object_unref (G_OBJECT (folder));
790 modest_ui_actions_on_reply (GtkWidget *widget,
791 ModestUIPrivate *priv)
793 reply_forward (widget, ACTION_REPLY, priv);
797 modest_ui_actions_on_forward (GtkWidget *widget,
798 ModestUIPrivate *priv)
800 reply_forward (widget, ACTION_FORWARD, priv);
804 modest_ui_actions_on_reply_all (GtkWidget *widget,
805 ModestUIPrivate *priv)
807 reply_forward (widget, ACTION_REPLY_TO_ALL, priv);
811 modest_ui_actions_on_next (GtkWidget *widget,
812 ModestUIPrivate *priv)
814 ModestHeaderView *header_view;
816 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
817 modest_header_view_select_next (header_view);
821 * Marks a message as read and passes it to the msg preview widget
824 read_msg_func (gpointer data, gpointer user_data)
826 ModestMsgView *msg_view;
829 GetMsgAsyncHelper *helper;
830 TnyHeaderFlags header_flags;
832 msg = TNY_MSG (data);
833 helper = (GetMsgAsyncHelper *) user_data;
835 /* mark message as seen; _set_flags crashes, bug in tinymail? */
836 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
837 header_flags = tny_header_get_flags (header);
838 tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
839 g_object_unref (G_OBJECT (header));
841 /* Set message on msg view */
842 msg_view = modest_widget_factory_get_msg_preview (helper->priv->widget_factory);
843 modest_msg_view_set_message (msg_view, msg);
847 * This function is a generic handler for the tny_folder_get_msg_async
848 * call. It expects as user_data a #GetMsgAsyncHelper. This helper
849 * contains a user provided function that is called inside this
850 * method. This will allow us to use this callback in many different
851 * places. This callback performs the common actions for the
852 * get_msg_async call, more specific actions will be done by the user
856 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
858 GetMsgAsyncHelper *helper;
860 helper = (GetMsgAsyncHelper *) user_data;
862 if (*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) {
863 ModestHeaderView *header_view;
865 header_view = modest_widget_factory_get_header_view (helper->priv->widget_factory);
866 modest_ui_actions_on_item_not_found (header_view, MODEST_ITEM_TYPE_MESSAGE, helper->priv);
873 /* Call user function */
874 helper->func (msg, user_data);
876 /* Process next element (if exists) */
877 tny_iterator_next (helper->iter);
878 if (tny_iterator_is_done (helper->iter)) {
880 headers = tny_iterator_get_list (helper->iter);
882 g_object_unref (G_OBJECT (headers));
883 g_object_unref (G_OBJECT (helper->iter));
884 g_slice_free (GetMsgAsyncHelper, helper);
886 tny_folder_get_msg_async (folder,
887 TNY_HEADER (tny_iterator_get_current (helper->iter)),
892 modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,
894 ModestUIPrivate *priv)
897 GetMsgAsyncHelper *helper;
904 folder = tny_header_get_folder (TNY_HEADER(header));
907 list = tny_simple_list_new ();
908 tny_list_prepend (list, G_OBJECT (header));
910 /* Fill helper data */
911 helper = g_slice_new0 (GetMsgAsyncHelper);
913 helper->iter = tny_list_create_iterator (list);
914 helper->func = read_msg_func;
916 tny_folder_get_msg_async (TNY_FOLDER(folder),
922 g_object_unref (G_OBJECT (folder));
926 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
929 ModestUIPrivate *priv)
931 GtkLabel *folder_info_label;
932 TnyPlatformFactory *factory;
935 ModestHeaderView *header_view;
938 GTK_LABEL (modest_widget_factory_get_folder_info_label (priv->widget_factory));
941 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
945 factory = modest_tny_platform_factory_get_instance ();
946 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
947 conf = modest_tny_platform_factory_get_modest_conf_instance (factory);
949 if (!selected) { /* the folder was unselected; save it's settings */
950 modest_widget_memory_save (conf, G_OBJECT (header_view),
952 } else { /* the folder was selected */
954 num = tny_folder_get_all_count (folder);
955 unread = tny_folder_get_unread_count (folder);
957 txt = g_strdup_printf (_("%d %s, %d unread"),
958 num, num==1 ? _("item") : _("items"), unread);
959 gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
962 modest_header_view_set_folder (header_view, folder);
963 modest_widget_memory_restore (conf, G_OBJECT(header_view),
969 modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
970 const gchar* account_name,
974 ModestUIPrivate *priv)
977 GtkWidget *dialog, *entry, *remember_pass_check;
979 dialog = gtk_dialog_new_with_buttons (_("Password requested"),
980 GTK_WINDOW (priv->main_window),
988 txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
989 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
993 entry = gtk_entry_new_with_max_length (40);
994 gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
995 gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
997 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
1000 remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
1001 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
1004 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1006 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1007 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
1014 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
1019 gtk_widget_destroy (dialog);
1021 while (gtk_events_pending ())
1022 gtk_main_iteration ();
1025 /****************************************************/
1027 * below some stuff to clearup statusbar messages after 1,5 seconds....
1030 GtkWidget *status_bar;
1031 GtkWidget *progress_bar;
1036 on_statusbar_remove_msg (StatusRemoveData *data)
1038 /* we need to test types, as this callback maybe called after the
1039 * widgets have been destroyed
1041 if (GTK_IS_STATUSBAR(data->status_bar))
1042 gtk_statusbar_remove (GTK_STATUSBAR(data->status_bar),
1044 if (GTK_IS_PROGRESS_BAR(data->progress_bar))
1045 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(data->progress_bar),
1052 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
1055 StatusRemoveData *data;
1056 GtkWidget *status_bar, *progress_bar;
1061 progress_bar = modest_widget_factory_get_progress_bar (factory);
1062 status_bar = modest_widget_factory_get_status_bar (factory);
1064 id = gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
1066 data = g_new (StatusRemoveData, 1);
1067 data->status_bar = status_bar;
1068 data->progress_bar = progress_bar;
1071 g_timeout_add (1500, (GSourceFunc)on_statusbar_remove_msg, data);
1073 /****************************************************************************/
1076 modest_ui_actions_on_connection_changed (TnyDevice *device,
1078 ModestUIPrivate *priv)
1080 GtkWidget *online_toggle;
1081 ModestHeaderView *header_view;
1083 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
1084 online_toggle = modest_widget_factory_get_online_toggle (priv->widget_factory);
1086 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
1088 gtk_button_set_label (GTK_BUTTON(online_toggle),
1089 online ? _("Online") : _("Offline"));
1091 statusbar_push (priv->widget_factory, 0,
1092 online ? _("Modest went online") : _("Modest went offline"));
1094 /* If Modest has became online and the header view has a
1095 header selected then show it */
1097 GtkTreeSelection *selected;
1099 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1100 _modest_header_view_change_selection (selected, header_view);
1105 modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1106 ModestUIPrivate *priv)
1111 online = gtk_toggle_button_get_active (toggle);
1112 device = tny_account_store_get_device (priv->account_store);
1115 tny_device_force_online (device);
1117 tny_device_force_offline (device);
1121 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1122 ModestItemType type,
1123 ModestUIPrivate *priv)
1130 item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1131 device = tny_account_store_get_device (priv->account_store);
1133 gdk_threads_enter ();
1134 online = tny_device_is_online (device);
1137 /* already online -- the item is simply not there... */
1138 dialog = gtk_message_dialog_new (GTK_WINDOW (priv->main_window),
1140 GTK_MESSAGE_WARNING,
1142 _("The %s you selected cannot be found"),
1144 gtk_dialog_run (GTK_DIALOG(dialog));
1147 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1148 GTK_WINDOW (priv->main_window),
1151 GTK_RESPONSE_REJECT,
1153 GTK_RESPONSE_ACCEPT,
1156 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1157 "Do you want to get online?"), item);
1158 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1159 gtk_label_new (txt), FALSE, FALSE, 0);
1160 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1163 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1164 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1165 tny_device_force_online (device);
1168 gtk_widget_destroy (dialog);
1169 gdk_threads_leave ();
1173 modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, const gchar *msg,
1174 gint num, gint total, ModestUIPrivate *priv)
1176 GtkWidget *progress_bar;
1178 progress_bar = modest_widget_factory_get_progress_bar (priv->widget_factory);
1181 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1182 (gdouble)num/(gdouble)total);
1184 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1186 statusbar_push (priv->widget_factory, 0, msg);
1191 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
1192 ModestUIPrivate *priv)
1195 statusbar_push (priv->widget_factory, 0, link);
1197 /* TODO: do something */
1202 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
1203 ModestUIPrivate *priv)
1206 msg = g_strdup_printf (_("Opening %s..."), link);
1208 statusbar_push (priv->widget_factory, 0, msg);
1211 /* TODO: do something */
1215 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index,
1216 ModestUIPrivate *priv)
1220 msg = g_strdup_printf (_("Opening attachment %d..."), index);
1221 statusbar_push (priv->widget_factory, 0, msg);
1225 /* TODO: do something */