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-ui-priv.h"
37 #include "modest-ui.h"
38 #include "modest-ui-actions.h"
39 #include "modest-icon-names.h"
40 #include "modest-tny-platform-factory.h"
41 #include "modest-account-view-window.h"
42 #include "modest-account-mgr-helpers.h"
43 #include "modest-main-window.h"
44 #include "modest-mail-operation.h"
45 #include <modest-widget-memory.h>
46 #include <tny-error.h>
47 #include <tny-simple-list.h>
48 #include <tny-msg-view.h>
49 #include <tny-device.h>
51 #define MODEST_UI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
55 typedef struct _GetMsgAsyncHelper {
56 ModestMainWindow *main_window;
62 typedef enum _ReplyForwardAction {
68 typedef struct _ReplyForwardHelper {
69 guint reply_forward_type;
70 ReplyForwardAction action;
75 static GObjectClass *parent_class = NULL;
77 /* 'private'/'protected' functions */
78 static void modest_ui_class_init (ModestUIClass *klass);
79 static void modest_ui_init (ModestUI *obj);
80 static void modest_ui_finalize (GObject *obj);
82 static void register_stock_icons ();
83 static void connect_signals (ModestUI *self);
85 static void reply_forward_func (gpointer data,
87 static void read_msg_func (gpointer data,
89 static void get_msg_cb (TnyFolder *folder,
94 static void reply_forward (GtkWidget *widget,
95 ReplyForwardAction action,
96 ModestMainWindow *main_window);
98 static gchar* ask_for_folder_name (GtkWindow *parent_window,
102 modest_ui_get_type (void)
104 static GType my_type = 0;
106 static const GTypeInfo my_info = {
107 sizeof(ModestUIClass),
108 NULL, /* base init */
109 NULL, /* base finalize */
110 (GClassInitFunc) modest_ui_class_init,
111 NULL, /* class finalize */
112 NULL, /* class data */
115 (GInstanceInitFunc) modest_ui_init,
118 my_type = g_type_register_static (G_TYPE_OBJECT,
127 modest_ui_class_init (ModestUIClass *klass)
129 GObjectClass *gobject_class;
130 gobject_class = (GObjectClass*) klass;
132 parent_class = g_type_class_peek_parent (klass);
133 gobject_class->finalize = modest_ui_finalize;
135 g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
141 modest_ui_init (ModestUI *obj)
143 ModestUIPrivate *priv;
145 priv = MODEST_UI_GET_PRIVATE(obj);
147 priv->widget_factory = NULL;
148 priv->main_window = NULL;
149 priv->account_store = NULL;
154 modest_ui_finalize (GObject *obj)
156 ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
158 if (priv->widget_factory) {
159 g_object_unref (G_OBJECT(priv->widget_factory));
160 priv->widget_factory = NULL;
163 if (priv->ui_manager) {
164 g_object_unref (G_OBJECT(priv->ui_manager));
165 priv->ui_manager = NULL;
168 G_OBJECT_CLASS(parent_class)->finalize (obj);
173 modest_ui_new (TnyAccountStore *account_store)
176 ModestUIPrivate *priv;
177 TnyPlatformFactory *fact;
178 ModestAccountMgr *account_mgr;
180 obj = g_object_new(MODEST_TYPE_UI, NULL);
181 priv = MODEST_UI_GET_PRIVATE(obj);
183 /* Get the platform-dependent instances */
184 fact = modest_tny_platform_factory_get_instance ();
186 priv->account_store = account_store;
188 account_mgr = modest_tny_platform_factory_get_account_mgr_instance
189 (MODEST_TNY_PLATFORM_FACTORY(fact));
191 g_printerr ("modest: could not create ModestAccountMgr instance\n");
192 g_object_unref (obj);
196 priv->widget_factory = modest_widget_factory_new ();
197 if (!priv->widget_factory) {
198 g_printerr ("modest: could not initialize widget factory\n");
202 /* Register our own icons as stock icons in order to
203 use them with the UI manager */
204 register_stock_icons ();
206 return MODEST_UI(obj);
210 on_main_window_destroy (GtkObject *widget, ModestUI *self)
212 /* FIXME: check if there any viewer/editing windows opened */
219 modest_ui_main_window (ModestUI *self)
221 ModestUIPrivate *priv;
223 g_return_val_if_fail (self, NULL);
224 priv = MODEST_UI_GET_PRIVATE(self);
226 if (!priv->main_window) {
228 /* Create main window */
229 priv->main_window = modest_main_window_new (priv->widget_factory,
230 priv->account_store);
232 connect_signals (self);
235 if (!priv->main_window)
236 g_printerr ("modest: could not create main window\n");
238 return priv->main_window;
242 modest_ui_edit_window (ModestUI *self, ModestEditType edit_type)
244 ModestUIPrivate *priv;
245 ModestWindow *edit_window;
247 g_return_val_if_fail (self, NULL);
248 priv = MODEST_UI_GET_PRIVATE(self);
251 edit_window = modest_edit_msg_window_new (priv->widget_factory,
255 /* Connect Edit Window signals */
256 /* connect_edit_window_signals (self); */
262 * This function registers our custom toolbar icons, so they can be
263 * themed. The idea of this function was taken from the gtk-demo
266 register_stock_icons ()
268 static gboolean registered = FALSE;
272 GtkIconFactory *factory;
275 static GtkStockItem items[] = {
276 { MODEST_STOCK_MAIL_SEND, "send mail", 0, 0, NULL },
277 { MODEST_STOCK_NEW_MAIL, "new mail", 0, 0, NULL },
278 { MODEST_STOCK_SEND_RECEIVE, "send receive", 0, 0, NULL },
279 { MODEST_STOCK_REPLY, "reply", 0, 0, NULL },
280 { MODEST_STOCK_REPLY_ALL, "reply all", 0, 0, NULL },
281 { MODEST_STOCK_FORWARD, "forward", 0, 0, NULL },
282 { MODEST_STOCK_DELETE, "delete", 0, 0, NULL },
283 { MODEST_STOCK_NEXT, "next", 0, 0, NULL },
284 { MODEST_STOCK_PREV, "prev", 0, 0, NULL },
285 /* { MODEST_STOCK_STOP, "stop", 0, 0, NULL } */
288 static gchar *items_names [] = {
289 MODEST_TOOLBAR_ICON_MAIL_SEND,
290 MODEST_TOOLBAR_ICON_NEW_MAIL,
291 MODEST_TOOLBAR_ICON_SEND_RECEIVE,
292 MODEST_TOOLBAR_ICON_REPLY,
293 MODEST_TOOLBAR_ICON_REPLY_ALL,
294 MODEST_TOOLBAR_ICON_FORWARD,
295 MODEST_TOOLBAR_ICON_DELETE,
296 MODEST_TOOLBAR_ICON_NEXT,
297 MODEST_TOOLBAR_ICON_PREV,
298 /* MODEST_TOOLBAR_ICON_STOP */
303 /* Register our stock items */
304 gtk_stock_add (items, G_N_ELEMENTS (items));
306 /* Add our custom icon factory to the list of defaults */
307 factory = gtk_icon_factory_new ();
308 gtk_icon_factory_add_default (factory);
310 /* Register icons to accompany stock items */
311 for (i = 0; i < G_N_ELEMENTS (items); i++) {
313 pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
315 if (pixbuf != NULL) {
316 GtkIconSet *icon_set;
317 GdkPixbuf *transparent;
319 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
321 icon_set = gtk_icon_set_new_from_pixbuf (transparent);
322 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
323 gtk_icon_set_unref (icon_set);
324 g_object_unref (pixbuf);
325 g_object_unref (transparent);
328 g_warning ("failed to load %s icon", items_names[i]);
330 /* Drop our reference to the factory, GTK will hold a reference. */
331 g_object_unref (factory);
335 /* FIXME: uninit these as well */
337 connect_signals (ModestUI *self)
340 ModestUIPrivate *priv;
341 ModestFolderView *folder_view;
342 ModestHeaderView *header_view;
343 ModestMsgView *msg_view;
346 priv = MODEST_UI_GET_PRIVATE(self);
348 folder_view = modest_widget_factory_get_folder_view (priv->widget_factory);
349 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
350 msg_view = modest_widget_factory_get_msg_preview (priv->widget_factory);
351 toggle = modest_widget_factory_get_online_toggle (priv->widget_factory);
352 device = tny_account_store_get_device (priv->account_store);
355 g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
356 G_CALLBACK(_modest_ui_actions_on_folder_selection_changed),
359 g_signal_connect (G_OBJECT(header_view), "status_update",
360 G_CALLBACK(_modest_ui_actions_on_header_status_update),
362 g_signal_connect (G_OBJECT(header_view), "header_selected",
363 G_CALLBACK(_modest_ui_actions_on_header_selected),
365 g_signal_connect (G_OBJECT(header_view), "item_not_found",
366 G_CALLBACK(_modest_ui_actions_on_item_not_found),
369 g_signal_connect (G_OBJECT(msg_view), "link_clicked",
370 G_CALLBACK(_modest_ui_actions_on_msg_link_clicked),
372 g_signal_connect (G_OBJECT(msg_view), "link_hover",
373 G_CALLBACK(_modest_ui_actions_on_msg_link_hover),
375 g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
376 G_CALLBACK(_modest_ui_actions_on_msg_attachment_clicked),
380 g_signal_connect (G_OBJECT(device), "connection_changed",
381 G_CALLBACK(_modest_ui_actions_on_connection_changed),
383 g_signal_connect (G_OBJECT(toggle), "toggled",
384 G_CALLBACK(_modest_ui_actions_on_online_toggle_toggled),
388 g_signal_connect (G_OBJECT(priv->main_window),
390 G_CALLBACK(on_main_window_destroy),
394 /* Init toggle in correct state */
395 _modest_ui_actions_on_connection_changed (device,
396 tny_device_is_online (device),
397 MODEST_MAIN_WINDOW (priv->main_window));
401 /* ***************************************************************** */
402 /* M O D E S T U I A C T I O N S */
403 /* ***************************************************************** */
405 _modest_ui_actions_on_about (GtkWidget *widget,
406 ModestMainWindow *main_window)
409 const gchar *authors[] = {
410 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
413 about = gtk_about_dialog_new ();
414 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
415 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
416 gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
417 _("Copyright (c) 2006, Nokia Corporation\n"
418 "All rights reserved."));
419 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
420 _("a modest e-mail client\n\n"
421 "design and implementation: Dirk-Jan C. Binnema\n"
422 "contributions from the fine people at KernelConcepts and Igalia\n"
423 "uses the tinymail email framework written by Philip van Hoof"));
424 gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
425 gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
427 gtk_dialog_run (GTK_DIALOG (about));
428 gtk_widget_destroy(about);
432 _modest_ui_actions_on_delete (GtkWidget *widget,
433 ModestMainWindow *main_window)
435 ModestWidgetFactory *widget_factory;
436 ModestHeaderView *header_view;
437 TnyList *header_list;
441 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
442 header_view = modest_widget_factory_get_header_view (widget_factory);
443 header_list = modest_header_view_get_selected_headers (header_view);
444 g_object_unref (G_OBJECT(widget_factory));
447 iter = tny_list_create_iterator (header_list);
448 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
449 if (GTK_IS_TREE_MODEL_SORT (model))
450 model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
453 ModestMailOperation *mail_op;
455 header = TNY_HEADER (tny_iterator_get_current (iter));
456 /* TODO: thick grain mail operation involving
457 a list of objects. Composite pattern ??? */
458 mail_op = modest_mail_operation_new ();
460 /* TODO: add confirmation dialog */
463 modest_mail_operation_remove_msg (mail_op, header, TRUE);
465 /* Remove from tree model */
466 if (modest_mail_operation_get_status (mail_op) ==
467 MODEST_MAIL_OPERATION_STATUS_SUCCESS)
468 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
470 /* TODO: error handling management */
472 error = modest_mail_operation_get_error (mail_op);
473 g_warning (error->message);
476 g_object_unref (G_OBJECT (mail_op));
477 g_object_unref (header);
478 tny_iterator_next (iter);
480 } while (!tny_iterator_is_done (iter));
485 _modest_ui_actions_on_quit (GtkWidget *widget,
486 ModestMainWindow *main_window)
488 /* FIXME: save size of main window */
489 /* save_sizes (main_window); */
490 gtk_widget_destroy (GTK_WIDGET (main_window));
494 _modest_ui_actions_on_accounts (GtkWidget *widget,
495 ModestMainWindow *main_window)
497 GtkWidget *account_win;
498 ModestWidgetFactory *widget_factory;
500 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
501 account_win = modest_account_view_window_new (widget_factory);
502 g_object_unref (G_OBJECT(widget_factory));
504 gtk_window_set_transient_for (GTK_WINDOW (account_win),
505 GTK_WINDOW (main_window));
507 gtk_widget_show (account_win);
511 _modest_ui_actions_on_new_msg (GtkWidget *widget,
512 ModestMainWindow *main_window)
514 ModestWindow *msg_win;
515 ModestWidgetFactory *widget_factory;
516 TnyAccountStore *account_store;
518 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
519 account_store = modest_window_get_account_store (MODEST_WINDOW (main_window));
520 msg_win = modest_edit_msg_window_new (widget_factory,
522 MODEST_EDIT_TYPE_NEW);
523 g_object_unref (G_OBJECT (widget_factory));
524 g_object_unref (G_OBJECT (account_store));
526 gtk_widget_show_all (GTK_WIDGET (msg_win));
530 reply_forward_func (gpointer data, gpointer user_data)
532 ModestWidgetFactory *widget_factory;
533 //TnyHeader *new_header;
534 TnyMsg *msg, *new_msg;
535 TnyAccountStore *account_store;
536 GetMsgAsyncHelper *helper;
537 ReplyForwardHelper *rf_helper;
538 ModestWindow *msg_win;
539 ModestEditType edit_type;
541 msg = TNY_MSG (data);
542 helper = (GetMsgAsyncHelper *) user_data;
543 rf_helper = (ReplyForwardHelper *) helper->user_data;
545 /* Create reply mail */
546 switch (rf_helper->action) {
549 modest_mail_operation_create_reply_mail (msg,
551 rf_helper->reply_forward_type,
552 MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
554 case ACTION_REPLY_TO_ALL:
556 modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
557 MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
558 edit_type = MODEST_EDIT_TYPE_REPLY;
562 modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
563 edit_type = MODEST_EDIT_TYPE_FORWARD;
566 g_return_if_reached ();
570 g_warning ("Unable to create a message");
574 /* /\* Set from *\/ */
575 /* new_header = tny_msg_get_header (new_msg); */
576 /* tny_header_set_from (new_header, rf_helper->from); */
577 /* g_object_unref (G_OBJECT (new_header)); */
579 /* Show edit window */
580 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
581 account_store = modest_window_get_account_store (MODEST_WINDOW (helper->main_window));
582 msg_win = modest_edit_msg_window_new (widget_factory,
584 MODEST_EDIT_TYPE_NEW);
585 g_object_unref (G_OBJECT (widget_factory));
586 g_object_unref (G_OBJECT (account_store));
588 modest_edit_msg_window_set_msg (MODEST_EDIT_MSG_WINDOW (msg_win),
590 gtk_widget_show_all (GTK_WIDGET (msg_win));
593 g_object_unref (G_OBJECT (new_msg));
596 g_free (rf_helper->from);
597 g_slice_free (ReplyForwardHelper, rf_helper);
601 * Common code for the reply and forward actions
604 reply_forward (GtkWidget *widget,
605 ReplyForwardAction action,
606 ModestMainWindow *main_window)
608 ModestHeaderView *header_view;
609 ModestAccountMgr *account_mgr;
610 ModestWidgetFactory *widget_factory;
611 TnyList *header_list;
612 guint reply_forward_type;
614 ModestAccountData *default_account_data;
615 TnyPlatformFactory *plat_factory;
618 gchar *from, *key, *default_account_name;
619 GetMsgAsyncHelper *helper;
620 ReplyForwardHelper *rf_helper;
623 plat_factory = modest_tny_platform_factory_get_instance ();
624 conf = modest_tny_platform_factory_get_conf_instance
625 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
627 /* Get reply or forward type */
628 key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE,
629 (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE);
630 reply_forward_type = modest_conf_get_int (conf, key, NULL);
633 /* Get the list of headers */
634 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
635 header_view = modest_widget_factory_get_header_view (widget_factory);
636 header_list = modest_header_view_get_selected_headers (header_view);
637 g_object_unref (G_OBJECT(widget_factory));
642 /* We assume that we can only select messages of the
643 same folder and that we reply all of them from the
644 same account. In fact the interface currently only
645 allows single selection */
646 account_mgr = modest_tny_platform_factory_get_account_mgr_instance
647 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
648 default_account_name = modest_account_mgr_get_default_account (account_mgr);
649 default_account_data =
650 modest_account_mgr_get_account_data (account_mgr,
651 (const gchar*) default_account_name);
652 from = g_strdup (default_account_data->email);
653 modest_account_mgr_free_account_data (account_mgr, default_account_data);
654 g_free (default_account_name);
657 rf_helper = g_slice_new0 (ReplyForwardHelper);
658 rf_helper->reply_forward_type = reply_forward_type;
659 rf_helper->action = action;
660 rf_helper->from = from;
662 helper = g_slice_new0 (GetMsgAsyncHelper);
663 helper->main_window = main_window;
664 helper->func = reply_forward_func;
665 helper->iter = tny_list_create_iterator (header_list);
666 helper->user_data = rf_helper;
668 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
669 folder = tny_header_get_folder (header);
671 /* The callback will call it per each header */
672 tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
675 g_object_unref (G_OBJECT (folder));
679 _modest_ui_actions_on_reply (GtkWidget *widget,
680 ModestMainWindow *main_window)
682 reply_forward (widget, ACTION_REPLY, main_window);
686 _modest_ui_actions_on_forward (GtkWidget *widget,
687 ModestMainWindow *main_window)
689 reply_forward (widget, ACTION_FORWARD, main_window);
693 _modest_ui_actions_on_reply_all (GtkWidget *widget,
694 ModestMainWindow *main_window)
696 reply_forward (widget, ACTION_REPLY_TO_ALL, main_window);
700 _modest_ui_actions_on_next (GtkWidget *widget,
701 ModestMainWindow *main_window)
703 ModestHeaderView *header_view;
704 ModestWidgetFactory *widget_factory;
706 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
707 header_view = modest_widget_factory_get_header_view (widget_factory);
708 g_object_unref (G_OBJECT(widget_factory));
710 modest_header_view_select_next (header_view);
714 _modest_ui_actions_toggle_view (GtkWidget *widget,
715 ModestMainWindow *main_window)
717 ModestHeaderView *header_view;
718 ModestWidgetFactory *widget_factory;
720 TnyPlatformFactory *plat_factory;
723 plat_factory = modest_tny_platform_factory_get_instance ();
724 conf = modest_tny_platform_factory_get_conf_instance
725 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
726 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
727 header_view = modest_widget_factory_get_header_view (widget_factory);
728 g_object_unref (G_OBJECT(widget_factory));
730 /* what is saved/restored is depending on the style; thus; we save with
731 * old style, then update the style, and restore for this new style*/
732 modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
734 if (modest_header_view_get_style (header_view) == MODEST_HEADER_VIEW_STYLE_DETAILS)
735 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
737 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_DETAILS);
739 modest_widget_memory_restore (conf, G_OBJECT(header_view), "header-view");
745 * Marks a message as read and passes it to the msg preview widget
748 read_msg_func (gpointer data, gpointer user_data)
750 ModestMsgView *msg_view;
751 ModestWidgetFactory *widget_factory;
754 GetMsgAsyncHelper *helper;
755 TnyHeaderFlags header_flags;
757 msg = TNY_MSG (data);
758 helper = (GetMsgAsyncHelper *) user_data;
760 /* mark message as seen; _set_flags crashes, bug in tinymail? */
761 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
762 header_flags = tny_header_get_flags (header);
763 tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
764 g_object_unref (G_OBJECT (header));
766 /* Set message on msg view */
767 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
768 msg_view = modest_widget_factory_get_msg_preview (widget_factory);
769 g_object_unref (G_OBJECT(widget_factory));
770 modest_msg_view_set_message (msg_view, msg);
774 * This function is a generic handler for the tny_folder_get_msg_async
775 * call. It expects as user_data a #GetMsgAsyncHelper. This helper
776 * contains a user provided function that is called inside this
777 * method. This will allow us to use this callback in many different
778 * places. This callback performs the common actions for the
779 * get_msg_async call, more specific actions will be done by the user
783 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
785 GetMsgAsyncHelper *helper;
787 helper = (GetMsgAsyncHelper *) user_data;
789 if (*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) {
790 ModestHeaderView *header_view;
791 ModestWidgetFactory *widget_factory;
793 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
794 header_view = modest_widget_factory_get_header_view (widget_factory);
795 g_object_unref (G_OBJECT (widget_factory));
796 _modest_ui_actions_on_item_not_found (header_view,
797 MODEST_ITEM_TYPE_MESSAGE,
798 helper->main_window);
805 /* Call user function */
806 helper->func (msg, user_data);
808 /* Process next element (if exists) */
809 tny_iterator_next (helper->iter);
810 if (tny_iterator_is_done (helper->iter)) {
812 headers = tny_iterator_get_list (helper->iter);
814 g_object_unref (G_OBJECT (headers));
815 g_object_unref (G_OBJECT (helper->iter));
816 g_slice_free (GetMsgAsyncHelper, helper);
818 tny_folder_get_msg_async (folder,
819 TNY_HEADER (tny_iterator_get_current (helper->iter)),
824 _modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,
826 ModestMainWindow *main_window)
829 GetMsgAsyncHelper *helper;
832 /* when there's no header, clear the msgview */
834 ModestMsgView *msg_view;
835 ModestWidgetFactory *widget_factory;
836 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
837 msg_view = modest_widget_factory_get_msg_preview (widget_factory);
838 modest_msg_view_set_message (msg_view, NULL);
842 folder = tny_header_get_folder (TNY_HEADER(header));
845 list = tny_simple_list_new ();
846 tny_list_prepend (list, G_OBJECT (header));
848 /* Fill helper data */
849 helper = g_slice_new0 (GetMsgAsyncHelper);
850 helper->main_window = main_window;
851 helper->iter = tny_list_create_iterator (list);
852 helper->func = read_msg_func;
854 tny_folder_get_msg_async (TNY_FOLDER(folder),
859 g_object_unref (G_OBJECT (folder));
863 _modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
866 ModestMainWindow *main_window)
868 GtkLabel *folder_info_label;
869 TnyPlatformFactory *factory;
872 ModestHeaderView *header_view;
873 ModestWidgetFactory *widget_factory;
875 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
877 GTK_LABEL (modest_widget_factory_get_folder_info_label (widget_factory));
880 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
884 factory = modest_tny_platform_factory_get_instance ();
885 header_view = modest_widget_factory_get_header_view (widget_factory);
886 conf = modest_tny_platform_factory_get_conf_instance
887 (MODEST_TNY_PLATFORM_FACTORY(factory));
888 g_object_unref (G_OBJECT (widget_factory));
890 if (!selected) { /* the folder was unselected; save it's settings */
891 modest_widget_memory_save (conf, G_OBJECT (header_view),
893 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
894 modest_header_view_set_folder (header_view, NULL);
895 } else { /* the folder was selected */
896 if (folder) { /* folder may be NULL */
900 num = tny_folder_get_all_count (folder);
901 unread = tny_folder_get_unread_count (folder);
903 title = g_strdup_printf ("Modest: %s",
904 tny_folder_get_name (folder));
906 gtk_window_set_title (GTK_WINDOW(main_window), title);
909 txt = g_strdup_printf (_("%d %s, %d unread"),
910 num, num==1 ? _("item") : _("items"), unread);
911 gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
914 modest_header_view_set_folder (header_view, folder);
915 modest_widget_memory_restore (conf, G_OBJECT(header_view),
921 /****************************************************/
923 * below some stuff to clearup statusbar messages after 1,5 seconds....
926 GtkWidget *status_bar;
927 GtkWidget *progress_bar;
933 progress_bar_clean (GtkWidget *bar)
935 if (GTK_IS_PROGRESS_BAR(bar)) {
936 gtk_progress_bar_set_text (GTK_PROGRESS_BAR(bar), "");
937 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
943 statusbar_clean (GtkWidget *bar)
945 if (GTK_IS_STATUSBAR(bar))
946 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
952 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
954 GtkWidget *status_bar, *progress_bar;
959 progress_bar = modest_widget_factory_get_progress_bar (factory);
960 status_bar = modest_widget_factory_get_status_bar (factory);
962 gtk_widget_show (GTK_WIDGET(status_bar));
963 gtk_widget_show (GTK_WIDGET(progress_bar));
965 gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
967 g_timeout_add (1500, (GSourceFunc)statusbar_clean, status_bar);
968 g_timeout_add (3000, (GSourceFunc)progress_bar_clean, progress_bar);
970 /****************************************************************************/
973 _modest_ui_actions_on_connection_changed (TnyDevice *device,
975 ModestMainWindow *main_window)
977 GtkWidget *online_toggle;
978 ModestHeaderView *header_view;
979 ModestWidgetFactory *widget_factory;
981 g_return_if_fail (main_window);
983 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
984 header_view = modest_widget_factory_get_header_view (widget_factory);
985 online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
987 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
989 gtk_button_set_label (GTK_BUTTON(online_toggle),
990 online ? _("Online") : _("Offline"));
992 statusbar_push (widget_factory, 0,
993 online ? _("Modest went online") : _("Modest went offline"));
994 g_object_unref (G_OBJECT (widget_factory));
996 /* If Modest has became online and the header view has a
997 header selected then show it */
999 GtkTreeSelection *selected;
1001 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1002 _modest_header_view_change_selection (selected, header_view);
1007 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1008 ModestMainWindow *main_window)
1012 TnyPlatformFactory *factory;
1013 TnyAccountStore *account_store;
1015 /* Get device. Do not ask the platform factory for it, because
1016 it returns always a new one */
1017 factory = modest_tny_platform_factory_get_instance ();
1018 account_store = tny_platform_factory_new_account_store (factory);
1019 device = tny_account_store_get_device (account_store);
1021 online = gtk_toggle_button_get_active (toggle);
1024 tny_device_force_online (device);
1026 tny_device_force_offline (device);
1030 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1031 ModestItemType type,
1032 ModestMainWindow *main_window)
1038 TnyPlatformFactory *factory;
1039 TnyAccountStore *account_store;
1041 item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1043 /* Get device. Do not ask the platform factory for it, because
1044 it returns always a new one */
1045 factory = modest_tny_platform_factory_get_instance ();
1046 account_store = tny_platform_factory_new_account_store (factory);
1047 device = tny_account_store_get_device (account_store);
1049 if (g_main_depth > 0)
1050 gdk_threads_enter ();
1051 online = tny_device_is_online (device);
1054 /* already online -- the item is simply not there... */
1055 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1057 GTK_MESSAGE_WARNING,
1059 _("The %s you selected cannot be found"),
1061 gtk_dialog_run (GTK_DIALOG(dialog));
1064 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1065 GTK_WINDOW (main_window),
1068 GTK_RESPONSE_REJECT,
1070 GTK_RESPONSE_ACCEPT,
1073 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1074 "Do you want to get online?"), item);
1075 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1076 gtk_label_new (txt), FALSE, FALSE, 0);
1077 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1080 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1081 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1082 tny_device_force_online (device);
1085 gtk_widget_destroy (dialog);
1086 if (g_main_depth > 0)
1087 gdk_threads_leave ();
1093 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view,
1097 ModestMainWindow *main_window)
1099 GtkWidget *progress_bar;
1100 ModestWidgetFactory *widget_factory;
1103 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1104 progress_bar = modest_widget_factory_get_progress_bar (widget_factory);
1107 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1108 (gdouble)num/(gdouble)total);
1110 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1112 txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
1113 gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
1116 statusbar_push (widget_factory, 0, msg);
1119 g_object_unref (G_OBJECT (widget_factory));
1125 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview,
1127 ModestMainWindow *main_window)
1129 ModestWidgetFactory *widget_factory;
1131 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1132 statusbar_push (widget_factory, 0, link);
1133 g_object_unref (G_OBJECT (widget_factory));
1135 /* TODO: do something */
1140 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview,
1142 ModestMainWindow *main_window)
1145 ModestWidgetFactory *widget_factory;
1147 msg = g_strdup_printf (_("Opening %s..."), link);
1148 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1149 statusbar_push (widget_factory, 0, msg);
1151 g_object_unref (G_OBJECT (widget_factory));
1155 /* TODO: do something */
1159 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview,
1161 ModestMainWindow *main_window)
1164 ModestWidgetFactory *widget_factory;
1166 msg = g_strdup_printf (_("Opening attachment %d..."), index);
1167 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1168 statusbar_push (widget_factory, 0, msg);
1171 g_object_unref (G_OBJECT (widget_factory));
1172 /* TODO: do something */
1176 _modest_ui_actions_on_send (GtkWidget *widget,
1177 ModestEditMsgWindow *edit_window)
1179 TnyTransportAccount *transport_account;
1180 ModestMailOperation *mail_operation;
1183 data = modest_edit_msg_window_get_msg_data (edit_window);
1185 /* FIXME: Code added just for testing. The final version will
1186 use the send queue provided by tinymail and some
1191 TnyAccountStore *account_store;
1193 accounts = TNY_LIST(tny_simple_list_new ());
1194 account_store = modest_window_get_account_store (MODEST_WINDOW (edit_window));
1195 tny_account_store_get_accounts (account_store, accounts,
1196 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1197 g_object_unref (G_OBJECT (account_store));
1199 iter = tny_list_create_iterator(accounts);
1200 tny_iterator_first (iter);
1201 if (tny_iterator_is_done (iter)) {
1202 /* FIXME: Add error handling through mail operation */
1203 g_printerr("modest: no transport accounts defined\n");
1204 modest_edit_msg_window_free_msg_data (edit_window, data);
1207 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1208 g_object_ref (transport_account);
1210 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1211 g_object_unref (G_OBJECT (accounts));
1212 g_object_unref (G_OBJECT (iter));
1215 mail_operation = modest_mail_operation_new ();
1217 modest_mail_operation_send_new_mail (mail_operation,
1227 g_object_unref (G_OBJECT (mail_operation));
1228 g_object_unref (G_OBJECT (transport_account));
1229 modest_edit_msg_window_free_msg_data (edit_window, data);
1231 /* Save settings and close the window */
1232 /* save_settings (edit_window) */
1233 gtk_widget_destroy (GTK_WIDGET (edit_window));
1237 * Shows a dialog with an entry that asks for some text. The returned
1238 * value must be freed by the caller. The dialog window title will be
1242 ask_for_folder_name (GtkWindow *parent_window,
1245 GtkWidget *dialog, *entry;
1246 gchar *folder_name = NULL;
1248 /* Ask for folder name */
1249 dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1253 GTK_RESPONSE_REJECT,
1255 GTK_RESPONSE_ACCEPT,
1257 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1258 gtk_label_new(title),
1261 entry = gtk_entry_new_with_max_length (40);
1262 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1266 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1268 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1269 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1271 gtk_widget_destroy (dialog);
1277 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1278 ModestMainWindow *main_window)
1280 TnyFolder *parent_folder;
1281 ModestFolderView *folder_view;
1282 ModestWidgetFactory *widget_factory;
1284 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1285 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1286 parent_folder = modest_folder_view_get_selected (folder_view);
1288 if (parent_folder) {
1291 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1292 _("Please enter a name for the new folder"));
1294 if (folder_name != NULL && strlen (folder_name) > 0) {
1295 TnyFolder *new_folder;
1296 ModestMailOperation *mail_op;
1298 mail_op = modest_mail_operation_new ();
1299 new_folder = modest_mail_operation_create_folder (mail_op,
1300 TNY_FOLDER_STORE (parent_folder),
1301 (const gchar *) folder_name);
1303 /* Do anything more? The model
1304 is automatically updated */
1305 g_object_unref (new_folder);
1307 g_object_unref (mail_op);
1309 g_object_unref (parent_folder);
1311 g_object_unref (G_OBJECT (widget_factory));
1315 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1316 ModestMainWindow *main_window)
1319 ModestFolderView *folder_view;
1320 ModestWidgetFactory *widget_factory;
1322 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1323 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1324 folder = modest_folder_view_get_selected (folder_view);
1329 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1330 _("Please enter a new name for the folder"));
1332 if (folder_name != NULL && strlen (folder_name) > 0) {
1333 ModestMailOperation *mail_op;
1335 mail_op = modest_mail_operation_new ();
1336 modest_mail_operation_rename_folder (mail_op,
1338 (const gchar *) folder_name);
1339 g_object_unref (mail_op);
1341 g_object_unref (folder);
1343 g_object_unref (G_OBJECT (widget_factory));
1347 delete_folder (ModestMainWindow *main_window,
1348 gboolean move_to_trash)
1351 ModestFolderView *folder_view;
1352 ModestWidgetFactory *widget_factory;
1353 ModestMailOperation *mail_op;
1355 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1356 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1357 folder = modest_folder_view_get_selected (folder_view);
1359 mail_op = modest_mail_operation_new ();
1360 modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1361 g_object_unref (mail_op);
1365 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1366 ModestMainWindow *main_window)
1368 delete_folder (main_window, FALSE);
1372 _modest_ui_actions_on_move_to_trash_folder (GtkWidget *widget,
1373 ModestMainWindow *main_window)
1375 delete_folder (main_window, TRUE);