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 */
893 num = tny_folder_get_all_count (folder);
894 unread = tny_folder_get_unread_count (folder);
896 title = g_strdup_printf ("Modest: %s",
897 tny_folder_get_name (folder));
899 gtk_window_set_title (GTK_WINDOW(main_window), title);
902 txt = g_strdup_printf (_("%d %s, %d unread"),
903 num, num==1 ? _("item") : _("items"), unread);
904 gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
907 modest_header_view_set_folder (header_view, folder);
908 modest_widget_memory_restore (conf, G_OBJECT(header_view),
914 _modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
915 const gchar* account_name,
919 ModestMainWindow *main_window)
922 GtkWidget *dialog, *entry, *remember_pass_check;
924 dialog = gtk_dialog_new_with_buttons (_("Password requested"),
925 GTK_WINDOW (main_window),
933 txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
934 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
938 entry = gtk_entry_new_with_max_length (40);
939 gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
940 gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
942 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
945 remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
946 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
949 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
951 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
952 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
959 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
964 gtk_widget_destroy (dialog);
966 while (gtk_events_pending ())
967 gtk_main_iteration ();
970 /****************************************************/
972 * below some stuff to clearup statusbar messages after 1,5 seconds....
975 GtkWidget *status_bar;
976 GtkWidget *progress_bar;
981 on_statusbar_remove_msg (StatusRemoveData *data)
983 /* we need to test types, as this callback maybe called after the
984 * widgets have been destroyed
986 if (GTK_IS_STATUSBAR(data->status_bar))
987 gtk_statusbar_remove (GTK_STATUSBAR(data->status_bar),
989 if (GTK_IS_PROGRESS_BAR(data->progress_bar))
990 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(data->progress_bar),
997 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
1000 StatusRemoveData *data;
1001 GtkWidget *status_bar, *progress_bar;
1006 progress_bar = modest_widget_factory_get_progress_bar (factory);
1007 status_bar = modest_widget_factory_get_status_bar (factory);
1009 id = gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
1011 data = g_new (StatusRemoveData, 1);
1012 data->status_bar = status_bar;
1013 data->progress_bar = progress_bar;
1016 g_timeout_add (1500, (GSourceFunc)on_statusbar_remove_msg, data);
1018 /****************************************************************************/
1021 _modest_ui_actions_on_connection_changed (TnyDevice *device,
1023 ModestMainWindow *main_window)
1025 GtkWidget *online_toggle;
1026 ModestHeaderView *header_view;
1027 ModestWidgetFactory *widget_factory;
1029 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1030 header_view = modest_widget_factory_get_header_view (widget_factory);
1031 online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
1033 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
1035 gtk_button_set_label (GTK_BUTTON(online_toggle),
1036 online ? _("Online") : _("Offline"));
1038 statusbar_push (widget_factory, 0,
1039 online ? _("Modest went online") : _("Modest went offline"));
1040 g_object_unref (G_OBJECT (widget_factory));
1042 /* If Modest has became online and the header view has a
1043 header selected then show it */
1045 GtkTreeSelection *selected;
1047 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1048 _modest_header_view_change_selection (selected, header_view);
1053 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1054 ModestMainWindow *main_window)
1058 TnyPlatformFactory *factory;
1059 TnyAccountStore *account_store;
1061 /* Get device. Do not ask the platform factory for it, because
1062 it returns always a new one */
1063 factory = modest_tny_platform_factory_get_instance ();
1064 account_store = tny_platform_factory_new_account_store (factory);
1065 device = tny_account_store_get_device (account_store);
1067 online = gtk_toggle_button_get_active (toggle);
1070 tny_device_force_online (device);
1072 tny_device_force_offline (device);
1076 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1077 ModestItemType type,
1078 ModestMainWindow *main_window)
1084 TnyPlatformFactory *factory;
1085 TnyAccountStore *account_store;
1087 item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1089 /* Get device. Do not ask the platform factory for it, because
1090 it returns always a new one */
1091 factory = modest_tny_platform_factory_get_instance ();
1092 account_store = tny_platform_factory_new_account_store (factory);
1093 device = tny_account_store_get_device (account_store);
1095 gdk_threads_enter ();
1096 online = tny_device_is_online (device);
1099 /* already online -- the item is simply not there... */
1100 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1102 GTK_MESSAGE_WARNING,
1104 _("The %s you selected cannot be found"),
1106 gtk_dialog_run (GTK_DIALOG(dialog));
1109 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1110 GTK_WINDOW (main_window),
1113 GTK_RESPONSE_REJECT,
1115 GTK_RESPONSE_ACCEPT,
1118 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1119 "Do you want to get online?"), item);
1120 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1121 gtk_label_new (txt), FALSE, FALSE, 0);
1122 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1125 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1126 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1127 tny_device_force_online (device);
1130 gtk_widget_destroy (dialog);
1131 gdk_threads_leave ();
1137 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view,
1141 ModestMainWindow *main_window)
1143 GtkWidget *progress_bar;
1144 ModestWidgetFactory *widget_factory;
1146 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1147 progress_bar = modest_widget_factory_get_progress_bar (widget_factory);
1150 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1151 (gdouble)num/(gdouble)total);
1153 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1155 statusbar_push (widget_factory, 0, msg);
1158 g_object_unref (G_OBJECT (widget_factory));
1164 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview,
1166 ModestMainWindow *main_window)
1168 ModestWidgetFactory *widget_factory;
1170 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1171 statusbar_push (widget_factory, 0, link);
1172 g_object_unref (G_OBJECT (widget_factory));
1174 /* TODO: do something */
1179 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview,
1181 ModestMainWindow *main_window)
1184 ModestWidgetFactory *widget_factory;
1186 msg = g_strdup_printf (_("Opening %s..."), link);
1187 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1188 statusbar_push (widget_factory, 0, msg);
1190 g_object_unref (G_OBJECT (widget_factory));
1194 /* TODO: do something */
1198 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview,
1200 ModestMainWindow *main_window)
1203 ModestWidgetFactory *widget_factory;
1205 msg = g_strdup_printf (_("Opening attachment %d..."), index);
1206 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1207 statusbar_push (widget_factory, 0, msg);
1210 g_object_unref (G_OBJECT (widget_factory));
1211 /* TODO: do something */
1215 _modest_ui_actions_on_send (GtkWidget *widget,
1216 ModestEditMsgWindow *edit_window)
1218 TnyTransportAccount *transport_account;
1219 ModestMailOperation *mail_operation;
1222 data = modest_edit_msg_window_get_msg_data (edit_window);
1224 /* FIXME: Code added just for testing. The final version will
1225 use the send queue provided by tinymail and some
1230 TnyAccountStore *account_store;
1232 accounts = TNY_LIST(tny_simple_list_new ());
1233 account_store = modest_window_get_account_store (MODEST_WINDOW (edit_window));
1234 tny_account_store_get_accounts (account_store, accounts,
1235 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1236 g_object_unref (G_OBJECT (account_store));
1238 iter = tny_list_create_iterator(accounts);
1239 tny_iterator_first (iter);
1240 if (tny_iterator_is_done (iter)) {
1241 /* FIXME: Add error handling through mail operation */
1242 g_printerr("modest: no transport accounts defined\n");
1243 modest_edit_msg_window_free_msg_data (edit_window, data);
1246 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1247 g_object_ref (transport_account);
1249 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1250 g_object_unref (G_OBJECT (accounts));
1251 g_object_unref (G_OBJECT (iter));
1254 mail_operation = modest_mail_operation_new ();
1256 modest_mail_operation_send_new_mail (mail_operation,
1266 g_object_unref (G_OBJECT (mail_operation));
1267 g_object_unref (G_OBJECT (transport_account));
1268 modest_edit_msg_window_free_msg_data (edit_window, data);
1270 /* Save settings and close the window */
1271 /* save_settings (edit_window) */
1272 gtk_widget_destroy (GTK_WIDGET (edit_window));
1276 * Shows a dialog with an entry that asks for some text. The returned
1277 * value must be freed by the caller. The dialog window title will be
1281 ask_for_folder_name (GtkWindow *parent_window,
1284 GtkWidget *dialog, *entry;
1285 gchar *folder_name = NULL;
1287 /* Ask for folder name */
1288 dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1292 GTK_RESPONSE_REJECT,
1294 GTK_RESPONSE_ACCEPT,
1296 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1297 gtk_label_new(title),
1300 entry = gtk_entry_new_with_max_length (40);
1301 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1305 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1307 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1308 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1310 gtk_widget_destroy (dialog);
1316 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1317 ModestMainWindow *main_window)
1319 TnyFolder *parent_folder;
1320 ModestFolderView *folder_view;
1321 ModestWidgetFactory *widget_factory;
1323 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1324 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1325 parent_folder = modest_folder_view_get_selected (folder_view);
1327 if (parent_folder) {
1330 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1331 _("Please enter a name for the new folder"));
1333 if (folder_name != NULL && strlen (folder_name) > 0) {
1334 TnyFolder *new_folder;
1335 ModestMailOperation *mail_op;
1337 mail_op = modest_mail_operation_new ();
1338 new_folder = modest_mail_operation_create_folder (mail_op,
1339 TNY_FOLDER_STORE (parent_folder),
1340 (const gchar *) folder_name);
1342 /* Do anything more? The model
1343 is automatically updated */
1344 g_object_unref (new_folder);
1346 g_object_unref (mail_op);
1348 g_object_unref (parent_folder);
1350 g_object_unref (G_OBJECT (widget_factory));
1354 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1355 ModestMainWindow *main_window)
1358 ModestFolderView *folder_view;
1359 ModestWidgetFactory *widget_factory;
1361 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1362 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1363 folder = modest_folder_view_get_selected (folder_view);
1368 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1369 _("Please enter a new name for the folder"));
1371 if (folder_name != NULL && strlen (folder_name) > 0) {
1372 ModestMailOperation *mail_op;
1374 mail_op = modest_mail_operation_new ();
1375 modest_mail_operation_rename_folder (mail_op,
1377 (const gchar *) folder_name);
1378 g_object_unref (mail_op);
1380 g_object_unref (folder);
1382 g_object_unref (G_OBJECT (widget_factory));
1386 delete_folder (ModestMainWindow *main_window,
1387 gboolean move_to_trash)
1390 ModestFolderView *folder_view;
1391 ModestWidgetFactory *widget_factory;
1392 ModestMailOperation *mail_op;
1394 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1395 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1396 folder = modest_folder_view_get_selected (folder_view);
1398 mail_op = modest_mail_operation_new ();
1399 modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1400 g_object_unref (mail_op);
1404 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1405 ModestMainWindow *main_window)
1407 delete_folder (main_window, FALSE);
1411 _modest_ui_actions_on_move_to_trash_folder (GtkWidget *widget,
1412 ModestMainWindow *main_window)
1414 delete_folder (main_window, TRUE);