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-main-window.h"
43 #include "modest-mail-operation.h"
44 #include <modest-widget-memory.h>
45 #include <tny-error.h>
46 #include <tny-simple-list.h>
47 #include <tny-msg-view.h>
49 #define MODEST_UI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
53 typedef struct _GetMsgAsyncHelper {
54 ModestMainWindow *main_window;
60 typedef enum _ReplyForwardAction {
66 typedef struct _ReplyForwardHelper {
67 guint reply_forward_type;
68 ReplyForwardAction action;
73 static GObjectClass *parent_class = NULL;
75 /* 'private'/'protected' functions */
76 static void modest_ui_class_init (ModestUIClass *klass);
77 static void modest_ui_init (ModestUI *obj);
78 static void modest_ui_finalize (GObject *obj);
80 static void register_stock_icons ();
81 static void connect_signals (ModestUI *self);
83 static void reply_forward_func (gpointer data,
85 static void read_msg_func (gpointer data,
87 static void get_msg_cb (TnyFolder *folder,
92 static void reply_forward (GtkWidget *widget,
93 ReplyForwardAction action,
94 ModestMainWindow *main_window);
96 static gchar* ask_for_folder_name (GtkWindow *parent_window,
99 static void _modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
100 const gchar* account_name,
104 ModestMainWindow *main_window);
107 modest_ui_get_type (void)
109 static GType my_type = 0;
111 static const GTypeInfo my_info = {
112 sizeof(ModestUIClass),
113 NULL, /* base init */
114 NULL, /* base finalize */
115 (GClassInitFunc) modest_ui_class_init,
116 NULL, /* class finalize */
117 NULL, /* class data */
120 (GInstanceInitFunc) modest_ui_init,
123 my_type = g_type_register_static (G_TYPE_OBJECT,
132 modest_ui_class_init (ModestUIClass *klass)
134 GObjectClass *gobject_class;
135 gobject_class = (GObjectClass*) klass;
137 parent_class = g_type_class_peek_parent (klass);
138 gobject_class->finalize = modest_ui_finalize;
140 g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
146 modest_ui_init (ModestUI *obj)
148 ModestUIPrivate *priv;
150 priv = MODEST_UI_GET_PRIVATE(obj);
152 priv->widget_factory = NULL;
153 priv->main_window = NULL;
154 priv->account_store = NULL;
159 modest_ui_finalize (GObject *obj)
162 ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
164 if (priv->widget_factory) {
165 g_object_unref (G_OBJECT(priv->widget_factory));
166 priv->widget_factory = NULL;
169 if (priv->ui_manager) {
170 g_object_unref (G_OBJECT(priv->ui_manager));
171 priv->ui_manager = NULL;
174 G_OBJECT_CLASS(parent_class)->finalize (obj);
179 modest_ui_new (TnyAccountStore *account_store)
182 ModestUIPrivate *priv;
183 TnyPlatformFactory *fact;
184 ModestAccountMgr *account_mgr;
186 obj = g_object_new(MODEST_TYPE_UI, NULL);
187 priv = MODEST_UI_GET_PRIVATE(obj);
189 /* Get the platform-dependent instances */
190 fact = modest_tny_platform_factory_get_instance ();
192 priv->account_store = account_store;
194 account_mgr = modest_tny_platform_factory_get_account_mgr_instance
195 (MODEST_TNY_PLATFORM_FACTORY(fact));
197 g_printerr ("modest: could not create ModestAccountMgr instance\n");
198 g_object_unref (obj);
202 priv->widget_factory = modest_widget_factory_new ();
203 if (!priv->widget_factory) {
204 g_printerr ("modest: could not initialize widget factory\n");
208 /* Register our own icons as stock icons in order to
209 use them with the UI manager */
210 register_stock_icons ();
212 return MODEST_UI(obj);
216 on_main_window_destroy (GtkObject *widget, ModestUI *self)
218 /* FIXME: check if there any viewer/editing windows opened */
225 modest_ui_main_window (ModestUI *self)
227 ModestUIPrivate *priv;
229 g_return_val_if_fail (self, NULL);
230 priv = MODEST_UI_GET_PRIVATE(self);
232 if (!priv->main_window) {
234 /* Create main window */
235 priv->main_window = modest_main_window_new (priv->widget_factory,
236 priv->account_store);
238 connect_signals (self);
241 if (!priv->main_window)
242 g_printerr ("modest: could not create main window\n");
244 return priv->main_window;
248 modest_ui_edit_window (ModestUI *self, ModestEditType edit_type)
250 ModestUIPrivate *priv;
251 ModestWindow *edit_window;
253 g_return_val_if_fail (self, NULL);
254 priv = MODEST_UI_GET_PRIVATE(self);
257 edit_window = modest_edit_msg_window_new (priv->widget_factory,
261 /* Connect Edit Window signals */
262 /* connect_edit_window_signals (self); */
268 * This function registers our custom toolbar icons, so they can be
269 * themed. The idea of this function was taken from the gtk-demo
272 register_stock_icons ()
274 static gboolean registered = FALSE;
278 GtkIconFactory *factory;
281 static GtkStockItem items[] = {
282 { MODEST_STOCK_MAIL_SEND, "send mail", 0, 0, NULL },
283 { MODEST_STOCK_NEW_MAIL, "new mail", 0, 0, NULL },
284 { MODEST_STOCK_SEND_RECEIVE, "send receive", 0, 0, NULL },
285 { MODEST_STOCK_REPLY, "reply", 0, 0, NULL },
286 { MODEST_STOCK_REPLY_ALL, "reply all", 0, 0, NULL },
287 { MODEST_STOCK_FORWARD, "forward", 0, 0, NULL },
288 { MODEST_STOCK_DELETE, "delete", 0, 0, NULL },
289 { MODEST_STOCK_NEXT, "next", 0, 0, NULL },
290 { MODEST_STOCK_PREV, "prev", 0, 0, NULL },
291 { MODEST_STOCK_STOP, "stop", 0, 0, NULL }
294 static gchar *items_names [] = {
295 MODEST_TOOLBAR_ICON_MAIL_SEND,
296 MODEST_TOOLBAR_ICON_NEW_MAIL,
297 MODEST_TOOLBAR_ICON_SEND_RECEIVE,
298 MODEST_TOOLBAR_ICON_REPLY,
299 MODEST_TOOLBAR_ICON_REPLY_ALL,
300 MODEST_TOOLBAR_ICON_FORWARD,
301 MODEST_TOOLBAR_ICON_DELETE,
302 MODEST_TOOLBAR_ICON_NEXT,
303 MODEST_TOOLBAR_ICON_PREV,
304 MODEST_TOOLBAR_ICON_STOP
309 /* Register our stock items */
310 gtk_stock_add (items, G_N_ELEMENTS (items));
312 /* Add our custom icon factory to the list of defaults */
313 factory = gtk_icon_factory_new ();
314 gtk_icon_factory_add_default (factory);
316 /* Register icons to accompany stock items */
317 for (i = 0; i < G_N_ELEMENTS (items); i++) {
319 pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
321 if (pixbuf != NULL) {
322 GtkIconSet *icon_set;
323 GdkPixbuf *transparent;
325 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
327 icon_set = gtk_icon_set_new_from_pixbuf (transparent);
328 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
329 gtk_icon_set_unref (icon_set);
330 g_object_unref (pixbuf);
331 g_object_unref (transparent);
334 g_warning ("failed to load %s icon", items_names[i]);
336 /* Drop our reference to the factory, GTK will hold a reference. */
337 g_object_unref (factory);
341 /* FIXME: uninit these as well */
343 connect_signals (ModestUI *self)
346 ModestUIPrivate *priv;
347 ModestFolderView *folder_view;
348 ModestHeaderView *header_view;
349 ModestMsgView *msg_view;
352 priv = MODEST_UI_GET_PRIVATE(self);
354 folder_view = modest_widget_factory_get_folder_view (priv->widget_factory);
355 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
356 msg_view = modest_widget_factory_get_msg_preview (priv->widget_factory);
357 toggle = modest_widget_factory_get_online_toggle (priv->widget_factory);
358 device = tny_account_store_get_device (priv->account_store);
361 g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
362 G_CALLBACK(_modest_ui_actions_on_folder_selection_changed),
365 g_signal_connect (G_OBJECT(header_view), "status_update",
366 G_CALLBACK(_modest_ui_actions_on_header_status_update),
368 g_signal_connect (G_OBJECT(header_view), "header_selected",
369 G_CALLBACK(_modest_ui_actions_on_header_selected),
371 g_signal_connect (G_OBJECT(header_view), "item_not_found",
372 G_CALLBACK(_modest_ui_actions_on_item_not_found),
375 g_signal_connect (G_OBJECT(msg_view), "link_clicked",
376 G_CALLBACK(_modest_ui_actions_on_msg_link_clicked),
378 g_signal_connect (G_OBJECT(msg_view), "link_hover",
379 G_CALLBACK(_modest_ui_actions_on_msg_link_hover),
381 g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
382 G_CALLBACK(_modest_ui_actions_on_msg_attachment_clicked),
386 g_signal_connect (G_OBJECT(device), "connection_changed",
387 G_CALLBACK(_modest_ui_actions_on_connection_changed),
389 g_signal_connect (G_OBJECT(toggle), "toggled",
390 G_CALLBACK(_modest_ui_actions_on_online_toggle_toggled),
394 g_signal_connect (G_OBJECT (priv->account_store),
395 "password_requested",
396 G_CALLBACK(_modest_ui_actions_on_password_requested),
400 g_signal_connect (G_OBJECT(priv->main_window),
402 G_CALLBACK(on_main_window_destroy),
406 /* Init toggle in correct state */
407 _modest_ui_actions_on_connection_changed (device,
408 tny_device_is_online (device),
409 MODEST_MAIN_WINDOW (priv->main_window));
413 /* ***************************************************************** */
414 /* M O D E S T U I A C T I O N S */
415 /* ***************************************************************** */
417 _modest_ui_actions_on_about (GtkWidget *widget,
418 ModestMainWindow *main_window)
421 const gchar *authors[] = {
422 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
425 about = gtk_about_dialog_new ();
426 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
427 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
428 gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
429 _("Copyright (c) 2006, Nokia Corporation\n"
430 "All rights reserved."));
431 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
432 _("a modest e-mail client\n\n"
433 "design and implementation: Dirk-Jan C. Binnema\n"
434 "contributions from the fine people at KernelConcepts and Igalia\n"
435 "uses the tinymail email framework written by Philip van Hoof"));
436 gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
437 gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
439 gtk_dialog_run (GTK_DIALOG (about));
440 gtk_widget_destroy(about);
444 _modest_ui_actions_on_delete (GtkWidget *widget,
445 ModestMainWindow *main_window)
447 ModestWidgetFactory *widget_factory;
448 ModestHeaderView *header_view;
449 TnyList *header_list;
453 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
454 header_view = modest_widget_factory_get_header_view (widget_factory);
455 header_list = modest_header_view_get_selected_headers (header_view);
456 g_object_unref (G_OBJECT(widget_factory));
459 iter = tny_list_create_iterator (header_list);
460 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
461 if (GTK_IS_TREE_MODEL_SORT (model))
462 model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
465 ModestMailOperation *mail_op;
467 header = TNY_HEADER (tny_iterator_get_current (iter));
468 /* TODO: thick grain mail operation involving
469 a list of objects. Composite pattern ??? */
470 mail_op = modest_mail_operation_new ();
472 /* TODO: add confirmation dialog */
475 modest_mail_operation_remove_msg (mail_op, header, TRUE);
477 /* Remove from tree model */
478 if (modest_mail_operation_get_status (mail_op) ==
479 MODEST_MAIL_OPERATION_STATUS_SUCCESS)
480 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
482 /* TODO: error handling management */
484 error = modest_mail_operation_get_error (mail_op);
485 g_warning (error->message);
488 g_object_unref (G_OBJECT (mail_op));
489 g_object_unref (header);
490 tny_iterator_next (iter);
492 } while (!tny_iterator_is_done (iter));
497 _modest_ui_actions_on_quit (GtkWidget *widget,
498 ModestMainWindow *main_window)
500 /* FIXME: save size of main window */
501 /* save_sizes (main_window); */
502 gtk_widget_destroy (GTK_WIDGET (main_window));
506 _modest_ui_actions_on_accounts (GtkWidget *widget,
507 ModestMainWindow *main_window)
509 GtkWidget *account_win;
510 ModestWidgetFactory *widget_factory;
512 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
513 account_win = modest_account_view_window_new (widget_factory);
514 g_object_unref (G_OBJECT(widget_factory));
516 gtk_window_set_transient_for (GTK_WINDOW (account_win),
517 GTK_WINDOW (main_window));
519 gtk_widget_show (account_win);
523 _modest_ui_actions_on_new_msg (GtkWidget *widget,
524 ModestMainWindow *main_window)
526 ModestWindow *msg_win;
527 ModestWidgetFactory *widget_factory;
528 TnyAccountStore *account_store;
530 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
531 account_store = modest_window_get_account_store (MODEST_WINDOW (main_window));
532 msg_win = modest_edit_msg_window_new (widget_factory,
534 MODEST_EDIT_TYPE_NEW);
535 g_object_unref (G_OBJECT (widget_factory));
536 g_object_unref (G_OBJECT (account_store));
538 gtk_widget_show (GTK_WIDGET (msg_win));
542 reply_forward_func (gpointer data, gpointer user_data)
544 ModestWidgetFactory *widget_factory;
545 TnyHeader *new_header;
546 TnyMsg *msg, *new_msg;
547 TnyAccountStore *account_store;
548 GetMsgAsyncHelper *helper;
549 ReplyForwardHelper *rf_helper;
550 ModestWindow *msg_win;
551 ModestEditType edit_type;
553 msg = TNY_MSG (data);
554 helper = (GetMsgAsyncHelper *) user_data;
555 rf_helper = (ReplyForwardHelper *) helper->user_data;
557 /* Create reply mail */
558 switch (rf_helper->action) {
561 modest_mail_operation_create_reply_mail (msg,
563 rf_helper->reply_forward_type,
564 MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
565 case ACTION_REPLY_TO_ALL:
567 modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
568 MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
569 edit_type = MODEST_EDIT_TYPE_REPLY;
573 modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
574 edit_type = MODEST_EDIT_TYPE_FORWARD;
577 g_return_if_reached ();
581 new_header = tny_msg_get_header (new_msg);
582 tny_header_set_from (new_header, rf_helper->from);
583 g_object_unref (G_OBJECT (new_header));
585 /* Show edit window */
586 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
587 account_store = modest_window_get_account_store (MODEST_WINDOW (helper->main_window));
588 msg_win = modest_edit_msg_window_new (widget_factory,
590 MODEST_EDIT_TYPE_NEW);
591 g_object_unref (G_OBJECT (widget_factory));
592 g_object_unref (G_OBJECT (account_store));
593 modest_edit_msg_window_set_msg (MODEST_EDIT_MSG_WINDOW (msg_win),
595 gtk_widget_show (GTK_WIDGET (msg_win));
598 g_object_unref (G_OBJECT (new_msg));
599 g_free (rf_helper->from);
600 g_slice_free (ReplyForwardHelper, rf_helper);
604 * Common code for the reply and forward actions
607 reply_forward (GtkWidget *widget,
608 ReplyForwardAction action,
609 ModestMainWindow *main_window)
611 ModestHeaderView *header_view;
612 ModestWidgetFactory *widget_factory;
613 TnyList *header_list;
614 guint reply_forward_type;
616 TnyPlatformFactory *plat_factory;
620 GetMsgAsyncHelper *helper;
621 ReplyForwardHelper *rf_helper;
624 plat_factory = modest_tny_platform_factory_get_instance ();
625 conf = modest_tny_platform_factory_get_conf_instance
626 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
628 /* Get reply or forward type */
629 key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE,
630 (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE);
631 reply_forward_type = modest_conf_get_int (conf, key, NULL);
634 /* Get the list of headers */
635 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
636 header_view = modest_widget_factory_get_header_view (widget_factory);
637 header_list = modest_header_view_get_selected_headers (header_view);
638 g_object_unref (G_OBJECT(widget_factory));
643 /* We assume that we can only select messages of the
644 same folder and that we reply all of them from the
645 same account. In fact the interface currently only
646 allows single selection */
648 /* TODO: get the from string from account */
649 from = g_strdup ("Invalid");
652 rf_helper = g_slice_new0 (ReplyForwardHelper);
653 rf_helper->reply_forward_type = reply_forward_type;
654 rf_helper->action = action;
655 rf_helper->from = from;
657 helper = g_slice_new0 (GetMsgAsyncHelper);
658 helper->main_window = main_window;
659 helper->func = reply_forward_func;
660 helper->iter = tny_list_create_iterator (header_list);
661 helper->user_data = rf_helper;
663 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
664 folder = tny_header_get_folder (header);
666 /* The callback will call it per each header */
667 tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
670 g_object_unref (G_OBJECT (folder));
674 _modest_ui_actions_on_reply (GtkWidget *widget,
675 ModestMainWindow *main_window)
677 reply_forward (widget, ACTION_REPLY, main_window);
681 _modest_ui_actions_on_forward (GtkWidget *widget,
682 ModestMainWindow *main_window)
684 reply_forward (widget, ACTION_FORWARD, main_window);
688 _modest_ui_actions_on_reply_all (GtkWidget *widget,
689 ModestMainWindow *main_window)
691 reply_forward (widget, ACTION_REPLY_TO_ALL, main_window);
695 _modest_ui_actions_on_next (GtkWidget *widget,
696 ModestMainWindow *main_window)
698 ModestHeaderView *header_view;
699 ModestWidgetFactory *widget_factory;
701 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
702 header_view = modest_widget_factory_get_header_view (widget_factory);
703 g_object_unref (G_OBJECT(widget_factory));
705 modest_header_view_select_next (header_view);
709 _modest_ui_actions_toggle_view (GtkWidget *widget,
710 ModestMainWindow *main_window)
712 ModestHeaderView *header_view;
713 ModestWidgetFactory *widget_factory;
715 TnyPlatformFactory *plat_factory;
718 plat_factory = modest_tny_platform_factory_get_instance ();
719 conf = modest_tny_platform_factory_get_conf_instance
720 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
721 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
722 header_view = modest_widget_factory_get_header_view (widget_factory);
723 g_object_unref (G_OBJECT(widget_factory));
725 /* what is saved/restored is depending on the style; thus; we save with
726 * old style, then update the style, and restore for this new style*/
727 modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
729 if (modest_header_view_get_style (header_view) == MODEST_HEADER_VIEW_STYLE_DETAILS)
730 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
732 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_DETAILS);
734 modest_widget_memory_restore (conf, G_OBJECT(header_view), "header-view");
740 * Marks a message as read and passes it to the msg preview widget
743 read_msg_func (gpointer data, gpointer user_data)
745 ModestMsgView *msg_view;
746 ModestWidgetFactory *widget_factory;
749 GetMsgAsyncHelper *helper;
750 TnyHeaderFlags header_flags;
752 msg = TNY_MSG (data);
753 helper = (GetMsgAsyncHelper *) user_data;
755 /* mark message as seen; _set_flags crashes, bug in tinymail? */
756 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
757 header_flags = tny_header_get_flags (header);
758 tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
759 g_object_unref (G_OBJECT (header));
761 /* Set message on msg view */
762 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
763 msg_view = modest_widget_factory_get_msg_preview (widget_factory);
764 g_object_unref (G_OBJECT(widget_factory));
765 modest_msg_view_set_message (msg_view, msg);
769 * This function is a generic handler for the tny_folder_get_msg_async
770 * call. It expects as user_data a #GetMsgAsyncHelper. This helper
771 * contains a user provided function that is called inside this
772 * method. This will allow us to use this callback in many different
773 * places. This callback performs the common actions for the
774 * get_msg_async call, more specific actions will be done by the user
778 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
780 GetMsgAsyncHelper *helper;
782 helper = (GetMsgAsyncHelper *) user_data;
784 if (*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) {
785 ModestHeaderView *header_view;
786 ModestWidgetFactory *widget_factory;
788 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
789 header_view = modest_widget_factory_get_header_view (widget_factory);
790 g_object_unref (G_OBJECT (widget_factory));
791 _modest_ui_actions_on_item_not_found (header_view,
792 MODEST_ITEM_TYPE_MESSAGE,
793 helper->main_window);
800 /* Call user function */
801 helper->func (msg, user_data);
803 /* Process next element (if exists) */
804 tny_iterator_next (helper->iter);
805 if (tny_iterator_is_done (helper->iter)) {
807 headers = tny_iterator_get_list (helper->iter);
809 g_object_unref (G_OBJECT (headers));
810 g_object_unref (G_OBJECT (helper->iter));
811 g_slice_free (GetMsgAsyncHelper, helper);
813 tny_folder_get_msg_async (folder,
814 TNY_HEADER (tny_iterator_get_current (helper->iter)),
819 _modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,
821 ModestMainWindow *main_window)
824 GetMsgAsyncHelper *helper;
827 /* when there's no header, clear the msgview */
829 ModestMsgView *msg_view;
830 ModestWidgetFactory *widget_factory;
831 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
832 msg_view = modest_widget_factory_get_msg_preview (widget_factory);
833 modest_msg_view_set_message (msg_view, NULL);
837 folder = tny_header_get_folder (TNY_HEADER(header));
840 list = tny_simple_list_new ();
841 tny_list_prepend (list, G_OBJECT (header));
843 /* Fill helper data */
844 helper = g_slice_new0 (GetMsgAsyncHelper);
845 helper->main_window = main_window;
846 helper->iter = tny_list_create_iterator (list);
847 helper->func = read_msg_func;
849 tny_folder_get_msg_async (TNY_FOLDER(folder),
854 g_object_unref (G_OBJECT (folder));
858 _modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
861 ModestMainWindow *main_window)
863 GtkLabel *folder_info_label;
864 TnyPlatformFactory *factory;
867 ModestHeaderView *header_view;
868 ModestWidgetFactory *widget_factory;
870 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
872 GTK_LABEL (modest_widget_factory_get_folder_info_label (widget_factory));
875 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
879 factory = modest_tny_platform_factory_get_instance ();
880 header_view = modest_widget_factory_get_header_view (widget_factory);
881 conf = modest_tny_platform_factory_get_conf_instance
882 (MODEST_TNY_PLATFORM_FACTORY(factory));
883 g_object_unref (G_OBJECT (widget_factory));
885 if (!selected) { /* the folder was unselected; save it's settings */
886 modest_widget_memory_save (conf, G_OBJECT (header_view),
888 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
889 modest_header_view_set_folder (header_view, NULL);
890 } else { /* the folder was selected */
891 if (folder) { /* folder may be NULL */
895 num = tny_folder_get_all_count (folder);
896 unread = tny_folder_get_unread_count (folder);
898 title = g_strdup_printf ("Modest: %s",
899 tny_folder_get_name (folder));
901 gtk_window_set_title (GTK_WINDOW(main_window), title);
904 txt = g_strdup_printf (_("%d %s, %d unread"),
905 num, num==1 ? _("item") : _("items"), unread);
906 gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
909 modest_header_view_set_folder (header_view, folder);
910 modest_widget_memory_restore (conf, G_OBJECT(header_view),
916 _modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
917 const gchar* account_name,
921 ModestMainWindow *main_window)
924 GtkWidget *dialog, *entry, *remember_pass_check;
926 dialog = gtk_dialog_new_with_buttons (_("Password requested"),
927 GTK_WINDOW (main_window),
935 txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
936 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
940 entry = gtk_entry_new_with_max_length (40);
941 gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
942 gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
944 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
947 remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
948 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
951 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
953 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
954 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
961 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
966 gtk_widget_destroy (dialog);
968 while (gtk_events_pending ())
969 gtk_main_iteration ();
972 /****************************************************/
974 * below some stuff to clearup statusbar messages after 1,5 seconds....
977 GtkWidget *status_bar;
978 GtkWidget *progress_bar;
983 on_statusbar_remove_msg (StatusRemoveData *data)
985 /* we need to test types, as this callback maybe called after the
986 * widgets have been destroyed
988 if (GTK_IS_STATUSBAR(data->status_bar))
989 gtk_statusbar_remove (GTK_STATUSBAR(data->status_bar),
991 if (GTK_IS_PROGRESS_BAR(data->progress_bar))
992 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(data->progress_bar),
999 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
1002 StatusRemoveData *data;
1003 GtkWidget *status_bar, *progress_bar;
1008 progress_bar = modest_widget_factory_get_progress_bar (factory);
1009 status_bar = modest_widget_factory_get_status_bar (factory);
1011 id = gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
1013 data = g_new (StatusRemoveData, 1);
1014 data->status_bar = status_bar;
1015 data->progress_bar = progress_bar;
1018 g_timeout_add (1500, (GSourceFunc)on_statusbar_remove_msg, data);
1020 /****************************************************************************/
1023 _modest_ui_actions_on_connection_changed (TnyDevice *device,
1025 ModestMainWindow *main_window)
1027 GtkWidget *online_toggle;
1028 ModestHeaderView *header_view;
1029 ModestWidgetFactory *widget_factory;
1031 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1032 header_view = modest_widget_factory_get_header_view (widget_factory);
1033 online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
1035 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
1037 gtk_button_set_label (GTK_BUTTON(online_toggle),
1038 online ? _("Online") : _("Offline"));
1040 statusbar_push (widget_factory, 0,
1041 online ? _("Modest went online") : _("Modest went offline"));
1042 g_object_unref (G_OBJECT (widget_factory));
1044 /* If Modest has became online and the header view has a
1045 header selected then show it */
1047 GtkTreeSelection *selected;
1049 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1050 _modest_header_view_change_selection (selected, header_view);
1055 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1056 ModestMainWindow *main_window)
1060 TnyPlatformFactory *factory;
1061 TnyAccountStore *account_store;
1063 /* Get device. Do not ask the platform factory for it, because
1064 it returns always a new one */
1065 factory = modest_tny_platform_factory_get_instance ();
1066 account_store = tny_platform_factory_new_account_store (factory);
1067 device = tny_account_store_get_device (account_store);
1069 online = gtk_toggle_button_get_active (toggle);
1072 tny_device_force_online (device);
1074 tny_device_force_offline (device);
1078 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1079 ModestItemType type,
1080 ModestMainWindow *main_window)
1086 TnyPlatformFactory *factory;
1087 TnyAccountStore *account_store;
1089 item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1091 /* Get device. Do not ask the platform factory for it, because
1092 it returns always a new one */
1093 factory = modest_tny_platform_factory_get_instance ();
1094 account_store = tny_platform_factory_new_account_store (factory);
1095 device = tny_account_store_get_device (account_store);
1097 gdk_threads_enter ();
1098 online = tny_device_is_online (device);
1101 /* already online -- the item is simply not there... */
1102 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1104 GTK_MESSAGE_WARNING,
1106 _("The %s you selected cannot be found"),
1108 gtk_dialog_run (GTK_DIALOG(dialog));
1111 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1112 GTK_WINDOW (main_window),
1115 GTK_RESPONSE_REJECT,
1117 GTK_RESPONSE_ACCEPT,
1120 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1121 "Do you want to get online?"), item);
1122 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1123 gtk_label_new (txt), FALSE, FALSE, 0);
1124 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1127 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1128 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1129 tny_device_force_online (device);
1132 gtk_widget_destroy (dialog);
1133 gdk_threads_leave ();
1139 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view,
1143 ModestMainWindow *main_window)
1145 GtkWidget *progress_bar;
1146 ModestWidgetFactory *widget_factory;
1148 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1149 progress_bar = modest_widget_factory_get_progress_bar (widget_factory);
1152 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1153 (gdouble)num/(gdouble)total);
1155 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1157 statusbar_push (widget_factory, 0, msg);
1160 g_object_unref (G_OBJECT (widget_factory));
1166 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview,
1168 ModestMainWindow *main_window)
1170 ModestWidgetFactory *widget_factory;
1172 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1173 statusbar_push (widget_factory, 0, link);
1174 g_object_unref (G_OBJECT (widget_factory));
1176 /* TODO: do something */
1181 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview,
1183 ModestMainWindow *main_window)
1186 ModestWidgetFactory *widget_factory;
1188 msg = g_strdup_printf (_("Opening %s..."), link);
1189 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1190 statusbar_push (widget_factory, 0, msg);
1192 g_object_unref (G_OBJECT (widget_factory));
1196 /* TODO: do something */
1200 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview,
1202 ModestMainWindow *main_window)
1205 ModestWidgetFactory *widget_factory;
1207 msg = g_strdup_printf (_("Opening attachment %d..."), index);
1208 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1209 statusbar_push (widget_factory, 0, msg);
1212 g_object_unref (G_OBJECT (widget_factory));
1213 /* TODO: do something */
1217 _modest_ui_actions_on_send (GtkWidget *widget,
1218 ModestEditMsgWindow *edit_window)
1220 TnyTransportAccount *transport_account;
1221 ModestMailOperation *mail_operation;
1224 data = modest_edit_msg_window_get_msg_data (edit_window);
1226 /* FIXME: Code added just for testing. The final version will
1227 use the send queue provided by tinymail and some
1232 TnyAccountStore *account_store;
1234 accounts = TNY_LIST(tny_simple_list_new ());
1235 account_store = modest_window_get_account_store (MODEST_WINDOW (edit_window));
1236 tny_account_store_get_accounts (account_store, accounts,
1237 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1238 g_object_unref (G_OBJECT (account_store));
1240 iter = tny_list_create_iterator(accounts);
1241 tny_iterator_first (iter);
1242 if (tny_iterator_is_done (iter)) {
1243 /* FIXME: Add error handling through mail operation */
1244 g_printerr("modest: no transport accounts defined\n");
1245 modest_edit_msg_window_free_msg_data (edit_window, data);
1248 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1249 g_object_ref (transport_account);
1251 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1252 g_object_unref (G_OBJECT (accounts));
1253 g_object_unref (G_OBJECT (iter));
1256 mail_operation = modest_mail_operation_new ();
1258 modest_mail_operation_send_new_mail (mail_operation,
1268 g_object_unref (G_OBJECT (mail_operation));
1269 g_object_unref (G_OBJECT (transport_account));
1270 modest_edit_msg_window_free_msg_data (edit_window, data);
1272 /* Save settings and close the window */
1273 /* save_settings (edit_window) */
1274 gtk_widget_destroy (GTK_WIDGET (edit_window));
1278 * Shows a dialog with an entry that asks for some text. The returned
1279 * value must be freed by the caller. The dialog window title will be
1283 ask_for_folder_name (GtkWindow *parent_window,
1286 GtkWidget *dialog, *entry;
1287 gchar *folder_name = NULL;
1289 /* Ask for folder name */
1290 dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1294 GTK_RESPONSE_REJECT,
1296 GTK_RESPONSE_ACCEPT,
1298 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1299 gtk_label_new(title),
1302 entry = gtk_entry_new_with_max_length (40);
1303 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1307 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1309 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1310 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1312 gtk_widget_destroy (dialog);
1318 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1319 ModestMainWindow *main_window)
1321 TnyFolder *parent_folder;
1322 ModestFolderView *folder_view;
1323 ModestWidgetFactory *widget_factory;
1325 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1326 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1327 parent_folder = modest_folder_view_get_selected (folder_view);
1329 if (parent_folder) {
1332 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1333 _("Please enter a name for the new folder"));
1335 if (folder_name != NULL && strlen (folder_name) > 0) {
1336 TnyFolder *new_folder;
1337 ModestMailOperation *mail_op;
1339 mail_op = modest_mail_operation_new ();
1340 new_folder = modest_mail_operation_create_folder (mail_op,
1341 TNY_FOLDER_STORE (parent_folder),
1342 (const gchar *) folder_name);
1344 /* Do anything more? The model
1345 is automatically updated */
1346 g_object_unref (new_folder);
1348 g_object_unref (mail_op);
1350 g_object_unref (parent_folder);
1352 g_object_unref (G_OBJECT (widget_factory));
1356 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1357 ModestMainWindow *main_window)
1360 ModestFolderView *folder_view;
1361 ModestWidgetFactory *widget_factory;
1363 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1364 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1365 folder = modest_folder_view_get_selected (folder_view);
1370 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1371 _("Please enter a new name for the folder"));
1373 if (folder_name != NULL && strlen (folder_name) > 0) {
1374 ModestMailOperation *mail_op;
1376 mail_op = modest_mail_operation_new ();
1377 modest_mail_operation_rename_folder (mail_op,
1379 (const gchar *) folder_name);
1380 g_object_unref (mail_op);
1382 g_object_unref (folder);
1384 g_object_unref (G_OBJECT (widget_factory));
1388 delete_folder (ModestMainWindow *main_window,
1389 gboolean move_to_trash)
1392 ModestFolderView *folder_view;
1393 ModestWidgetFactory *widget_factory;
1394 ModestMailOperation *mail_op;
1396 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1397 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1398 folder = modest_folder_view_get_selected (folder_view);
1400 mail_op = modest_mail_operation_new ();
1401 modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1402 g_object_unref (mail_op);
1406 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1407 ModestMainWindow *main_window)
1409 delete_folder (main_window, FALSE);
1413 _modest_ui_actions_on_move_to_trash_folder (GtkWidget *widget,
1414 ModestMainWindow *main_window)
1416 delete_folder (main_window, TRUE);