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-widget-memory.h>
50 #include "modest-edit-msg-window.h"
51 #include "modest-account-view-window.h"
52 #include "modest-icon-names.h"
53 #include "modest-main-window.h"
55 typedef struct _ModestUIPrivate ModestUIPrivate;
56 struct _ModestUIPrivate {
57 ModestWidgetFactory *widget_factory;
58 TnyAccountStore *account_store;
59 GtkWidget *main_window;
62 #define MODEST_UI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
66 typedef struct _GetMsgAsyncHelper {
67 ModestUIPrivate *priv;
73 typedef enum _ReplyForwardAction {
79 typedef struct _ReplyForwardHelper {
80 guint reply_forward_type;
81 ReplyForwardAction action;
86 static GObjectClass *parent_class = NULL;
88 /* 'private'/'protected' functions */
89 static void modest_ui_class_init (ModestUIClass *klass);
90 static void modest_ui_init (ModestUI *obj);
91 static void modest_ui_finalize (GObject *obj);
93 static void register_stock_icons ();
94 static void connect_signals (ModestUI *self);
95 static void connect_main_window_signals (ModestUI *self);
96 static GtkUIManager *create_ui_manager ();
98 static void reply_forward_func (gpointer data, gpointer user_data);
99 static void read_msg_func (gpointer data, gpointer user_data);
100 static void get_msg_cb (TnyFolder *folder,
105 static void reply_forward (GtkWidget *widget,
106 ReplyForwardAction action,
107 ModestUIPrivate *priv);
109 /* Menu & toolbar actions */
110 static void modest_ui_actions_on_about (GtkWidget *widget, ModestUIPrivate *priv);
112 static void modest_ui_actions_on_delete (GtkWidget *widget, ModestUIPrivate *priv);
114 static void modest_ui_actions_on_quit (GtkWidget *widget, ModestUIPrivate *priv);
116 static void modest_ui_actions_on_accounts (GtkWidget *widget, ModestUIPrivate *priv);
118 static void modest_ui_actions_on_new_msg (GtkWidget *widget, ModestUIPrivate *priv);
120 static void modest_ui_actions_on_reply (GtkWidget *widget, ModestUIPrivate *priv);
122 static void modest_ui_actions_on_forward (GtkWidget *widget, ModestUIPrivate *priv);
124 static void modest_ui_actions_on_reply_all (GtkWidget *widget, ModestUIPrivate *priv);
126 static void modest_ui_actions_on_next (GtkWidget *widget, ModestUIPrivate *priv);
129 static void modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,
131 ModestUIPrivate *priv);
133 static void modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
136 ModestUIPrivate *priv);
138 static void modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
139 const gchar* account_name,
143 ModestUIPrivate *priv);
145 static void modest_ui_actions_on_connection_changed (TnyDevice *device,
147 ModestUIPrivate *priv);
149 static void modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
150 ModestUIPrivate *priv);
152 static void modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
154 ModestUIPrivate *priv);
156 static void modest_ui_actions_on_header_status_update (ModestHeaderView *header_view,
160 ModestUIPrivate *priv);
162 static void modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview,
164 ModestUIPrivate *priv);
167 static void modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview,
169 ModestUIPrivate *priv);
171 static void modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview,
173 ModestUIPrivate *priv);
177 static const GtkActionEntry modest_action_entries [] = {
180 { "File", NULL, N_("_File") },
181 { "Edit", NULL, N_("_Edit") },
182 { "Actions", NULL, N_("_Actions") },
183 { "Options", NULL, N_("_Options") },
184 { "Help", NULL, N_("_Help") },
187 { "FileNew", GTK_STOCK_NEW, N_("_New"), "<CTRL>N", N_("Compose new message"), G_CALLBACK (modest_ui_actions_on_new_msg) },
188 { "FileOpen", GTK_STOCK_OPEN, N_("_Open"), "<CTRL>O", N_("Open a message"), NULL },
189 { "FileSave", GTK_STOCK_SAVE, N_("_Save"), "<CTRL>S", N_("Save a message"), NULL },
190 { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("Save _As"), NULL, N_("Save a message as"), NULL },
191 { "FileQuit", GTK_STOCK_QUIT, N_("_Quit"), "<CTRL>Q", N_("Exit the application"), G_CALLBACK (modest_ui_actions_on_quit) },
194 { "EditUndo", GTK_STOCK_UNDO, N_("_Undo"), "<CTRL>Z", N_("Undo last action"), NULL },
195 { "EditRedo", GTK_STOCK_REDO, N_("_Redo"), "<shift><CTRL>Z", N_("Redo previous action"), NULL },
196 { "EditCut", GTK_STOCK_CUT, N_("Cut"), "<CTRL>X", N_("_Cut"), NULL },
197 { "EditCopy", GTK_STOCK_COPY, N_("Copy"), "<CTRL>C", N_("Copy"), NULL },
198 { "EditPaste", GTK_STOCK_PASTE, N_("Paste"), "<CTRL>V", N_("Paste"), NULL },
199 { "EditDelete", GTK_STOCK_DELETE, N_("_Delete"), "<CTRL>Q", N_("Delete"), NULL },
200 { "EditSelectAll", NULL, N_("Select all"), "<CTRL>A", N_("Select all"), NULL },
201 { "EditDeselectAll", NULL, N_("Deselect all"), "<Shift><CTRL>A", N_("Deselect all"), NULL },
204 { "ActionsNew", MODEST_STOCK_MAIL_SEND, N_("_New Message"), NULL, N_("Compose a new message"), G_CALLBACK (modest_ui_actions_on_new_msg) },
205 { "ActionsReply", MODEST_STOCK_REPLY, N_("_Reply"), NULL, N_("Reply to a message"), G_CALLBACK (modest_ui_actions_on_reply) },
206 { "ActionsReplyAll", MODEST_STOCK_REPLY_ALL, N_("Reply to all"), NULL, N_("Reply to all"), G_CALLBACK (modest_ui_actions_on_reply_all) },
207 { "ActionsForward", MODEST_STOCK_FORWARD, N_("_Forward"), NULL, N_("Forward a message"), G_CALLBACK (modest_ui_actions_on_forward) },
208 { "ActionsBounce", NULL, N_("_Bounce"), NULL, N_("Bounce a message"), NULL },
209 { "ActionsSendReceive", MODEST_STOCK_SEND_RECEIVE, N_("Send/Receive"), NULL, N_("Send and receive messages"), NULL },
210 { "ActionsDelete", MODEST_STOCK_DELETE, N_("Delete message"), NULL, N_("Delete messages"), G_CALLBACK (modest_ui_actions_on_delete) },
213 { "GotoPrevious", MODEST_STOCK_PREV, N_("Previous"), NULL, N_("Go to previous message"), NULL },
214 { "GotoNext", MODEST_STOCK_NEXT, N_("Next"), NULL, N_("Go to next message"), G_CALLBACK (modest_ui_actions_on_next) },
217 { "OptionsAccounts", NULL, N_("_Accounts"), NULL, N_("Manage accounts"), G_CALLBACK (modest_ui_actions_on_accounts) },
218 { "OptionsContacts", NULL, N_("_Contacts"), NULL, N_("Manage contacts"), NULL },
221 { "HelpAbout", GTK_STOCK_ABOUT, N_("About"), NULL, N_("About Modest"), G_CALLBACK (modest_ui_actions_on_about) },
225 modest_ui_get_type (void)
227 static GType my_type = 0;
229 static const GTypeInfo my_info = {
230 sizeof(ModestUIClass),
231 NULL, /* base init */
232 NULL, /* base finalize */
233 (GClassInitFunc) modest_ui_class_init,
234 NULL, /* class finalize */
235 NULL, /* class data */
238 (GInstanceInitFunc) modest_ui_init,
241 my_type = g_type_register_static (G_TYPE_OBJECT,
250 modest_ui_class_init (ModestUIClass *klass)
252 GObjectClass *gobject_class;
253 gobject_class = (GObjectClass*) klass;
255 parent_class = g_type_class_peek_parent (klass);
256 gobject_class->finalize = modest_ui_finalize;
258 g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
264 modest_ui_init (ModestUI *obj)
266 ModestUIPrivate *priv;
268 priv = MODEST_UI_GET_PRIVATE(obj);
270 priv->widget_factory = NULL;
271 priv->main_window = NULL;
272 priv->account_store = NULL;
277 modest_ui_finalize (GObject *obj)
280 ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
282 if (priv->widget_factory) {
283 g_object_unref (G_OBJECT(priv->widget_factory));
284 priv->widget_factory = NULL;
287 G_OBJECT_CLASS(parent_class)->finalize (obj);
292 modest_ui_new (TnyAccountStore *account_store)
295 ModestUIPrivate *priv;
296 TnyPlatformFactory *fact;
297 ModestAccountMgr *account_mgr;
299 obj = g_object_new(MODEST_TYPE_UI, NULL);
300 priv = MODEST_UI_GET_PRIVATE(obj);
302 /* Get the platform-dependent instances */
303 fact = modest_tny_platform_factory_get_instance ();
305 priv->account_store = account_store;
307 account_mgr = modest_tny_platform_factory_get_modest_account_mgr_instance (fact);
309 g_printerr ("modest: could not create ModestAccountMgr instance\n");
310 g_object_unref (obj);
314 priv->widget_factory = modest_widget_factory_new ();
315 if (!priv->widget_factory) {
316 g_printerr ("modest: could not initialize widget factory\n");
320 /* Connect signals */
321 connect_signals (MODEST_UI (obj));
323 return MODEST_UI(obj);
327 on_main_window_destroy (GtkObject *widget, ModestUI *self)
329 /* FIXME: check if there any viewer/editing windows opened */
336 modest_ui_main_window (ModestUI *self)
338 ModestUIPrivate *priv;
339 GtkUIManager *ui_manager;
341 g_return_val_if_fail (self, NULL);
342 priv = MODEST_UI_GET_PRIVATE(self);
344 if (!priv->main_window) {
347 /* Register our own icons as stock icons in order to
348 use them with the UI manager */
349 register_stock_icons ();
351 /* Create UI manager */
352 ui_manager = create_ui_manager (self);
354 /* Create main window */
355 priv->main_window = modest_main_window_new (priv->widget_factory, ui_manager);
356 g_signal_connect (G_OBJECT(priv->main_window), "destroy",
357 G_CALLBACK(on_main_window_destroy), self);
359 /* Connect Main Window signals */
360 connect_main_window_signals (self);
362 g_object_unref (G_OBJECT (ui_manager));
365 if (!priv->main_window)
366 g_printerr ("modest: could not create main window\n");
368 return priv->main_window;
371 static GtkUIManager *
372 create_ui_manager (ModestUI *self)
374 GtkUIManager *ui_manager;
375 GtkActionGroup *action_group;
376 GError *error = NULL;
377 ModestUIPrivate *priv;
379 priv = MODEST_UI_GET_PRIVATE(self);
381 /* Create UI manager */
382 ui_manager = gtk_ui_manager_new();
384 /* Create action group */
385 action_group = gtk_action_group_new ("ModestMainWindowActions");
386 gtk_action_group_add_actions (action_group,
387 modest_action_entries,
388 G_N_ELEMENTS (modest_action_entries),
390 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
391 g_object_unref (action_group);
393 /* Load the UI definition */
394 gtk_ui_manager_add_ui_from_file (ui_manager, MODEST_UIDIR "modest-ui.xml", &error);
396 g_warning ("Could not merge modest-ui.xml: %s", error->message);
397 g_error_free (error);
403 * This function registers our custom toolbar icons, so they can be
404 * themed. The idea of this function was taken from the gtk-demo
407 register_stock_icons ()
409 static gboolean registered = FALSE;
413 GtkIconFactory *factory;
417 static GtkStockItem items[] = {
418 { MODEST_STOCK_MAIL_SEND, "send mail", 0, 0, NULL },
419 { MODEST_STOCK_NEW_MAIL, "new mail", 0, 0, NULL },
420 { MODEST_STOCK_SEND_RECEIVE, "send receive", 0, 0, NULL },
421 { MODEST_STOCK_REPLY, "reply", 0, 0, NULL },
422 { MODEST_STOCK_REPLY_ALL, "reply all", 0, 0, NULL },
423 { MODEST_STOCK_FORWARD, "forward", 0, 0, NULL },
424 { MODEST_STOCK_DELETE, "delete", 0, 0, NULL },
425 { MODEST_STOCK_NEXT, "next", 0, 0, NULL },
426 { MODEST_STOCK_PREV, "prev", 0, 0, NULL },
427 { MODEST_STOCK_STOP, "stop", 0, 0, NULL }
430 static gchar *items_names [] = {
431 MODEST_TOOLBAR_ICON_MAIL_SEND,
432 MODEST_TOOLBAR_ICON_NEW_MAIL,
433 MODEST_TOOLBAR_ICON_SEND_RECEIVE,
434 MODEST_TOOLBAR_ICON_REPLY,
435 MODEST_TOOLBAR_ICON_REPLY_ALL,
436 MODEST_TOOLBAR_ICON_FORWARD,
437 MODEST_TOOLBAR_ICON_DELETE,
438 MODEST_TOOLBAR_ICON_NEXT,
439 MODEST_TOOLBAR_ICON_PREV,
440 MODEST_TOOLBAR_ICON_STOP
445 /* Register our stock items */
446 gtk_stock_add (items, G_N_ELEMENTS (items));
448 /* Add our custom icon factory to the list of defaults */
449 factory = gtk_icon_factory_new ();
450 gtk_icon_factory_add_default (factory);
452 /* Register icons to accompany stock items */
453 for (i = 0; i < G_N_ELEMENTS (items); i++) {
455 pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
457 if (pixbuf != NULL) {
458 GtkIconSet *icon_set;
459 GdkPixbuf *transparent;
461 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
463 icon_set = gtk_icon_set_new_from_pixbuf (transparent);
464 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
465 gtk_icon_set_unref (icon_set);
466 g_object_unref (pixbuf);
467 g_object_unref (transparent);
470 g_warning ("failed to load %s icon", items_names[i]);
472 /* Drop our reference to the factory, GTK will hold a reference. */
473 g_object_unref (factory);
477 /* FIXME: uninit these as well */
479 connect_signals (ModestUI *self)
482 ModestUIPrivate *priv;
483 ModestFolderView *folder_view;
484 ModestHeaderView *header_view;
485 ModestMsgView *msg_view;
488 priv = MODEST_UI_GET_PRIVATE(self);
490 folder_view = modest_widget_factory_get_folder_view (priv->widget_factory);
491 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
492 msg_view = modest_widget_factory_get_msg_preview (priv->widget_factory);
493 toggle = modest_widget_factory_get_online_toggle (priv->widget_factory);
494 device = tny_account_store_get_device (priv->account_store);
497 g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
498 G_CALLBACK(modest_ui_actions_on_folder_selection_changed),
500 /* g_signal_connect (G_OBJECT(folder_view), "key-press-event", */
501 /* G_CALLBACK(on_folder_key_press_event), priv->widget_factory); */
504 g_signal_connect (G_OBJECT(header_view), "status_update",
505 G_CALLBACK(modest_ui_actions_on_header_status_update),
507 g_signal_connect (G_OBJECT(header_view), "header_selected",
508 G_CALLBACK(modest_ui_actions_on_header_selected),
510 g_signal_connect (G_OBJECT(header_view), "item_not_found",
511 G_CALLBACK(modest_ui_actions_on_item_not_found),
516 g_signal_connect (G_OBJECT(msg_view), "link_clicked",
517 G_CALLBACK(modest_ui_actions_on_msg_link_clicked),
519 g_signal_connect (G_OBJECT(msg_view), "link_hover",
520 G_CALLBACK(modest_ui_actions_on_msg_link_hover),
522 g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
523 G_CALLBACK(modest_ui_actions_on_msg_attachment_clicked),
527 g_signal_connect (G_OBJECT(device), "connection_changed",
528 G_CALLBACK(modest_ui_actions_on_connection_changed),
530 g_signal_connect (G_OBJECT(toggle), "toggled",
531 G_CALLBACK(modest_ui_actions_on_online_toggle_toggled),
534 /* Init toggle in correct state */
535 modest_ui_actions_on_connection_changed (device,
536 tny_device_is_online (device),
542 connect_main_window_signals (ModestUI *self)
544 ModestUIPrivate *priv;
546 priv = MODEST_UI_GET_PRIVATE(self);
549 g_signal_connect (G_OBJECT (priv->account_store),
550 "password_requested",
551 G_CALLBACK(modest_ui_actions_on_password_requested),
555 /* ***************************************************************** */
556 /* M O D E S T U I A C T I O N S */
557 /* ***************************************************************** */
559 modest_ui_actions_on_about (GtkWidget *widget,
560 ModestUIPrivate *priv)
563 const gchar *authors[] = {
564 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
567 about = gtk_about_dialog_new ();
568 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
569 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
570 gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
571 _("Copyright (c) 2006, Nokia Corporation\n"
572 "All rights reserved."));
573 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
574 _("a modest e-mail client\n\n"
575 "design and implementation: Dirk-Jan C. Binnema\n"
576 "contributions from the fine people at KernelConcepts and Igalia\n"
577 "uses the tinymail email framework written by Philip van Hoof"));
578 gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
579 gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
581 gtk_dialog_run (GTK_DIALOG (about));
582 gtk_widget_destroy(about);
586 modest_ui_actions_on_delete (GtkWidget *widget,
587 ModestUIPrivate *priv)
589 ModestWidgetFactory *widget_factory;
590 ModestHeaderView *header_view;
591 TnyList *header_list;
595 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
596 header_list = modest_header_view_get_selected_headers (header_view);
599 iter = tny_list_create_iterator (header_list);
600 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
601 if (GTK_IS_TREE_MODEL_SORT (model))
602 model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
605 ModestMailOperation *mail_op;
607 header = TNY_HEADER (tny_iterator_get_current (iter));
608 /* TODO: thick grain mail operation involving
609 a list of objects. Composite pattern ??? */
610 mail_op = modest_mail_operation_new ();
612 /* TODO: add confirmation dialog */
615 modest_mail_operation_remove_msg (mail_op, header, TRUE);
617 /* Remove from tree model */
618 if (modest_mail_operation_get_status (mail_op) ==
619 MODEST_MAIL_OPERATION_STATUS_SUCCESS)
620 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
622 /* TODO: error handling management */
624 error = modest_mail_operation_get_error (mail_op);
625 g_warning (error->message);
628 g_object_unref (G_OBJECT (mail_op));
629 g_object_unref (header);
630 tny_iterator_next (iter);
632 } while (!tny_iterator_is_done (iter));
637 modest_ui_actions_on_quit (GtkWidget *widget,
638 ModestUIPrivate *priv)
640 /* FIXME: save size of main window */
641 /* save_sizes (main_window); */
642 gtk_widget_destroy (GTK_WIDGET (priv->main_window));
646 modest_ui_actions_on_accounts (GtkWidget *widget,
647 ModestUIPrivate *priv)
649 GtkWidget *account_win;
651 account_win = modest_account_view_window_new (priv->widget_factory);
653 gtk_window_set_transient_for (GTK_WINDOW (account_win),
654 GTK_WINDOW (priv->main_window));
656 gtk_widget_show (account_win);
660 modest_ui_actions_on_new_msg (GtkWidget *widget,
661 ModestUIPrivate *priv)
665 msg_win = modest_edit_msg_window_new (priv->widget_factory,
666 MODEST_EDIT_TYPE_NEW);
667 gtk_widget_show (msg_win);
671 reply_forward_func (gpointer data, gpointer user_data)
673 TnyHeader *new_header;
674 TnyMsg *msg, *new_msg;
675 GetMsgAsyncHelper *helper;
676 ReplyForwardHelper *rf_helper;
678 ModestEditType edit_type;
680 msg = TNY_MSG (data);
681 helper = (GetMsgAsyncHelper *) user_data;
682 rf_helper = (ReplyForwardHelper *) helper->user_data;
684 /* Create reply mail */
685 switch (rf_helper->action) {
688 modest_mail_operation_create_reply_mail (msg,
690 rf_helper->reply_forward_type,
691 MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
692 case ACTION_REPLY_TO_ALL:
694 modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
695 MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
696 edit_type = MODEST_EDIT_TYPE_REPLY;
700 modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
701 edit_type = MODEST_EDIT_TYPE_FORWARD;
706 new_header = tny_msg_get_header (new_msg);
707 tny_header_set_from (new_header, rf_helper->from);
708 g_object_unref (G_OBJECT (new_header));
710 /* Show edit window */
711 msg_win = modest_edit_msg_window_new (helper->priv->widget_factory,
713 modest_edit_msg_window_set_msg (MODEST_EDIT_MSG_WINDOW (msg_win),
715 gtk_widget_show (msg_win);
718 g_object_unref (new_msg);
719 g_free (rf_helper->from);
720 g_slice_free (ReplyForwardHelper, rf_helper);
724 * Common code for the reply and forward actions
727 reply_forward (GtkWidget *widget,
728 ReplyForwardAction action,
729 ModestUIPrivate *priv)
731 ModestHeaderView *header_view;
732 TnyList *header_list;
733 guint reply_forward_type;
735 TnyPlatformFactory *plat_factory;
739 ModestFolderView *folder_view;
740 GetMsgAsyncHelper *helper;
741 ReplyForwardHelper *rf_helper;
744 plat_factory = modest_tny_platform_factory_get_instance ();
745 conf = modest_tny_platform_factory_get_modest_conf_instance (plat_factory);
747 /* Get reply or forward type */
748 key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE,
749 (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE);
750 reply_forward_type = modest_conf_get_int (conf, key, NULL);
753 /* Get the list of headers */
754 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
755 header_list = modest_header_view_get_selected_headers (header_view);
760 /* We assume that we can only select messages of the
761 same folder and that we reply all of them from the
762 same account. In fact the interface currently only
763 allows single selection */
765 /* TODO: get the from string from account */
766 from = g_strdup ("Invalid");
769 rf_helper = g_slice_new0 (ReplyForwardHelper);
770 rf_helper->reply_forward_type = reply_forward_type;
771 rf_helper->action = action;
772 rf_helper->from = from;
774 helper = g_slice_new0 (GetMsgAsyncHelper);
776 helper->func = reply_forward_func;
777 helper->iter = tny_list_create_iterator (header_list);
778 helper->user_data = rf_helper;
780 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
781 folder = tny_header_get_folder (header);
783 /* The callback will call it per each header */
784 tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
787 g_object_unref (G_OBJECT (folder));
791 modest_ui_actions_on_reply (GtkWidget *widget,
792 ModestUIPrivate *priv)
794 reply_forward (widget, ACTION_REPLY, priv);
798 modest_ui_actions_on_forward (GtkWidget *widget,
799 ModestUIPrivate *priv)
801 reply_forward (widget, ACTION_FORWARD, priv);
805 modest_ui_actions_on_reply_all (GtkWidget *widget,
806 ModestUIPrivate *priv)
808 reply_forward (widget, ACTION_REPLY_TO_ALL, priv);
812 modest_ui_actions_on_next (GtkWidget *widget,
813 ModestUIPrivate *priv)
815 ModestHeaderView *header_view;
817 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
818 modest_header_view_select_next (header_view);
822 * Marks a message as read and passes it to the msg preview widget
825 read_msg_func (gpointer data, gpointer user_data)
827 ModestMsgView *msg_view;
830 GetMsgAsyncHelper *helper;
831 TnyHeaderFlags header_flags;
833 msg = TNY_MSG (data);
834 helper = (GetMsgAsyncHelper *) user_data;
836 /* mark message as seen; _set_flags crashes, bug in tinymail? */
837 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
838 header_flags = tny_header_get_flags (header);
839 tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
840 g_object_unref (G_OBJECT (header));
842 /* Set message on msg view */
843 msg_view = modest_widget_factory_get_msg_preview (helper->priv->widget_factory);
844 modest_msg_view_set_message (msg_view, msg);
848 * This function is a generic handler for the tny_folder_get_msg_async
849 * call. It expects as user_data a #GetMsgAsyncHelper. This helper
850 * contains a user provided function that is called inside this
851 * method. This will allow us to use this callback in many different
852 * places. This callback performs the common actions for the
853 * get_msg_async call, more specific actions will be done by the user
857 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
859 GetMsgAsyncHelper *helper;
861 helper = (GetMsgAsyncHelper *) user_data;
863 if (*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) {
864 ModestHeaderView *header_view;
866 header_view = modest_widget_factory_get_header_view (helper->priv->widget_factory);
867 modest_ui_actions_on_item_not_found (header_view, MODEST_ITEM_TYPE_MESSAGE, helper->priv);
874 /* Call user function */
875 helper->func (msg, user_data);
877 /* Process next element (if exists) */
878 tny_iterator_next (helper->iter);
879 if (tny_iterator_is_done (helper->iter)) {
881 headers = tny_iterator_get_list (helper->iter);
883 g_object_unref (G_OBJECT (headers));
884 g_object_unref (G_OBJECT (helper->iter));
885 g_slice_free (GetMsgAsyncHelper, helper);
887 tny_folder_get_msg_async (folder,
888 TNY_HEADER (tny_iterator_get_current (helper->iter)),
893 modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,
895 ModestUIPrivate *priv)
898 GetMsgAsyncHelper *helper;
905 folder = tny_header_get_folder (TNY_HEADER(header));
908 list = tny_simple_list_new ();
909 tny_list_prepend (list, G_OBJECT (header));
911 /* Fill helper data */
912 helper = g_slice_new0 (GetMsgAsyncHelper);
914 helper->iter = tny_list_create_iterator (list);
915 helper->func = read_msg_func;
917 tny_folder_get_msg_async (TNY_FOLDER(folder),
923 g_object_unref (G_OBJECT (folder));
927 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
930 ModestUIPrivate *priv)
932 GtkLabel *folder_info_label;
933 TnyPlatformFactory *factory;
936 ModestHeaderView *header_view;
939 GTK_LABEL (modest_widget_factory_get_folder_info_label (priv->widget_factory));
942 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
946 factory = modest_tny_platform_factory_get_instance ();
947 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
948 conf = modest_tny_platform_factory_get_modest_conf_instance (factory);
950 if (!selected) { /* the folder was unselected; save it's settings */
951 modest_widget_memory_save (conf, G_OBJECT (header_view),
953 } else { /* the folder was selected */
955 num = tny_folder_get_all_count (folder);
956 unread = tny_folder_get_unread_count (folder);
958 txt = g_strdup_printf (_("%d %s, %d unread"),
959 num, num==1 ? _("item") : _("items"), unread);
960 gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
963 modest_header_view_set_folder (header_view, folder);
964 modest_widget_memory_restore (conf, G_OBJECT(header_view),
970 modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
971 const gchar* account_name,
975 ModestUIPrivate *priv)
978 GtkWidget *dialog, *entry, *remember_pass_check;
980 dialog = gtk_dialog_new_with_buttons (_("Password requested"),
981 GTK_WINDOW (priv->main_window),
989 txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
990 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
994 entry = gtk_entry_new_with_max_length (40);
995 gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
996 gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
998 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
1001 remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
1002 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
1005 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1007 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1008 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
1015 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
1020 gtk_widget_destroy (dialog);
1022 while (gtk_events_pending ())
1023 gtk_main_iteration ();
1026 /****************************************************/
1028 * below some stuff to clearup statusbar messages after 1,5 seconds....
1031 GtkWidget *status_bar;
1032 GtkWidget *progress_bar;
1037 on_statusbar_remove_msg (StatusRemoveData *data)
1039 /* we need to test types, as this callback maybe called after the
1040 * widgets have been destroyed
1042 if (GTK_IS_STATUSBAR(data->status_bar))
1043 gtk_statusbar_remove (GTK_STATUSBAR(data->status_bar),
1045 if (GTK_IS_PROGRESS_BAR(data->progress_bar))
1046 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(data->progress_bar),
1053 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
1056 StatusRemoveData *data;
1057 GtkWidget *status_bar, *progress_bar;
1062 progress_bar = modest_widget_factory_get_progress_bar (factory);
1063 status_bar = modest_widget_factory_get_status_bar (factory);
1065 id = gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
1067 data = g_new (StatusRemoveData, 1);
1068 data->status_bar = status_bar;
1069 data->progress_bar = progress_bar;
1072 g_timeout_add (1500, (GSourceFunc)on_statusbar_remove_msg, data);
1074 /****************************************************************************/
1077 modest_ui_actions_on_connection_changed (TnyDevice *device,
1079 ModestUIPrivate *priv)
1081 GtkWidget *online_toggle;
1082 ModestHeaderView *header_view;
1084 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
1085 online_toggle = modest_widget_factory_get_online_toggle (priv->widget_factory);
1087 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
1089 gtk_button_set_label (GTK_BUTTON(online_toggle),
1090 online ? _("Online") : _("Offline"));
1092 statusbar_push (priv->widget_factory, 0,
1093 online ? _("Modest went online") : _("Modest went offline"));
1095 /* If Modest has became online and the header view has a
1096 header selected then show it */
1098 GtkTreeSelection *selected;
1100 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1101 _modest_header_view_change_selection (selected, header_view);
1106 modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1107 ModestUIPrivate *priv)
1112 online = gtk_toggle_button_get_active (toggle);
1113 device = tny_account_store_get_device (priv->account_store);
1116 tny_device_force_online (device);
1118 tny_device_force_offline (device);
1122 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1123 ModestItemType type,
1124 ModestUIPrivate *priv)
1131 item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1132 device = tny_account_store_get_device (priv->account_store);
1134 gdk_threads_enter ();
1135 online = tny_device_is_online (device);
1138 /* already online -- the item is simply not there... */
1139 dialog = gtk_message_dialog_new (GTK_WINDOW (priv->main_window),
1141 GTK_MESSAGE_WARNING,
1143 _("The %s you selected cannot be found"),
1145 gtk_dialog_run (GTK_DIALOG(dialog));
1148 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1149 GTK_WINDOW (priv->main_window),
1152 GTK_RESPONSE_REJECT,
1154 GTK_RESPONSE_ACCEPT,
1157 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1158 "Do you want to get online?"), item);
1159 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1160 gtk_label_new (txt), FALSE, FALSE, 0);
1161 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1164 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1165 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1166 tny_device_force_online (device);
1169 gtk_widget_destroy (dialog);
1170 gdk_threads_leave ();
1174 modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, const gchar *msg,
1175 gint num, gint total, ModestUIPrivate *priv)
1177 GtkWidget *progress_bar;
1179 progress_bar = modest_widget_factory_get_progress_bar (priv->widget_factory);
1182 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1183 (gdouble)num/(gdouble)total);
1185 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1187 statusbar_push (priv->widget_factory, 0, msg);
1192 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
1193 ModestUIPrivate *priv)
1196 statusbar_push (priv->widget_factory, 0, link);
1198 /* TODO: do something */
1203 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
1204 ModestUIPrivate *priv)
1207 msg = g_strdup_printf (_("Opening %s..."), link);
1209 statusbar_push (priv->widget_factory, 0, msg);
1212 /* TODO: do something */
1216 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index,
1217 ModestUIPrivate *priv)
1221 msg = g_strdup_printf (_("Opening attachment %d..."), index);
1222 statusbar_push (priv->widget_factory, 0, msg);
1226 /* TODO: do something */