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)
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_all (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_all (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 */
890 if (folder) { /* folder may be NULL */
894 num = tny_folder_get_all_count (folder);
895 unread = tny_folder_get_unread_count (folder);
897 title = g_strdup_printf ("Modest: %s",
898 tny_folder_get_name (folder));
900 gtk_window_set_title (GTK_WINDOW(main_window), title);
903 txt = g_strdup_printf (_("%d %s, %d unread"),
904 num, num==1 ? _("item") : _("items"), unread);
905 gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
908 modest_header_view_set_folder (header_view, folder);
909 modest_widget_memory_restore (conf, G_OBJECT(header_view),
915 _modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store,
916 const gchar* account_name,
920 ModestMainWindow *main_window)
923 GtkWidget *dialog, *entry, *remember_pass_check;
925 dialog = gtk_dialog_new_with_buttons (_("Password requested"),
926 GTK_WINDOW (main_window),
934 txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
935 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
939 entry = gtk_entry_new_with_max_length (40);
940 gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
941 gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
943 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
946 remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
947 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
950 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
952 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
953 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
960 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
965 gtk_widget_destroy (dialog);
967 while (gtk_events_pending ())
968 gtk_main_iteration ();
971 /****************************************************/
973 * below some stuff to clearup statusbar messages after 1,5 seconds....
976 GtkWidget *status_bar;
977 GtkWidget *progress_bar;
982 on_statusbar_remove_msg (StatusRemoveData *data)
984 /* we need to test types, as this callback maybe called after the
985 * widgets have been destroyed
987 if (GTK_IS_STATUSBAR(data->status_bar))
988 gtk_statusbar_remove (GTK_STATUSBAR(data->status_bar),
990 if (GTK_IS_PROGRESS_BAR(data->progress_bar))
991 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(data->progress_bar),
998 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
1001 StatusRemoveData *data;
1002 GtkWidget *status_bar, *progress_bar;
1007 progress_bar = modest_widget_factory_get_progress_bar (factory);
1008 status_bar = modest_widget_factory_get_status_bar (factory);
1010 id = gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
1012 data = g_new (StatusRemoveData, 1);
1013 data->status_bar = status_bar;
1014 data->progress_bar = progress_bar;
1017 g_timeout_add (1500, (GSourceFunc)on_statusbar_remove_msg, data);
1019 /****************************************************************************/
1022 _modest_ui_actions_on_connection_changed (TnyDevice *device,
1024 ModestMainWindow *main_window)
1026 GtkWidget *online_toggle;
1027 ModestHeaderView *header_view;
1028 ModestWidgetFactory *widget_factory;
1030 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1031 header_view = modest_widget_factory_get_header_view (widget_factory);
1032 online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
1034 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
1036 gtk_button_set_label (GTK_BUTTON(online_toggle),
1037 online ? _("Online") : _("Offline"));
1039 statusbar_push (widget_factory, 0,
1040 online ? _("Modest went online") : _("Modest went offline"));
1041 g_object_unref (G_OBJECT (widget_factory));
1043 /* If Modest has became online and the header view has a
1044 header selected then show it */
1046 GtkTreeSelection *selected;
1048 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1049 _modest_header_view_change_selection (selected, header_view);
1054 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1055 ModestMainWindow *main_window)
1059 TnyPlatformFactory *factory;
1060 TnyAccountStore *account_store;
1062 /* Get device. Do not ask the platform factory for it, because
1063 it returns always a new one */
1064 factory = modest_tny_platform_factory_get_instance ();
1065 account_store = tny_platform_factory_new_account_store (factory);
1066 device = tny_account_store_get_device (account_store);
1068 online = gtk_toggle_button_get_active (toggle);
1071 tny_device_force_online (device);
1073 tny_device_force_offline (device);
1077 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1078 ModestItemType type,
1079 ModestMainWindow *main_window)
1085 TnyPlatformFactory *factory;
1086 TnyAccountStore *account_store;
1088 item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1090 /* Get device. Do not ask the platform factory for it, because
1091 it returns always a new one */
1092 factory = modest_tny_platform_factory_get_instance ();
1093 account_store = tny_platform_factory_new_account_store (factory);
1094 device = tny_account_store_get_device (account_store);
1096 gdk_threads_enter ();
1097 online = tny_device_is_online (device);
1100 /* already online -- the item is simply not there... */
1101 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1103 GTK_MESSAGE_WARNING,
1105 _("The %s you selected cannot be found"),
1107 gtk_dialog_run (GTK_DIALOG(dialog));
1110 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1111 GTK_WINDOW (main_window),
1114 GTK_RESPONSE_REJECT,
1116 GTK_RESPONSE_ACCEPT,
1119 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1120 "Do you want to get online?"), item);
1121 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1122 gtk_label_new (txt), FALSE, FALSE, 0);
1123 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1126 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1127 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1128 tny_device_force_online (device);
1131 gtk_widget_destroy (dialog);
1132 gdk_threads_leave ();
1138 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view,
1142 ModestMainWindow *main_window)
1144 GtkWidget *progress_bar;
1145 ModestWidgetFactory *widget_factory;
1147 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1148 progress_bar = modest_widget_factory_get_progress_bar (widget_factory);
1151 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1152 (gdouble)num/(gdouble)total);
1154 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1156 statusbar_push (widget_factory, 0, msg);
1159 g_object_unref (G_OBJECT (widget_factory));
1165 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview,
1167 ModestMainWindow *main_window)
1169 ModestWidgetFactory *widget_factory;
1171 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1172 statusbar_push (widget_factory, 0, link);
1173 g_object_unref (G_OBJECT (widget_factory));
1175 /* TODO: do something */
1180 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview,
1182 ModestMainWindow *main_window)
1185 ModestWidgetFactory *widget_factory;
1187 msg = g_strdup_printf (_("Opening %s..."), link);
1188 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1189 statusbar_push (widget_factory, 0, msg);
1191 g_object_unref (G_OBJECT (widget_factory));
1195 /* TODO: do something */
1199 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview,
1201 ModestMainWindow *main_window)
1204 ModestWidgetFactory *widget_factory;
1206 msg = g_strdup_printf (_("Opening attachment %d..."), index);
1207 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1208 statusbar_push (widget_factory, 0, msg);
1211 g_object_unref (G_OBJECT (widget_factory));
1212 /* TODO: do something */
1216 _modest_ui_actions_on_send (GtkWidget *widget,
1217 ModestEditMsgWindow *edit_window)
1219 TnyTransportAccount *transport_account;
1220 ModestMailOperation *mail_operation;
1223 data = modest_edit_msg_window_get_msg_data (edit_window);
1225 /* FIXME: Code added just for testing. The final version will
1226 use the send queue provided by tinymail and some
1231 TnyAccountStore *account_store;
1233 accounts = TNY_LIST(tny_simple_list_new ());
1234 account_store = modest_window_get_account_store (MODEST_WINDOW (edit_window));
1235 tny_account_store_get_accounts (account_store, accounts,
1236 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1237 g_object_unref (G_OBJECT (account_store));
1239 iter = tny_list_create_iterator(accounts);
1240 tny_iterator_first (iter);
1241 if (tny_iterator_is_done (iter)) {
1242 /* FIXME: Add error handling through mail operation */
1243 g_printerr("modest: no transport accounts defined\n");
1244 modest_edit_msg_window_free_msg_data (edit_window, data);
1247 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1248 g_object_ref (transport_account);
1250 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1251 g_object_unref (G_OBJECT (accounts));
1252 g_object_unref (G_OBJECT (iter));
1255 mail_operation = modest_mail_operation_new ();
1257 modest_mail_operation_send_new_mail (mail_operation,
1267 g_object_unref (G_OBJECT (mail_operation));
1268 g_object_unref (G_OBJECT (transport_account));
1269 modest_edit_msg_window_free_msg_data (edit_window, data);
1271 /* Save settings and close the window */
1272 /* save_settings (edit_window) */
1273 gtk_widget_destroy (GTK_WIDGET (edit_window));
1277 * Shows a dialog with an entry that asks for some text. The returned
1278 * value must be freed by the caller. The dialog window title will be
1282 ask_for_folder_name (GtkWindow *parent_window,
1285 GtkWidget *dialog, *entry;
1286 gchar *folder_name = NULL;
1288 /* Ask for folder name */
1289 dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1293 GTK_RESPONSE_REJECT,
1295 GTK_RESPONSE_ACCEPT,
1297 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1298 gtk_label_new(title),
1301 entry = gtk_entry_new_with_max_length (40);
1302 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1306 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1308 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1309 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1311 gtk_widget_destroy (dialog);
1317 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1318 ModestMainWindow *main_window)
1320 TnyFolder *parent_folder;
1321 ModestFolderView *folder_view;
1322 ModestWidgetFactory *widget_factory;
1324 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1325 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1326 parent_folder = modest_folder_view_get_selected (folder_view);
1328 if (parent_folder) {
1331 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1332 _("Please enter a name for the new folder"));
1334 if (folder_name != NULL && strlen (folder_name) > 0) {
1335 TnyFolder *new_folder;
1336 ModestMailOperation *mail_op;
1338 mail_op = modest_mail_operation_new ();
1339 new_folder = modest_mail_operation_create_folder (mail_op,
1340 TNY_FOLDER_STORE (parent_folder),
1341 (const gchar *) folder_name);
1343 /* Do anything more? The model
1344 is automatically updated */
1345 g_object_unref (new_folder);
1347 g_object_unref (mail_op);
1349 g_object_unref (parent_folder);
1351 g_object_unref (G_OBJECT (widget_factory));
1355 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1356 ModestMainWindow *main_window)
1359 ModestFolderView *folder_view;
1360 ModestWidgetFactory *widget_factory;
1362 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1363 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1364 folder = modest_folder_view_get_selected (folder_view);
1369 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1370 _("Please enter a new name for the folder"));
1372 if (folder_name != NULL && strlen (folder_name) > 0) {
1373 ModestMailOperation *mail_op;
1375 mail_op = modest_mail_operation_new ();
1376 modest_mail_operation_rename_folder (mail_op,
1378 (const gchar *) folder_name);
1379 g_object_unref (mail_op);
1381 g_object_unref (folder);
1383 g_object_unref (G_OBJECT (widget_factory));
1387 delete_folder (ModestMainWindow *main_window,
1388 gboolean move_to_trash)
1391 ModestFolderView *folder_view;
1392 ModestWidgetFactory *widget_factory;
1393 ModestMailOperation *mail_op;
1395 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1396 folder_view = modest_widget_factory_get_folder_view (widget_factory);
1397 folder = modest_folder_view_get_selected (folder_view);
1399 mail_op = modest_mail_operation_new ();
1400 modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1401 g_object_unref (mail_op);
1405 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1406 ModestMainWindow *main_window)
1408 delete_folder (main_window, FALSE);
1412 _modest_ui_actions_on_move_to_trash_folder (GtkWidget *widget,
1413 ModestMainWindow *main_window)
1415 delete_folder (main_window, TRUE);