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>
48 #define MODEST_UI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
52 typedef struct _GetMsgAsyncHelper {
53 ModestMainWindow *main_window;
59 typedef enum _ReplyForwardAction {
65 typedef struct _ReplyForwardHelper {
66 guint reply_forward_type;
67 ReplyForwardAction action;
72 static GObjectClass *parent_class = NULL;
74 /* 'private'/'protected' functions */
75 static void modest_ui_class_init (ModestUIClass *klass);
76 static void modest_ui_init (ModestUI *obj);
77 static void modest_ui_finalize (GObject *obj);
79 static void register_stock_icons ();
80 static void connect_signals (ModestUI *self);
82 static void reply_forward_func (gpointer data,
84 static void read_msg_func (gpointer data,
86 static void get_msg_cb (TnyFolder *folder,
91 static void reply_forward (GtkWidget *widget,
92 ReplyForwardAction action,
93 ModestMainWindow *main_window);
95 static gchar* ask_for_folder_name (GtkWindow *parent_window,
98 static void _modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
99 const gchar* account_name,
103 ModestMainWindow *main_window);
106 modest_ui_get_type (void)
108 static GType my_type = 0;
110 static const GTypeInfo my_info = {
111 sizeof(ModestUIClass),
112 NULL, /* base init */
113 NULL, /* base finalize */
114 (GClassInitFunc) modest_ui_class_init,
115 NULL, /* class finalize */
116 NULL, /* class data */
119 (GInstanceInitFunc) modest_ui_init,
122 my_type = g_type_register_static (G_TYPE_OBJECT,
131 modest_ui_class_init (ModestUIClass *klass)
133 GObjectClass *gobject_class;
134 gobject_class = (GObjectClass*) klass;
136 parent_class = g_type_class_peek_parent (klass);
137 gobject_class->finalize = modest_ui_finalize;
139 g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
145 modest_ui_init (ModestUI *obj)
147 ModestUIPrivate *priv;
149 priv = MODEST_UI_GET_PRIVATE(obj);
151 priv->widget_factory = NULL;
152 priv->main_window = NULL;
153 priv->account_store = NULL;
158 modest_ui_finalize (GObject *obj)
161 ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
163 if (priv->widget_factory) {
164 g_object_unref (G_OBJECT(priv->widget_factory));
165 priv->widget_factory = NULL;
168 if (priv->ui_manager) {
169 g_object_unref (G_OBJECT(priv->ui_manager));
170 priv->ui_manager = NULL;
173 G_OBJECT_CLASS(parent_class)->finalize (obj);
178 modest_ui_new (TnyAccountStore *account_store)
181 ModestUIPrivate *priv;
182 TnyPlatformFactory *fact;
183 ModestAccountMgr *account_mgr;
185 obj = g_object_new(MODEST_TYPE_UI, NULL);
186 priv = MODEST_UI_GET_PRIVATE(obj);
188 /* Get the platform-dependent instances */
189 fact = modest_tny_platform_factory_get_instance ();
191 priv->account_store = account_store;
193 account_mgr = modest_tny_platform_factory_get_account_mgr_instance
194 (MODEST_TNY_PLATFORM_FACTORY(fact));
196 g_printerr ("modest: could not create ModestAccountMgr instance\n");
197 g_object_unref (obj);
201 priv->widget_factory = modest_widget_factory_new ();
202 if (!priv->widget_factory) {
203 g_printerr ("modest: could not initialize widget factory\n");
207 /* Register our own icons as stock icons in order to
208 use them with the UI manager */
209 register_stock_icons ();
211 return MODEST_UI(obj);
215 on_main_window_destroy (GtkObject *widget, ModestUI *self)
217 /* FIXME: check if there any viewer/editing windows opened */
224 modest_ui_main_window (ModestUI *self)
226 ModestUIPrivate *priv;
228 g_return_val_if_fail (self, NULL);
229 priv = MODEST_UI_GET_PRIVATE(self);
231 if (!priv->main_window) {
233 /* Create main window */
234 priv->main_window = modest_main_window_new (priv->widget_factory,
235 priv->account_store);
237 connect_signals (self);
240 if (!priv->main_window)
241 g_printerr ("modest: could not create main window\n");
243 return priv->main_window;
247 modest_ui_edit_window (ModestUI *self, ModestEditType edit_type)
249 ModestUIPrivate *priv;
250 ModestWindow *edit_window;
252 g_return_val_if_fail (self, NULL);
253 priv = MODEST_UI_GET_PRIVATE(self);
256 edit_window = modest_edit_msg_window_new (priv->widget_factory,
260 /* Connect Edit Window signals */
261 /* connect_edit_window_signals (self); */
267 * This function registers our custom toolbar icons, so they can be
268 * themed. The idea of this function was taken from the gtk-demo
271 register_stock_icons ()
273 static gboolean registered = FALSE;
277 GtkIconFactory *factory;
280 static GtkStockItem items[] = {
281 { MODEST_STOCK_MAIL_SEND, "send mail", 0, 0, NULL },
282 { MODEST_STOCK_NEW_MAIL, "new mail", 0, 0, NULL },
283 { MODEST_STOCK_SEND_RECEIVE, "send receive", 0, 0, NULL },
284 { MODEST_STOCK_REPLY, "reply", 0, 0, NULL },
285 { MODEST_STOCK_REPLY_ALL, "reply all", 0, 0, NULL },
286 { MODEST_STOCK_FORWARD, "forward", 0, 0, NULL },
287 { MODEST_STOCK_DELETE, "delete", 0, 0, NULL },
288 { MODEST_STOCK_NEXT, "next", 0, 0, NULL },
289 { MODEST_STOCK_PREV, "prev", 0, 0, NULL },
290 { MODEST_STOCK_STOP, "stop", 0, 0, NULL }
293 static gchar *items_names [] = {
294 MODEST_TOOLBAR_ICON_MAIL_SEND,
295 MODEST_TOOLBAR_ICON_NEW_MAIL,
296 MODEST_TOOLBAR_ICON_SEND_RECEIVE,
297 MODEST_TOOLBAR_ICON_REPLY,
298 MODEST_TOOLBAR_ICON_REPLY_ALL,
299 MODEST_TOOLBAR_ICON_FORWARD,
300 MODEST_TOOLBAR_ICON_DELETE,
301 MODEST_TOOLBAR_ICON_NEXT,
302 MODEST_TOOLBAR_ICON_PREV,
303 MODEST_TOOLBAR_ICON_STOP
308 /* Register our stock items */
309 gtk_stock_add (items, G_N_ELEMENTS (items));
311 /* Add our custom icon factory to the list of defaults */
312 factory = gtk_icon_factory_new ();
313 gtk_icon_factory_add_default (factory);
315 /* Register icons to accompany stock items */
316 for (i = 0; i < G_N_ELEMENTS (items); i++) {
318 pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
320 if (pixbuf != NULL) {
321 GtkIconSet *icon_set;
322 GdkPixbuf *transparent;
324 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
326 icon_set = gtk_icon_set_new_from_pixbuf (transparent);
327 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
328 gtk_icon_set_unref (icon_set);
329 g_object_unref (pixbuf);
330 g_object_unref (transparent);
333 g_warning ("failed to load %s icon", items_names[i]);
335 /* Drop our reference to the factory, GTK will hold a reference. */
336 g_object_unref (factory);
340 /* FIXME: uninit these as well */
342 connect_signals (ModestUI *self)
345 ModestUIPrivate *priv;
346 ModestFolderView *folder_view;
347 ModestHeaderView *header_view;
348 ModestMsgView *msg_view;
351 priv = MODEST_UI_GET_PRIVATE(self);
353 folder_view = modest_widget_factory_get_folder_view (priv->widget_factory);
354 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
355 msg_view = modest_widget_factory_get_msg_preview (priv->widget_factory);
356 toggle = modest_widget_factory_get_online_toggle (priv->widget_factory);
357 device = tny_account_store_get_device (priv->account_store);
360 g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
361 G_CALLBACK(_modest_ui_actions_on_folder_selection_changed),
364 g_signal_connect (G_OBJECT(header_view), "status_update",
365 G_CALLBACK(_modest_ui_actions_on_header_status_update),
367 g_signal_connect (G_OBJECT(header_view), "header_selected",
368 G_CALLBACK(_modest_ui_actions_on_header_selected),
370 g_signal_connect (G_OBJECT(header_view), "item_not_found",
371 G_CALLBACK(_modest_ui_actions_on_item_not_found),
374 g_signal_connect (G_OBJECT(msg_view), "link_clicked",
375 G_CALLBACK(_modest_ui_actions_on_msg_link_clicked),
377 g_signal_connect (G_OBJECT(msg_view), "link_hover",
378 G_CALLBACK(_modest_ui_actions_on_msg_link_hover),
380 g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
381 G_CALLBACK(_modest_ui_actions_on_msg_attachment_clicked),
385 g_signal_connect (G_OBJECT(device), "connection_changed",
386 G_CALLBACK(_modest_ui_actions_on_connection_changed),
388 g_signal_connect (G_OBJECT(toggle), "toggled",
389 G_CALLBACK(_modest_ui_actions_on_online_toggle_toggled),
393 g_signal_connect (G_OBJECT (priv->account_store),
394 "password_requested",
395 G_CALLBACK(_modest_ui_actions_on_password_requested),
399 g_signal_connect (G_OBJECT(priv->main_window),
401 G_CALLBACK(on_main_window_destroy),
405 /* Init toggle in correct state */
406 _modest_ui_actions_on_connection_changed (device,
407 tny_device_is_online (device),
408 MODEST_MAIN_WINDOW (priv->main_window));
412 /* ***************************************************************** */
413 /* M O D E S T U I A C T I O N S */
414 /* ***************************************************************** */
416 _modest_ui_actions_on_about (GtkWidget *widget,
417 ModestMainWindow *main_window)
420 const gchar *authors[] = {
421 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
424 about = gtk_about_dialog_new ();
425 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
426 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
427 gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
428 _("Copyright (c) 2006, Nokia Corporation\n"
429 "All rights reserved."));
430 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
431 _("a modest e-mail client\n\n"
432 "design and implementation: Dirk-Jan C. Binnema\n"
433 "contributions from the fine people at KernelConcepts and Igalia\n"
434 "uses the tinymail email framework written by Philip van Hoof"));
435 gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
436 gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
438 gtk_dialog_run (GTK_DIALOG (about));
439 gtk_widget_destroy(about);
443 _modest_ui_actions_on_delete (GtkWidget *widget,
444 ModestMainWindow *main_window)
446 ModestWidgetFactory *widget_factory;
447 ModestHeaderView *header_view;
448 TnyList *header_list;
452 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
453 header_view = modest_widget_factory_get_header_view (widget_factory);
454 header_list = modest_header_view_get_selected_headers (header_view);
455 g_object_unref (G_OBJECT(widget_factory));
458 iter = tny_list_create_iterator (header_list);
459 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
460 if (GTK_IS_TREE_MODEL_SORT (model))
461 model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
464 ModestMailOperation *mail_op;
466 header = TNY_HEADER (tny_iterator_get_current (iter));
467 /* TODO: thick grain mail operation involving
468 a list of objects. Composite pattern ??? */
469 mail_op = modest_mail_operation_new ();
471 /* TODO: add confirmation dialog */
474 modest_mail_operation_remove_msg (mail_op, header, TRUE);
476 /* Remove from tree model */
477 if (modest_mail_operation_get_status (mail_op) ==
478 MODEST_MAIL_OPERATION_STATUS_SUCCESS)
479 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
481 /* TODO: error handling management */
483 error = modest_mail_operation_get_error (mail_op);
484 g_warning (error->message);
487 g_object_unref (G_OBJECT (mail_op));
488 g_object_unref (header);
489 tny_iterator_next (iter);
491 } while (!tny_iterator_is_done (iter));
496 _modest_ui_actions_on_quit (GtkWidget *widget,
497 ModestMainWindow *main_window)
499 /* FIXME: save size of main window */
500 /* save_sizes (main_window); */
501 gtk_widget_destroy (GTK_WIDGET (main_window));
505 _modest_ui_actions_on_accounts (GtkWidget *widget,
506 ModestMainWindow *main_window)
508 GtkWidget *account_win;
509 ModestWidgetFactory *widget_factory;
511 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
512 account_win = modest_account_view_window_new (widget_factory);
513 g_object_unref (G_OBJECT(widget_factory));
515 gtk_window_set_transient_for (GTK_WINDOW (account_win),
516 GTK_WINDOW (main_window));
518 gtk_widget_show (account_win);
522 _modest_ui_actions_on_new_msg (GtkWidget *widget,
523 ModestMainWindow *main_window)
525 ModestWindow *msg_win;
526 ModestWidgetFactory *widget_factory;
527 TnyAccountStore *account_store;
529 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
530 account_store = modest_window_get_account_store (MODEST_WINDOW (main_window));
531 msg_win = modest_edit_msg_window_new (widget_factory,
533 MODEST_EDIT_TYPE_NEW);
534 g_object_unref (G_OBJECT (widget_factory));
535 g_object_unref (G_OBJECT (account_store));
537 gtk_widget_show (GTK_WIDGET (msg_win));
541 reply_forward_func (gpointer data, gpointer user_data)
543 ModestWidgetFactory *widget_factory;
544 TnyHeader *new_header;
545 TnyMsg *msg, *new_msg;
546 TnyAccountStore *account_store;
547 GetMsgAsyncHelper *helper;
548 ReplyForwardHelper *rf_helper;
549 ModestWindow *msg_win;
550 ModestEditType edit_type;
552 msg = TNY_MSG (data);
553 helper = (GetMsgAsyncHelper *) user_data;
554 rf_helper = (ReplyForwardHelper *) helper->user_data;
556 /* Create reply mail */
557 switch (rf_helper->action) {
560 modest_mail_operation_create_reply_mail (msg,
562 rf_helper->reply_forward_type,
563 MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
564 case ACTION_REPLY_TO_ALL:
566 modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
567 MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
568 edit_type = MODEST_EDIT_TYPE_REPLY;
572 modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
573 edit_type = MODEST_EDIT_TYPE_FORWARD;
576 g_return_if_reached ();
580 new_header = tny_msg_get_header (new_msg);
581 tny_header_set_from (new_header, rf_helper->from);
582 g_object_unref (G_OBJECT (new_header));
584 /* Show edit window */
585 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
586 account_store = modest_window_get_account_store (MODEST_WINDOW (helper->main_window));
587 msg_win = modest_edit_msg_window_new (widget_factory,
589 MODEST_EDIT_TYPE_NEW);
590 g_object_unref (G_OBJECT (widget_factory));
591 g_object_unref (G_OBJECT (account_store));
592 modest_edit_msg_window_set_msg (MODEST_EDIT_MSG_WINDOW (msg_win),
594 gtk_widget_show (GTK_WIDGET (msg_win));
597 g_object_unref (G_OBJECT (new_msg));
598 g_free (rf_helper->from);
599 g_slice_free (ReplyForwardHelper, rf_helper);
603 * Common code for the reply and forward actions
606 reply_forward (GtkWidget *widget,
607 ReplyForwardAction action,
608 ModestMainWindow *main_window)
610 ModestHeaderView *header_view;
611 ModestWidgetFactory *widget_factory;
612 TnyList *header_list;
613 guint reply_forward_type;
615 TnyPlatformFactory *plat_factory;
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 */
647 /* TODO: get the from string from account */
648 from = g_strdup ("Invalid");
651 rf_helper = g_slice_new0 (ReplyForwardHelper);
652 rf_helper->reply_forward_type = reply_forward_type;
653 rf_helper->action = action;
654 rf_helper->from = from;
656 helper = g_slice_new0 (GetMsgAsyncHelper);
657 helper->main_window = main_window;
658 helper->func = reply_forward_func;
659 helper->iter = tny_list_create_iterator (header_list);
660 helper->user_data = rf_helper;
662 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
663 folder = tny_header_get_folder (header);
665 /* The callback will call it per each header */
666 tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
669 g_object_unref (G_OBJECT (folder));
673 _modest_ui_actions_on_reply (GtkWidget *widget,
674 ModestMainWindow *main_window)
676 reply_forward (widget, ACTION_REPLY, main_window);
680 _modest_ui_actions_on_forward (GtkWidget *widget,
681 ModestMainWindow *main_window)
683 reply_forward (widget, ACTION_FORWARD, main_window);
687 _modest_ui_actions_on_reply_all (GtkWidget *widget,
688 ModestMainWindow *main_window)
690 reply_forward (widget, ACTION_REPLY_TO_ALL, main_window);
694 _modest_ui_actions_on_next (GtkWidget *widget,
695 ModestMainWindow *main_window)
697 ModestHeaderView *header_view;
698 ModestWidgetFactory *widget_factory;
700 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
701 header_view = modest_widget_factory_get_header_view (widget_factory);
702 g_object_unref (G_OBJECT(widget_factory));
704 modest_header_view_select_next (header_view);
708 _modest_ui_actions_toggle_view (GtkWidget *widget,
709 ModestMainWindow *main_window)
711 ModestHeaderView *header_view;
712 ModestWidgetFactory *widget_factory;
714 TnyPlatformFactory *plat_factory;
717 plat_factory = modest_tny_platform_factory_get_instance ();
718 conf = modest_tny_platform_factory_get_conf_instance
719 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
720 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
721 header_view = modest_widget_factory_get_header_view (widget_factory);
722 g_object_unref (G_OBJECT(widget_factory));
724 /* what is saved/restored is depending on the style; thus; we save with
725 * old style, then update the style, and restore for this new style*/
726 modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
728 if (modest_header_view_get_style (header_view) == MODEST_HEADER_VIEW_STYLE_DETAILS)
729 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
731 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_DETAILS);
733 modest_widget_memory_restore (conf, G_OBJECT(header_view), "header-view");
739 * Marks a message as read and passes it to the msg preview widget
742 read_msg_func (gpointer data, gpointer user_data)
744 ModestMsgView *msg_view;
745 ModestWidgetFactory *widget_factory;
748 GetMsgAsyncHelper *helper;
749 TnyHeaderFlags header_flags;
751 msg = TNY_MSG (data);
752 helper = (GetMsgAsyncHelper *) user_data;
754 /* mark message as seen; _set_flags crashes, bug in tinymail? */
755 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
756 header_flags = tny_header_get_flags (header);
757 tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
758 g_object_unref (G_OBJECT (header));
760 /* Set message on msg view */
761 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
762 msg_view = modest_widget_factory_get_msg_preview (widget_factory);
763 g_object_unref (G_OBJECT(widget_factory));
764 modest_msg_view_set_message (msg_view, msg);
768 * This function is a generic handler for the tny_folder_get_msg_async
769 * call. It expects as user_data a #GetMsgAsyncHelper. This helper
770 * contains a user provided function that is called inside this
771 * method. This will allow us to use this callback in many different
772 * places. This callback performs the common actions for the
773 * get_msg_async call, more specific actions will be done by the user
777 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
779 GetMsgAsyncHelper *helper;
781 helper = (GetMsgAsyncHelper *) user_data;
783 if (*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) {
784 ModestHeaderView *header_view;
785 ModestWidgetFactory *widget_factory;
787 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
788 header_view = modest_widget_factory_get_header_view (widget_factory);
789 g_object_unref (G_OBJECT (widget_factory));
790 _modest_ui_actions_on_item_not_found (header_view,
791 MODEST_ITEM_TYPE_MESSAGE,
792 helper->main_window);
799 /* Call user function */
800 helper->func (msg, user_data);
802 /* Process next element (if exists) */
803 tny_iterator_next (helper->iter);
804 if (tny_iterator_is_done (helper->iter)) {
806 headers = tny_iterator_get_list (helper->iter);
808 g_object_unref (G_OBJECT (headers));
809 g_object_unref (G_OBJECT (helper->iter));
810 g_slice_free (GetMsgAsyncHelper, helper);
812 tny_folder_get_msg_async (folder,
813 TNY_HEADER (tny_iterator_get_current (helper->iter)),
818 _modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,
820 ModestMainWindow *main_window)
823 GetMsgAsyncHelper *helper;
826 /* when there's no header, clear the msgview */
828 ModestMsgView *msg_view;
829 ModestWidgetFactory *widget_factory;
830 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
831 msg_view = modest_widget_factory_get_msg_preview (widget_factory);
832 modest_msg_view_set_message (msg_view, NULL);
836 folder = tny_header_get_folder (TNY_HEADER(header));
839 list = tny_simple_list_new ();
840 tny_list_prepend (list, G_OBJECT (header));
842 /* Fill helper data */
843 helper = g_slice_new0 (GetMsgAsyncHelper);
844 helper->main_window = main_window;
845 helper->iter = tny_list_create_iterator (list);
846 helper->func = read_msg_func;
848 tny_folder_get_msg_async (TNY_FOLDER(folder),
853 g_object_unref (G_OBJECT (folder));
857 _modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
860 ModestMainWindow *main_window)
862 GtkLabel *folder_info_label;
863 TnyPlatformFactory *factory;
866 ModestHeaderView *header_view;
867 ModestWidgetFactory *widget_factory;
869 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
871 GTK_LABEL (modest_widget_factory_get_folder_info_label (widget_factory));
874 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
878 factory = modest_tny_platform_factory_get_instance ();
879 header_view = modest_widget_factory_get_header_view (widget_factory);
880 conf = modest_tny_platform_factory_get_conf_instance
881 (MODEST_TNY_PLATFORM_FACTORY(factory));
882 g_object_unref (G_OBJECT (widget_factory));
884 if (!selected) { /* the folder was unselected; save it's settings */
885 modest_widget_memory_save (conf, G_OBJECT (header_view),
887 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
888 modest_header_view_set_folder (header_view, NULL);
889 } else { /* the folder was selected */
892 num = tny_folder_get_all_count (folder);
893 unread = tny_folder_get_unread_count (folder);
895 title = g_strdup_printf ("Modest: %s",
896 tny_folder_get_name (folder));
898 gtk_window_set_title (GTK_WINDOW(main_window), title);
901 txt = g_strdup_printf (_("%d %s, %d unread"),
902 num, num==1 ? _("item") : _("items"), unread);
903 gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
906 modest_header_view_set_folder (header_view, folder);
907 modest_widget_memory_restore (conf, G_OBJECT(header_view),
913 _modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
914 const gchar* account_name,
918 ModestMainWindow *main_window)
921 GtkWidget *dialog, *entry, *remember_pass_check;
923 dialog = gtk_dialog_new_with_buttons (_("Password requested"),
924 GTK_WINDOW (main_window),
932 txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
933 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
937 entry = gtk_entry_new_with_max_length (40);
938 gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
939 gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
941 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
944 remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
945 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
948 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
950 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
951 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
958 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
963 gtk_widget_destroy (dialog);
965 while (gtk_events_pending ())
966 gtk_main_iteration ();
969 /****************************************************/
971 * below some stuff to clearup statusbar messages after 1,5 seconds....
974 GtkWidget *status_bar;
975 GtkWidget *progress_bar;
980 on_statusbar_remove_msg (StatusRemoveData *data)
982 /* we need to test types, as this callback maybe called after the
983 * widgets have been destroyed
985 if (GTK_IS_STATUSBAR(data->status_bar))
986 gtk_statusbar_remove (GTK_STATUSBAR(data->status_bar),
988 if (GTK_IS_PROGRESS_BAR(data->progress_bar))
989 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(data->progress_bar),
996 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
999 StatusRemoveData *data;
1000 GtkWidget *status_bar, *progress_bar;
1005 progress_bar = modest_widget_factory_get_progress_bar (factory);
1006 status_bar = modest_widget_factory_get_status_bar (factory);
1008 id = gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
1010 data = g_new (StatusRemoveData, 1);
1011 data->status_bar = status_bar;
1012 data->progress_bar = progress_bar;
1015 g_timeout_add (1500, (GSourceFunc)on_statusbar_remove_msg, data);
1017 /****************************************************************************/
1020 _modest_ui_actions_on_connection_changed (TnyDevice *device,
1022 ModestMainWindow *main_window)
1024 GtkWidget *online_toggle;
1025 ModestHeaderView *header_view;
1026 ModestWidgetFactory *widget_factory;
1028 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1029 header_view = modest_widget_factory_get_header_view (widget_factory);
1030 online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
1032 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
1034 gtk_button_set_label (GTK_BUTTON(online_toggle),
1035 online ? _("Online") : _("Offline"));
1037 statusbar_push (widget_factory, 0,
1038 online ? _("Modest went online") : _("Modest went offline"));
1039 g_object_unref (G_OBJECT (widget_factory));
1041 /* If Modest has became online and the header view has a
1042 header selected then show it */
1044 GtkTreeSelection *selected;
1046 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1047 _modest_header_view_change_selection (selected, header_view);
1052 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1053 ModestMainWindow *main_window)
1057 TnyPlatformFactory *factory;
1058 TnyAccountStore *account_store;
1060 /* Get device. Do not ask the platform factory for it, because
1061 it returns always a new one */
1062 factory = modest_tny_platform_factory_get_instance ();
1063 account_store = tny_platform_factory_new_account_store (factory);
1064 device = tny_account_store_get_device (account_store);
1066 online = gtk_toggle_button_get_active (toggle);
1069 tny_device_force_online (device);
1071 tny_device_force_offline (device);
1075 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1076 ModestItemType type,
1077 ModestMainWindow *main_window)
1083 TnyPlatformFactory *factory;
1084 TnyAccountStore *account_store;
1086 item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1088 /* Get device. Do not ask the platform factory for it, because
1089 it returns always a new one */
1090 factory = modest_tny_platform_factory_get_instance ();
1091 account_store = tny_platform_factory_new_account_store (factory);
1092 device = tny_account_store_get_device (account_store);
1094 gdk_threads_enter ();
1095 online = tny_device_is_online (device);
1098 /* already online -- the item is simply not there... */
1099 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1101 GTK_MESSAGE_WARNING,
1103 _("The %s you selected cannot be found"),
1105 gtk_dialog_run (GTK_DIALOG(dialog));
1108 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1109 GTK_WINDOW (main_window),
1112 GTK_RESPONSE_REJECT,
1114 GTK_RESPONSE_ACCEPT,
1117 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1118 "Do you want to get online?"), item);
1119 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1120 gtk_label_new (txt), FALSE, FALSE, 0);
1121 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1124 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1125 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1126 tny_device_force_online (device);
1129 gtk_widget_destroy (dialog);
1130 gdk_threads_leave ();
1136 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view,
1140 ModestMainWindow *main_window)
1142 GtkWidget *progress_bar;
1143 ModestWidgetFactory *widget_factory;
1145 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1146 progress_bar = modest_widget_factory_get_progress_bar (widget_factory);
1149 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1150 (gdouble)num/(gdouble)total);
1152 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1154 statusbar_push (widget_factory, 0, msg);
1157 g_object_unref (G_OBJECT (widget_factory));
1163 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview,
1165 ModestMainWindow *main_window)
1167 ModestWidgetFactory *widget_factory;
1169 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1170 statusbar_push (widget_factory, 0, link);
1171 g_object_unref (G_OBJECT (widget_factory));
1173 /* TODO: do something */
1178 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview,
1180 ModestMainWindow *main_window)
1183 ModestWidgetFactory *widget_factory;
1185 msg = g_strdup_printf (_("Opening %s..."), link);
1186 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1187 statusbar_push (widget_factory, 0, msg);
1189 g_object_unref (G_OBJECT (widget_factory));
1193 /* TODO: do something */
1197 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview,
1199 ModestMainWindow *main_window)
1202 ModestWidgetFactory *widget_factory;
1204 msg = g_strdup_printf (_("Opening attachment %d..."), index);
1205 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1206 statusbar_push (widget_factory, 0, msg);
1209 g_object_unref (G_OBJECT (widget_factory));
1210 /* TODO: do something */
1214 _modest_ui_actions_on_send (GtkWidget *widget,
1215 ModestEditMsgWindow *edit_window)
1217 TnyTransportAccount *transport_account;
1218 ModestMailOperation *mail_operation;
1221 data = modest_edit_msg_window_get_msg_data (edit_window);
1223 /* FIXME: Code added just for testing. The final version will
1224 use the send queue provided by tinymail and some
1229 TnyAccountStore *account_store;
1231 accounts = TNY_LIST(tny_simple_list_new ());
1232 account_store = modest_window_get_account_store (MODEST_WINDOW (edit_window));
1233 tny_account_store_get_accounts (account_store, accounts,
1234 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1235 g_object_unref (G_OBJECT (account_store));
1237 iter = tny_list_create_iterator(accounts);
1238 tny_iterator_first (iter);
1239 if (tny_iterator_is_done (iter)) {
1240 /* FIXME: Add error handling through mail operation */
1241 g_printerr("modest: no transport accounts defined\n");
1242 modest_edit_msg_window_free_msg_data (edit_window, data);
1245 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1246 g_object_ref (transport_account);
1248 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1249 g_object_unref (G_OBJECT (accounts));
1250 g_object_unref (G_OBJECT (iter));
1253 mail_operation = modest_mail_operation_new ();
1255 modest_mail_operation_send_new_mail (mail_operation,
1265 g_object_unref (G_OBJECT (mail_operation));
1266 g_object_unref (G_OBJECT (transport_account));
1267 modest_edit_msg_window_free_msg_data (edit_window, data);
1269 /* Save settings and close the window */
1270 /* save_settings (edit_window) */
1271 gtk_widget_destroy (GTK_WIDGET (edit_window));
1275 * Shows a dialog with an entry that asks for some text. The returned
1276 * value must be freed by the caller. The dialog window title will be
1280 ask_for_folder_name (GtkWindow *parent_window,
1283 GtkWidget *dialog, *entry;
1284 gchar *folder_name = NULL;
1286 /* Ask for folder name */
1287 dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1291 GTK_RESPONSE_REJECT,
1293 GTK_RESPONSE_ACCEPT,
1295 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1296 gtk_label_new(title),
1299 entry = gtk_entry_new_with_max_length (40);
1300 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1304 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1306 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1307 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1309 gtk_widget_destroy (dialog);
1315 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1316 ModestMainWindow *main_window)
1318 TnyFolder *parent_folder;
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 parent_folder = modest_folder_view_get_selected (folder_view);
1326 if (parent_folder) {
1329 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1330 _("Please enter a name for the new folder"));
1332 if (folder_name != NULL && strlen (folder_name) > 0) {
1333 TnyFolder *new_folder;
1334 ModestMailOperation *mail_op;
1336 mail_op = modest_mail_operation_new ();
1337 new_folder = modest_mail_operation_create_folder (mail_op,
1338 TNY_FOLDER_STORE (parent_folder),
1339 (const gchar *) folder_name);
1341 /* Do anything more? The model
1342 is automatically updated */
1343 g_object_unref (new_folder);
1345 g_object_unref (mail_op);
1347 g_object_unref (parent_folder);
1349 g_object_unref (G_OBJECT (widget_factory));
1353 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1354 ModestMainWindow *main_window)
1356 g_print ("Rename Folder");
1360 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1361 ModestMainWindow *main_window)
1363 g_print ("Delete Folder");