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-runtime.h>
37 #include "modest-ui-priv.h"
38 #include "modest-ui.h"
39 #include "modest-ui-actions.h"
40 #include "modest-icon-names.h"
41 #include "modest-tny-platform-factory.h"
42 #include "modest-account-view-window.h"
43 #include "modest-account-mgr-helpers.h"
44 #include "modest-main-window.h"
45 #include "modest-mail-operation.h"
46 #include "modest-msg-view-window.h"
47 #include <modest-widget-memory.h>
48 #include <tny-error.h>
49 #include <tny-simple-list.h>
50 #include <tny-msg-view.h>
51 #include <tny-device.h>
53 #define MODEST_UI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
57 typedef struct _GetMsgAsyncHelper {
58 ModestMainWindow *main_window;
64 typedef enum _ReplyForwardAction {
70 typedef struct _ReplyForwardHelper {
71 guint reply_forward_type;
72 ReplyForwardAction action;
77 static GObjectClass *parent_class = NULL;
79 /* 'private'/'protected' functions */
80 static void modest_ui_class_init (ModestUIClass *klass);
81 static void modest_ui_init (ModestUI *obj);
82 static void modest_ui_finalize (GObject *obj);
84 static void register_stock_icons ();
85 static void connect_signals (ModestUI *self);
87 static void reply_forward_func (gpointer data,
89 static void read_msg_func (gpointer data,
91 static void get_msg_cb (TnyFolder *folder,
96 static void reply_forward (GtkWidget *widget,
97 ReplyForwardAction action,
98 ModestMainWindow *main_window);
100 static gchar* ask_for_folder_name (GtkWindow *parent_window,
103 static void _modest_ui_actions_on_connection_changed (TnyDevice *device,
105 ModestUI *modest_ui);
108 static void _modest_ui_actions_on_accounts_reloaded (TnyAccountStore *store,
111 static void _modest_ui_actions_on_folder_moved (ModestFolderView *folder_view,
113 TnyFolderStore *parent,
118 modest_ui_get_type (void)
120 static GType my_type = 0;
122 static const GTypeInfo my_info = {
123 sizeof(ModestUIClass),
124 NULL, /* base init */
125 NULL, /* base finalize */
126 (GClassInitFunc) modest_ui_class_init,
127 NULL, /* class finalize */
128 NULL, /* class data */
131 (GInstanceInitFunc) modest_ui_init,
134 my_type = g_type_register_static (G_TYPE_OBJECT,
143 modest_ui_class_init (ModestUIClass *klass)
145 GObjectClass *gobject_class;
146 gobject_class = (GObjectClass*) klass;
148 parent_class = g_type_class_peek_parent (klass);
149 gobject_class->finalize = modest_ui_finalize;
151 g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
157 modest_ui_init (ModestUI *obj)
159 ModestUIPrivate *priv;
161 priv = MODEST_UI_GET_PRIVATE(obj);
163 priv->main_window = NULL;
168 modest_ui_finalize (GObject *obj)
170 ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
172 if (priv->ui_manager) {
173 g_object_unref (G_OBJECT(priv->ui_manager));
174 priv->ui_manager = NULL;
177 priv->main_window = NULL;
179 G_OBJECT_CLASS(parent_class)->finalize (obj);
187 ModestUIPrivate *priv;
189 obj = g_object_new(MODEST_TYPE_UI, NULL);
190 priv = MODEST_UI_GET_PRIVATE(obj);
192 /* Register our own icons as stock icons in order to
193 use them with the UI manager */
194 register_stock_icons ();
196 return MODEST_UI(obj);
200 on_main_window_destroy (GtkObject *widget, ModestUI *self)
202 /* FIXME: check if there any viewer/editing windows opened */
209 modest_ui_main_window (ModestUI *self)
211 ModestUIPrivate *priv;
213 g_return_val_if_fail (self, NULL);
214 priv = MODEST_UI_GET_PRIVATE(self);
216 if (!priv->main_window) {
217 priv->main_window = modest_main_window_new ();
218 connect_signals (self);
221 if (!priv->main_window)
222 g_printerr ("modest: could not create main window\n");
224 return priv->main_window;
228 modest_ui_edit_window (ModestUI *self, ModestEditType edit_type)
230 ModestUIPrivate *priv;
231 ModestWindow *edit_window;
233 g_return_val_if_fail (self, NULL);
234 priv = MODEST_UI_GET_PRIVATE(self);
237 edit_window = modest_edit_msg_window_new (edit_type);
239 /* Connect Edit Window signals */
240 /* connect_edit_window_signals (self); */
246 * This function registers our custom toolbar icons, so they can be
247 * themed. The idea of this function was taken from the gtk-demo
250 register_stock_icons ()
252 static gboolean registered = FALSE;
256 GtkIconFactory *factory;
259 static GtkStockItem items[] = {
260 { MODEST_STOCK_MAIL_SEND, "send mail", 0, 0, NULL },
261 { MODEST_STOCK_NEW_MAIL, "new mail", 0, 0, NULL },
262 { MODEST_STOCK_SEND_RECEIVE, "send receive", 0, 0, NULL },
263 { MODEST_STOCK_REPLY, "reply", 0, 0, NULL },
264 { MODEST_STOCK_REPLY_ALL, "reply all", 0, 0, NULL },
265 { MODEST_STOCK_FORWARD, "forward", 0, 0, NULL },
266 { MODEST_STOCK_DELETE, "delete", 0, 0, NULL },
267 { MODEST_STOCK_NEXT, "next", 0, 0, NULL },
268 { MODEST_STOCK_PREV, "prev", 0, 0, NULL },
269 /* { MODEST_STOCK_STOP, "stop", 0, 0, NULL } */
272 static gchar *items_names [] = {
273 MODEST_TOOLBAR_ICON_MAIL_SEND,
274 MODEST_TOOLBAR_ICON_NEW_MAIL,
275 MODEST_TOOLBAR_ICON_SEND_RECEIVE,
276 MODEST_TOOLBAR_ICON_REPLY,
277 MODEST_TOOLBAR_ICON_REPLY_ALL,
278 MODEST_TOOLBAR_ICON_FORWARD,
279 MODEST_TOOLBAR_ICON_DELETE,
280 MODEST_TOOLBAR_ICON_NEXT,
281 MODEST_TOOLBAR_ICON_PREV,
282 /* MODEST_TOOLBAR_ICON_STOP */
287 /* Register our stock items */
288 gtk_stock_add (items, G_N_ELEMENTS (items));
290 /* Add our custom icon factory to the list of defaults */
291 factory = gtk_icon_factory_new ();
292 gtk_icon_factory_add_default (factory);
294 /* Register icons to accompany stock items */
295 for (i = 0; i < G_N_ELEMENTS (items); i++) {
297 pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
299 if (pixbuf != NULL) {
300 GtkIconSet *icon_set;
301 GdkPixbuf *transparent;
303 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
305 icon_set = gtk_icon_set_new_from_pixbuf (transparent);
306 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
307 gtk_icon_set_unref (icon_set);
308 g_object_unref (pixbuf);
309 g_object_unref (transparent);
312 g_warning ("failed to load %s icon", items_names[i]);
314 /* Drop our reference to the factory, GTK will hold a reference. */
315 g_object_unref (factory);
319 /* FIXME: uninit these as well */
321 connect_signals (ModestUI *self)
324 TnyAccountStore *account_store;
325 ModestUIPrivate *priv;
326 ModestFolderView *folder_view;
327 ModestHeaderView *header_view;
328 ModestMsgView *msg_view;
330 ModestWidgetFactory *widget_factory;
332 priv = MODEST_UI_GET_PRIVATE(self);
334 widget_factory = modest_runtime_get_widget_factory ();
336 folder_view = modest_widget_factory_get_folder_view (widget_factory);
337 header_view = modest_widget_factory_get_header_view (widget_factory);
338 msg_view = modest_widget_factory_get_msg_preview (widget_factory);
339 toggle = modest_widget_factory_get_online_toggle (widget_factory);
340 account_store = TNY_ACCOUNT_STORE(modest_runtime_get_account_store());
341 device = tny_account_store_get_device (account_store);
344 g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
345 G_CALLBACK(_modest_ui_actions_on_folder_selection_changed),
347 g_signal_connect (G_OBJECT(folder_view), "folder_moved",
348 G_CALLBACK(_modest_ui_actions_on_folder_moved),
352 g_signal_connect (G_OBJECT(header_view), "status_update",
353 G_CALLBACK(_modest_ui_actions_on_header_status_update),
355 g_signal_connect (G_OBJECT(header_view), "header_selected",
356 G_CALLBACK(_modest_ui_actions_on_header_selected),
358 g_signal_connect (G_OBJECT(header_view), "header_activated",
359 G_CALLBACK(_modest_ui_actions_on_header_activated),
361 g_signal_connect (G_OBJECT(header_view), "item_not_found",
362 G_CALLBACK(_modest_ui_actions_on_item_not_found),
365 g_signal_connect (G_OBJECT(msg_view), "link_clicked",
366 G_CALLBACK(_modest_ui_actions_on_msg_link_clicked),
368 g_signal_connect (G_OBJECT(msg_view), "link_hover",
369 G_CALLBACK(_modest_ui_actions_on_msg_link_hover),
371 g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
372 G_CALLBACK(_modest_ui_actions_on_msg_attachment_clicked),
376 g_signal_connect (G_OBJECT (account_store), "accounts_reloaded",
377 G_CALLBACK (_modest_ui_actions_on_accounts_reloaded),
381 g_signal_connect (G_OBJECT(device), "connection_changed",
382 G_CALLBACK(_modest_ui_actions_on_connection_changed),
385 priv->toggle_button_signal=
386 g_signal_connect (G_OBJECT(toggle), "toggled",
387 G_CALLBACK(_modest_ui_actions_on_online_toggle_toggled),
391 g_signal_connect (G_OBJECT(priv->main_window),
393 G_CALLBACK(on_main_window_destroy),
396 /* Init toggle in correct state */
397 _modest_ui_actions_on_connection_changed (device,
398 tny_device_is_online (device),
403 /* ***************************************************************** */
404 /* M O D E S T U I A C T I O N S */
405 /* ***************************************************************** */
407 _modest_ui_actions_on_about (GtkWidget *widget,
408 ModestMainWindow *main_window)
411 const gchar *authors[] = {
412 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
415 about = gtk_about_dialog_new ();
416 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
417 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
418 gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
419 _("Copyright (c) 2006, Nokia Corporation\n"
420 "All rights reserved."));
421 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
422 _("a modest e-mail client\n\n"
423 "design and implementation: Dirk-Jan C. Binnema\n"
424 "contributions from the fine people at KernelConcepts and Igalia\n"
425 "uses the tinymail email framework written by Philip van Hoof"));
426 gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
427 gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
429 gtk_dialog_run (GTK_DIALOG (about));
430 gtk_widget_destroy(about);
434 _modest_ui_actions_on_delete (GtkWidget *widget,
435 ModestMainWindow *main_window)
437 ModestWidgetFactory *widget_factory;
438 ModestHeaderView *header_view;
439 TnyList *header_list;
443 widget_factory = modest_runtime_get_widget_factory ();
444 header_view = modest_widget_factory_get_header_view (widget_factory);
445 header_list = modest_header_view_get_selected_headers (header_view);
448 iter = tny_list_create_iterator (header_list);
449 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
450 if (GTK_IS_TREE_MODEL_SORT (model))
451 model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
454 ModestMailOperation *mail_op;
456 header = TNY_HEADER (tny_iterator_get_current (iter));
457 /* TODO: thick grain mail operation involving
458 a list of objects. Composite pattern ??? */
459 mail_op = modest_mail_operation_new ();
461 /* TODO: add confirmation dialog */
464 modest_mail_operation_remove_msg (mail_op, header, TRUE);
466 /* Remove from tree model */
467 if (modest_mail_operation_get_status (mail_op) ==
468 MODEST_MAIL_OPERATION_STATUS_SUCCESS)
469 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
471 /* TODO: error handling management */
473 error = modest_mail_operation_get_error (mail_op);
474 g_warning (error->message);
477 g_object_unref (G_OBJECT (mail_op));
478 g_object_unref (header);
479 tny_iterator_next (iter);
481 } while (!tny_iterator_is_done (iter));
486 _modest_ui_actions_on_quit (GtkWidget *widget,
487 ModestMainWindow *main_window)
489 /* FIXME: save size of main window */
490 /* save_sizes (main_window); */
491 gtk_widget_destroy (GTK_WIDGET (main_window));
495 _modest_ui_actions_on_accounts (GtkWidget *widget,
496 ModestMainWindow *main_window)
498 GtkWidget *account_win;
499 account_win = modest_account_view_window_new (modest_runtime_get_widget_factory());
501 gtk_window_set_transient_for (GTK_WINDOW (account_win),
502 GTK_WINDOW (main_window));
504 gtk_widget_show (account_win);
508 _modest_ui_actions_on_new_msg (GtkWidget *widget,
509 ModestMainWindow *main_window)
511 ModestWindow *msg_win;
512 msg_win = modest_edit_msg_window_new (MODEST_EDIT_TYPE_NEW);
513 gtk_widget_show_all (GTK_WIDGET (msg_win));
518 _modest_ui_actions_on_open (GtkWidget *widget,
519 ModestMainWindow *main_window)
527 reply_forward_func (gpointer data, gpointer user_data)
529 TnyMsg *msg, *new_msg;
530 GetMsgAsyncHelper *helper;
531 ReplyForwardHelper *rf_helper;
532 ModestWindow *msg_win;
533 ModestEditType edit_type;
535 msg = TNY_MSG (data);
536 helper = (GetMsgAsyncHelper *) user_data;
537 rf_helper = (ReplyForwardHelper *) helper->user_data;
539 /* Create reply mail */
540 switch (rf_helper->action) {
543 modest_mail_operation_create_reply_mail (msg,
545 rf_helper->reply_forward_type,
546 MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
548 case ACTION_REPLY_TO_ALL:
550 modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
551 MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
552 edit_type = MODEST_EDIT_TYPE_REPLY;
556 modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
557 edit_type = MODEST_EDIT_TYPE_FORWARD;
560 g_return_if_reached ();
564 g_warning ("Unable to create a message");
568 /* Show edit window */
569 msg_win = modest_edit_msg_window_new (MODEST_EDIT_TYPE_NEW);
570 modest_edit_msg_window_set_msg (MODEST_EDIT_MSG_WINDOW (msg_win),
572 gtk_widget_show_all (GTK_WIDGET (msg_win));
575 g_object_unref (G_OBJECT (new_msg));
578 g_free (rf_helper->from);
579 g_slice_free (ReplyForwardHelper, rf_helper);
583 * Common code for the reply and forward actions
586 reply_forward (GtkWidget *widget,
587 ReplyForwardAction action,
588 ModestMainWindow *main_window)
590 ModestHeaderView *header_view;
591 ModestAccountMgr *account_mgr;
592 TnyList *header_list;
593 guint reply_forward_type;
595 ModestAccountData *default_account_data;
598 gchar *from, *key, *default_account_name;
599 GetMsgAsyncHelper *helper;
600 ReplyForwardHelper *rf_helper;
602 conf = modest_runtime_get_conf ();
604 /* Get reply or forward type */
605 key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE,
606 (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE);
607 reply_forward_type = modest_conf_get_int (conf, key, NULL);
610 /* Get the list of headers */
611 header_view = modest_widget_factory_get_header_view (modest_runtime_get_widget_factory());
612 header_list = modest_header_view_get_selected_headers (header_view);
616 /* We assume that we can only select messages of the
617 same folder and that we reply all of them from the
618 same account. In fact the interface currently only
619 allows single selection */
620 account_mgr = modest_runtime_get_account_mgr();
621 default_account_name = modest_account_mgr_get_default_account (account_mgr);
622 default_account_data =
623 modest_account_mgr_get_account_data (account_mgr,
624 (const gchar*) default_account_name);
625 from = g_strdup (default_account_data->email);
626 modest_account_mgr_free_account_data (account_mgr, default_account_data);
627 g_free (default_account_name);
630 rf_helper = g_slice_new0 (ReplyForwardHelper);
631 rf_helper->reply_forward_type = reply_forward_type;
632 rf_helper->action = action;
633 rf_helper->from = from;
635 helper = g_slice_new0 (GetMsgAsyncHelper);
636 helper->main_window = main_window;
637 helper->func = reply_forward_func;
638 helper->iter = tny_list_create_iterator (header_list);
639 helper->user_data = rf_helper;
641 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
642 folder = tny_header_get_folder (header);
644 /* The callback will call it per each header */
645 tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
648 g_object_unref (G_OBJECT (header));
649 g_object_unref (G_OBJECT (folder));
653 _modest_ui_actions_on_reply (GtkWidget *widget,
654 ModestMainWindow *main_window)
656 reply_forward (widget, ACTION_REPLY, main_window);
660 _modest_ui_actions_on_forward (GtkWidget *widget,
661 ModestMainWindow *main_window)
663 reply_forward (widget, ACTION_FORWARD, main_window);
667 _modest_ui_actions_on_reply_all (GtkWidget *widget,
668 ModestMainWindow *main_window)
670 reply_forward (widget, ACTION_REPLY_TO_ALL, main_window);
674 _modest_ui_actions_on_next (GtkWidget *widget,
675 ModestMainWindow *main_window)
677 ModestHeaderView *header_view;
679 header_view = modest_widget_factory_get_header_view
680 (modest_runtime_get_widget_factory());
682 modest_header_view_select_next (header_view);
686 _modest_ui_actions_toggle_view (GtkWidget *widget,
687 ModestMainWindow *main_window)
690 ModestHeaderView *header_view;
692 header_view = modest_widget_factory_get_header_view
693 (modest_runtime_get_widget_factory());
695 conf = modest_runtime_get_conf ();
697 /* what is saved/restored is depending on the style; thus; we save with
698 * old style, then update the style, and restore for this new style*/
699 modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
701 if (modest_header_view_get_style (header_view) == MODEST_HEADER_VIEW_STYLE_DETAILS)
702 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
704 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_DETAILS);
706 modest_widget_memory_restore (conf, G_OBJECT(header_view), "header-view");
712 * Marks a message as read and passes it to the msg preview widget
715 read_msg_func (gpointer data, gpointer user_data)
717 ModestMsgView *msg_view;
720 GetMsgAsyncHelper *helper;
721 TnyHeaderFlags header_flags;
723 msg = TNY_MSG (data);
724 helper = (GetMsgAsyncHelper *) user_data;
726 /* mark message as seen; _set_flags crashes, bug in tinymail? */
727 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
728 header_flags = tny_header_get_flags (header);
729 tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
730 g_object_unref (G_OBJECT (header));
732 /* Set message on msg view */
733 msg_view = modest_widget_factory_get_msg_preview
734 (modest_runtime_get_widget_factory());
735 modest_msg_view_set_message (msg_view, msg);
739 * This function is a generic handler for the tny_folder_get_msg_async
740 * call. It expects as user_data a #GetMsgAsyncHelper. This helper
741 * contains a user provided function that is called inside this
742 * method. This will allow us to use this callback in many different
743 * places. This callback performs the common actions for the
744 * get_msg_async call, more specific actions will be done by the user
748 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
750 GetMsgAsyncHelper *helper;
752 helper = (GetMsgAsyncHelper *) user_data;
754 if ((*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) || !msg) {
755 ModestHeaderView *header_view;
756 header_view = modest_widget_factory_get_header_view
757 (modest_runtime_get_widget_factory());
758 _modest_ui_actions_on_item_not_found (header_view,
759 MODEST_ITEM_TYPE_MESSAGE,
760 helper->main_window);
764 /* Call user function */
765 helper->func (msg, user_data);
767 /* Process next element (if exists) */
768 tny_iterator_next (helper->iter);
769 if (tny_iterator_is_done (helper->iter)) {
771 headers = tny_iterator_get_list (helper->iter);
773 g_object_unref (G_OBJECT (headers));
774 g_object_unref (G_OBJECT (helper->iter));
775 g_slice_free (GetMsgAsyncHelper, helper);
778 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
779 tny_folder_get_msg_async (folder, header,
781 g_object_unref (G_OBJECT(header));
786 _modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,
788 ModestMainWindow *main_window)
791 GetMsgAsyncHelper *helper;
794 /* when there's no header, clear the msgview */
796 ModestMsgView *msg_view;
797 msg_view = modest_widget_factory_get_msg_preview
798 (modest_runtime_get_widget_factory());
799 modest_msg_view_set_message (msg_view, NULL);
803 folder = tny_header_get_folder (TNY_HEADER(header));
806 list = tny_simple_list_new ();
807 tny_list_prepend (list, G_OBJECT (header));
809 /* Fill helper data */
810 helper = g_slice_new0 (GetMsgAsyncHelper);
811 helper->main_window = main_window;
812 helper->iter = tny_list_create_iterator (list);
813 helper->func = read_msg_func;
815 tny_folder_get_msg_async (TNY_FOLDER(folder),
820 g_object_unref (G_OBJECT (folder));
826 _modest_ui_actions_on_header_activated (ModestHeaderView *folder_view,
828 ModestMainWindow *main_window)
831 TnyFolder *folder = NULL;
837 folder = tny_header_get_folder (header);
839 g_printerr ("modest: cannot get folder for header\n");
843 /* FIXME: make async?; check error */
844 msg = tny_folder_get_msg (folder, header, NULL);
846 g_printerr ("modest: cannot get msg for header\n");
850 win = modest_msg_view_window_new (msg);
851 gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (main_window));
853 gtk_widget_show_all (GTK_WIDGET(win));
857 g_object_unref (G_OBJECT (folder));
859 g_object_unref (G_OBJECT (folder));
867 _modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
870 ModestMainWindow *main_window)
872 GtkLabel *folder_info_label;
875 ModestHeaderView *header_view;
878 GTK_LABEL (modest_widget_factory_get_folder_info_label
879 (modest_runtime_get_widget_factory()));
882 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
886 header_view = modest_widget_factory_get_header_view (modest_runtime_get_widget_factory());
887 conf = modest_runtime_get_conf ();
889 if (!selected) { /* the folder was unselected; save it's settings */
890 modest_widget_memory_save (conf, G_OBJECT (header_view),
892 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
893 modest_header_view_set_folder (header_view, NULL);
894 } else { /* the folder was selected */
895 if (folder) { /* folder may be NULL */
899 num = tny_folder_get_all_count (folder);
900 unread = tny_folder_get_unread_count (folder);
902 title = g_strdup_printf ("Modest: %s",
903 tny_folder_get_name (folder));
905 gtk_window_set_title (GTK_WINDOW(main_window), title);
908 txt = g_strdup_printf (_("%d %s, %d unread"),
909 num, num==1 ? _("item") : _("items"), unread);
910 gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
913 modest_header_view_set_folder (header_view, folder);
914 modest_widget_memory_restore (conf, G_OBJECT(header_view),
920 /****************************************************/
922 * below some stuff to clearup statusbar messages after 1,5 seconds....
925 progress_bar_clean (GtkWidget *bar)
927 if (GTK_IS_PROGRESS_BAR(bar)) {
928 gtk_progress_bar_set_text (GTK_PROGRESS_BAR(bar), "");
929 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
935 statusbar_clean (GtkWidget *bar)
937 if (GTK_IS_STATUSBAR(bar))
938 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
944 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
946 GtkWidget *status_bar, *progress_bar;
951 progress_bar = modest_widget_factory_get_progress_bar (factory);
952 status_bar = modest_widget_factory_get_status_bar (factory);
954 gtk_widget_show (GTK_WIDGET(status_bar));
955 gtk_widget_show (GTK_WIDGET(progress_bar));
957 gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
959 g_timeout_add (1500, (GSourceFunc)statusbar_clean, status_bar);
960 g_timeout_add (3000, (GSourceFunc)progress_bar_clean, progress_bar);
962 /****************************************************************************/
965 _modest_ui_actions_on_connection_changed (TnyDevice *device,
969 GtkWidget *online_toggle;
970 ModestHeaderView *header_view;
971 ModestWidgetFactory *widget_factory;
972 ModestUIPrivate *priv;
974 const gchar *icon_name;
976 g_return_if_fail (device);
977 g_return_if_fail (self);
979 priv = MODEST_UI_GET_PRIVATE (self);
981 icon_name = online ? GTK_STOCK_CONNECT : GTK_STOCK_DISCONNECT;
982 icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
984 widget_factory = modest_runtime_get_widget_factory ();
985 header_view = modest_widget_factory_get_header_view (widget_factory);
986 online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
988 /* Block handlers in order to avoid unnecessary calls */
989 g_signal_handler_block (G_OBJECT (online_toggle), priv->toggle_button_signal);
990 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle), online);
991 g_signal_handler_unblock (G_OBJECT (online_toggle), priv->toggle_button_signal);
993 gtk_button_set_image (GTK_BUTTON(online_toggle), icon);
994 statusbar_push (widget_factory, 0,
995 online ? _("Modest went online") : _("Modest went offline"));
997 /* If Modest has became online and the header view has a
998 header selected then show it */
999 /* FIXME: there is a race condition if some account needs to
1000 ask the user for a password */
1003 /* GtkTreeSelection *selected; */
1005 /* selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view)); */
1006 /* _modest_header_view_change_selection (selected, header_view); */
1011 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1012 ModestMainWindow *main_window)
1017 device = tny_account_store_get_device
1018 (TNY_ACCOUNT_STORE(modest_runtime_get_account_store()));
1020 online = gtk_toggle_button_get_active (toggle);
1023 tny_device_force_online (device);
1025 tny_device_force_offline (device);
1027 g_object_unref (G_OBJECT (device));
1031 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1032 ModestItemType type,
1033 ModestMainWindow *main_window)
1039 TnyAccountStore *account_store;
1041 item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1043 /* Get device. Do not ask the platform factory for it, because
1044 it returns always a new one */
1045 account_store = TNY_ACCOUNT_STORE (modest_runtime_get_account_store ());
1046 device = tny_account_store_get_device (account_store);
1048 if (g_main_depth > 0)
1049 gdk_threads_enter ();
1050 online = tny_device_is_online (device);
1053 /* already online -- the item is simply not there... */
1054 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1056 GTK_MESSAGE_WARNING,
1058 _("The %s you selected cannot be found"),
1060 gtk_dialog_run (GTK_DIALOG(dialog));
1063 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1064 GTK_WINDOW (main_window),
1067 GTK_RESPONSE_REJECT,
1069 GTK_RESPONSE_ACCEPT,
1072 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1073 "Do you want to get online?"), item);
1074 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1075 gtk_label_new (txt), FALSE, FALSE, 0);
1076 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1079 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1080 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1081 tny_device_force_online (device);
1084 gtk_widget_destroy (dialog);
1085 if (g_main_depth > 0)
1086 gdk_threads_leave ();
1092 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view,
1096 ModestMainWindow *main_window)
1098 GtkWidget *progress_bar;
1101 progress_bar = modest_widget_factory_get_progress_bar
1102 (modest_runtime_get_widget_factory());
1104 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1105 (gdouble)num/(gdouble)total);
1107 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1109 txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
1110 gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
1113 statusbar_push (modest_runtime_get_widget_factory(), 0, msg);
1119 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview,
1121 ModestMainWindow *main_window)
1123 statusbar_push (modest_runtime_get_widget_factory(), 0, link);
1125 /* TODO: do something */
1130 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview,
1132 ModestMainWindow *main_window)
1136 msg = g_strdup_printf (_("Opening %s..."), link);
1137 statusbar_push (modest_runtime_get_widget_factory(), 0, msg);
1140 /* TODO: do something */
1144 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview,
1146 ModestMainWindow *main_window)
1150 msg = g_strdup_printf (_("Opening attachment %d..."), index);
1151 statusbar_push (modest_runtime_get_widget_factory(), 0, msg);
1154 /* TODO: do something */
1158 _modest_ui_actions_on_send (GtkWidget *widget,
1159 ModestEditMsgWindow *edit_window)
1161 TnyTransportAccount *transport_account;
1162 ModestMailOperation *mail_operation;
1164 gchar *account_name, *from;
1165 ModestAccountMgr *account_mgr;
1168 data = modest_edit_msg_window_get_msg_data (edit_window);
1170 /* FIXME: Code added just for testing. The final version will
1171 use the send queue provided by tinymail and some
1173 account_mgr = modest_runtime_get_account_mgr();
1174 account_name = modest_account_mgr_get_default_account (account_mgr);
1175 if (!account_name) {
1176 g_printerr ("modest: no default account found\n");
1177 modest_edit_msg_window_free_msg_data (edit_window, data);
1181 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_tny_account_by_account
1182 (modest_runtime_get_account_store(),
1184 TNY_ACCOUNT_TYPE_TRANSPORT));
1185 if (!transport_account) {
1186 g_printerr ("modest: no transport account found for '%s'\n", account_name);
1187 g_free (account_name);
1188 modest_edit_msg_window_free_msg_data (edit_window, data);
1191 from = modest_account_mgr_get_from_string (account_mgr, account_name);
1193 mail_operation = modest_mail_operation_new ();
1194 modest_mail_operation_send_new_mail (mail_operation,
1205 g_free (account_name);
1206 g_object_unref (G_OBJECT (mail_operation));
1207 g_object_unref (G_OBJECT (transport_account));
1209 modest_edit_msg_window_free_msg_data (edit_window, data);
1211 /* Save settings and close the window */
1212 /* save_settings (edit_window) */
1213 gtk_widget_destroy (GTK_WIDGET (edit_window));
1217 * Shows a dialog with an entry that asks for some text. The returned
1218 * value must be freed by the caller. The dialog window title will be
1222 ask_for_folder_name (GtkWindow *parent_window,
1225 GtkWidget *dialog, *entry;
1226 gchar *folder_name = NULL;
1228 /* Ask for folder name */
1229 dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1233 GTK_RESPONSE_REJECT,
1235 GTK_RESPONSE_ACCEPT,
1237 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1238 gtk_label_new(title),
1241 entry = gtk_entry_new_with_max_length (40);
1242 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
1246 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1248 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1249 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1251 gtk_widget_destroy (dialog);
1257 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1258 ModestMainWindow *main_window)
1260 TnyFolder *parent_folder;
1261 ModestFolderView *folder_view;
1263 folder_view = modest_widget_factory_get_folder_view
1264 (modest_runtime_get_widget_factory());
1265 parent_folder = modest_folder_view_get_selected (folder_view);
1267 if (parent_folder) {
1270 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1271 _("Please enter a name for the new folder"));
1273 if (folder_name != NULL && strlen (folder_name) > 0) {
1274 TnyFolder *new_folder;
1275 ModestMailOperation *mail_op;
1277 mail_op = modest_mail_operation_new ();
1278 new_folder = modest_mail_operation_create_folder (mail_op,
1279 TNY_FOLDER_STORE (parent_folder),
1280 (const gchar *) folder_name);
1282 /* TODO: tinymail should do this.
1284 modest_folder_view_add_subfolder (folder_view, new_folder);
1286 /* Free new folder */
1287 g_object_unref (new_folder);
1289 g_object_unref (mail_op);
1291 g_object_unref (parent_folder);
1296 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1297 ModestMainWindow *main_window)
1300 ModestFolderView *folder_view;
1302 folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory());
1303 folder = modest_folder_view_get_selected (folder_view);
1308 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1309 _("Please enter a new name for the folder"));
1311 if (folder_name != NULL && strlen (folder_name) > 0) {
1312 ModestMailOperation *mail_op;
1313 const GError *error;
1315 mail_op = modest_mail_operation_new ();
1316 modest_mail_operation_rename_folder (mail_op,
1318 (const gchar *) folder_name);
1320 error = modest_mail_operation_get_error (mail_op);
1322 /* TODO: tinymail should do this.
1324 modest_folder_view_rename (folder_view);
1326 /* TODO: else ? notify error ? */
1328 g_object_unref (mail_op);
1330 g_object_unref (folder);
1335 delete_folder (ModestMainWindow *main_window,
1336 gboolean move_to_trash)
1339 ModestFolderView *folder_view;
1340 ModestMailOperation *mail_op;
1342 folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory());
1343 folder = modest_folder_view_get_selected (folder_view);
1345 mail_op = modest_mail_operation_new ();
1346 modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1347 g_object_unref (mail_op);
1351 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1352 ModestMainWindow *main_window)
1354 delete_folder (main_window, FALSE);
1358 _modest_ui_actions_on_move_to_trash_folder (GtkWidget *widget,
1359 ModestMainWindow *main_window)
1361 delete_folder (main_window, TRUE);
1365 _modest_ui_actions_on_accounts_reloaded (TnyAccountStore *store, gpointer user_data)
1367 ModestFolderView *folder_view;
1369 folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory());
1370 modest_folder_view_update_model (folder_view, store);
1374 _modest_ui_actions_on_folder_moved (ModestFolderView *folder_view,
1376 TnyFolderStore *parent,
1380 ModestMailOperation *mail_op;
1381 const GError *error;
1385 /* Try to move the folder */
1386 mail_op = modest_mail_operation_new ();
1387 modest_mail_operation_move_folder (mail_op, folder, parent);
1389 error = modest_mail_operation_get_error (mail_op);
1393 g_object_unref (G_OBJECT (mail_op));