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.
29 #include <glib/gi18n.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
34 #include <tny-mime-part.h>
35 #include <tny-vfs-stream.h>
36 #include "modest-marshal.h"
37 #include "modest-platform.h"
38 #include <modest-maemo-utils.h>
39 #include <modest-tny-msg.h>
40 #include <modest-msg-view-window.h>
41 #include <modest-attachments-view.h>
42 #include <modest-main-window-ui.h>
43 #include "modest-msg-view-window-ui-dimming.h"
44 #include <modest-widget-memory.h>
45 #include <modest-runtime.h>
46 #include <modest-window-priv.h>
47 #include <modest-tny-folder.h>
48 #include <modest-text-utils.h>
49 #include <modest-account-mgr-helpers.h>
50 #include "modest-progress-bar-widget.h"
51 #include "modest-defs.h"
52 #include "modest-hildon-includes.h"
53 #include "modest-ui-dimming-manager.h"
54 #include <gdk/gdkkeysyms.h>
55 #include <modest-tny-account.h>
56 #include <modest-mime-part-view.h>
57 #include <modest-isearch-view.h>
60 #define DEFAULT_FOLDER "MyDocs/.documents"
62 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
63 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
64 static void modest_header_view_observer_init(
65 ModestHeaderViewObserverIface *iface_class);
66 static void modest_msg_view_window_finalize (GObject *obj);
67 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
69 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
70 ModestMsgViewWindow *obj);
71 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
72 ModestMsgViewWindow *obj);
74 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
75 static void modest_msg_view_window_set_zoom (ModestWindow *window,
77 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
78 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
79 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
80 static gboolean modest_msg_view_window_key_release_event (GtkWidget *window,
83 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
84 GdkEventWindowState *event,
86 static void modest_msg_view_window_scroll_up (ModestWindow *window);
87 static void modest_msg_view_window_scroll_down (ModestWindow *window);
88 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
90 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
91 gboolean show_toolbar);
93 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
95 ModestMsgViewWindow *window);
96 void modest_msg_view_window_on_row_changed(
97 GtkTreeModel *header_model,
100 ModestMsgViewWindow *window);
102 void modest_msg_view_window_on_row_deleted(
103 GtkTreeModel *header_model,
105 ModestMsgViewWindow *window);
107 void modest_msg_view_window_on_row_inserted(
108 GtkTreeModel *header_model,
109 GtkTreePath *tree_path,
110 GtkTreeIter *tree_iter,
111 ModestMsgViewWindow *window);
113 void modest_msg_view_window_on_row_reordered(
114 GtkTreeModel *header_model,
118 ModestMsgViewWindow *window);
120 void modest_msg_view_window_update_model_replaced(
121 ModestHeaderViewObserver *window,
123 const gchar *tny_folder_id);
125 static void cancel_progressbar (GtkToolButton *toolbutton,
126 ModestMsgViewWindow *self);
128 static void on_queue_changed (ModestMailOperationQueue *queue,
129 ModestMailOperation *mail_op,
130 ModestMailOperationQueueNotification type,
131 ModestMsgViewWindow *self);
133 static void on_account_removed (TnyAccountStore *account_store,
137 static void on_move_focus (ModestMsgViewWindow *window,
138 GtkDirectionType direction,
141 static void view_msg_cb (ModestMailOperation *mail_op,
148 static void set_toolbar_mode (ModestMsgViewWindow *self,
149 ModestToolBarModes mode);
151 static void update_window_title (ModestMsgViewWindow *window);
153 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
154 static void init_window (ModestMsgViewWindow *obj);
157 /* list my signals */
163 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
164 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
165 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
168 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
169 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
170 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
171 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
172 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
173 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
174 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
177 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
178 struct _ModestMsgViewWindowPrivate {
181 GtkWidget *main_scroll;
182 GtkWidget *find_toolbar;
185 /* Progress observers */
186 GtkWidget *progress_bar;
187 GSList *progress_widgets;
190 GtkWidget *progress_toolitem;
191 GtkWidget *cancel_toolitem;
192 GtkWidget *prev_toolitem;
193 GtkWidget *next_toolitem;
194 ModestToolBarModes current_toolbar_mode;
196 /* Optimized view enabled */
197 gboolean optimized_view;
199 /* Whether this was created via the *_new_for_search_result() function. */
200 gboolean is_search_result;
202 /* A reference to the @model of the header view
203 * to allow selecting previous/next messages,
204 * if the message is currently selected in the header view.
206 const gchar *header_folder_id;
207 GtkTreeModel *header_model;
208 GtkTreeRowReference *row_reference;
209 GtkTreeRowReference *next_row_reference;
211 gulong clipboard_change_handler;
212 gulong queue_change_handler;
213 gulong account_removed_handler;
214 gulong row_changed_handler;
215 gulong row_deleted_handler;
216 gulong row_inserted_handler;
217 gulong rows_reordered_handler;
220 GtkWidget *remove_attachment_banner;
222 guint progress_bar_timeout;
227 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
228 MODEST_TYPE_MSG_VIEW_WINDOW, \
229 ModestMsgViewWindowPrivate))
231 static GtkWindowClass *parent_class = NULL;
233 /* uncomment the following if you have defined any signals */
234 static guint signals[LAST_SIGNAL] = {0};
237 modest_msg_view_window_get_type (void)
239 static GType my_type = 0;
241 static const GTypeInfo my_info = {
242 sizeof(ModestMsgViewWindowClass),
243 NULL, /* base init */
244 NULL, /* base finalize */
245 (GClassInitFunc) modest_msg_view_window_class_init,
246 NULL, /* class finalize */
247 NULL, /* class data */
248 sizeof(ModestMsgViewWindow),
250 (GInstanceInitFunc) modest_msg_view_window_init,
253 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
254 "ModestMsgViewWindow",
257 static const GInterfaceInfo modest_header_view_observer_info =
259 (GInterfaceInitFunc) modest_header_view_observer_init,
260 NULL, /* interface_finalize */
261 NULL /* interface_data */
264 g_type_add_interface_static (my_type,
265 MODEST_TYPE_HEADER_VIEW_OBSERVER,
266 &modest_header_view_observer_info);
272 save_state (ModestWindow *self)
274 modest_widget_memory_save (modest_runtime_get_conf (),
276 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
281 restore_settings (ModestMsgViewWindow *self)
283 modest_widget_memory_restore (modest_runtime_get_conf (),
285 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
289 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
291 GObjectClass *gobject_class;
292 ModestWindowClass *modest_window_class;
293 gobject_class = (GObjectClass*) klass;
294 modest_window_class = (ModestWindowClass *) klass;
296 parent_class = g_type_class_peek_parent (klass);
297 gobject_class->finalize = modest_msg_view_window_finalize;
299 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
300 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
301 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
302 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
303 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
304 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
306 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
308 modest_window_class->save_state_func = save_state;
310 signals[MSG_CHANGED_SIGNAL] =
311 g_signal_new ("msg-changed",
312 G_TYPE_FROM_CLASS (gobject_class),
314 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
316 modest_marshal_VOID__POINTER_POINTER,
317 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
320 static void modest_header_view_observer_init(
321 ModestHeaderViewObserverIface *iface_class)
323 iface_class->update_func = modest_msg_view_window_update_model_replaced;
327 modest_msg_view_window_init (ModestMsgViewWindow *obj)
329 ModestMsgViewWindowPrivate *priv;
330 ModestWindowPrivate *parent_priv = NULL;
331 GtkActionGroup *action_group = NULL;
332 GError *error = NULL;
333 GdkPixbuf *window_icon;
335 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
336 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
337 parent_priv->ui_manager = gtk_ui_manager_new();
339 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
340 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
342 /* Add common actions */
343 gtk_action_group_add_actions (action_group,
344 modest_action_entries,
345 G_N_ELEMENTS (modest_action_entries),
347 gtk_action_group_add_toggle_actions (action_group,
348 modest_toggle_action_entries,
349 G_N_ELEMENTS (modest_toggle_action_entries),
351 gtk_action_group_add_toggle_actions (action_group,
352 msg_view_toggle_action_entries,
353 G_N_ELEMENTS (msg_view_toggle_action_entries),
355 gtk_action_group_add_radio_actions (action_group,
356 msg_view_zoom_action_entries,
357 G_N_ELEMENTS (msg_view_zoom_action_entries),
359 G_CALLBACK (modest_ui_actions_on_change_zoom),
362 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
363 g_object_unref (action_group);
365 /* Load the UI definition */
366 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
369 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
370 g_error_free (error);
375 /* Add accelerators */
376 gtk_window_add_accel_group (GTK_WINDOW (obj),
377 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
379 priv->is_search_result = FALSE;
381 priv->msg_view = NULL;
382 priv->header_model = NULL;
383 priv->header_folder_id = NULL;
384 priv->clipboard_change_handler = 0;
385 priv->queue_change_handler = 0;
386 priv->account_removed_handler = 0;
387 priv->row_changed_handler = 0;
388 priv->row_deleted_handler = 0;
389 priv->row_inserted_handler = 0;
390 priv->rows_reordered_handler = 0;
391 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
393 priv->optimized_view = FALSE;
394 priv->progress_bar_timeout = 0;
395 priv->purge_timeout = 0;
396 priv->remove_attachment_banner = NULL;
397 priv->msg_uid = NULL;
400 init_window (MODEST_MSG_VIEW_WINDOW(obj));
401 /* Set window icon */
402 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
404 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
405 g_object_unref (window_icon);
409 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
410 GTK_WINDOW(obj),"applications_email_viewer");
415 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
417 ModestMsgViewWindowPrivate *priv = NULL;
419 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
421 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
423 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
425 if (priv->progress_bar_timeout > 0) {
426 g_source_remove (priv->progress_bar_timeout);
427 priv->progress_bar_timeout = 0;
434 set_toolbar_mode (ModestMsgViewWindow *self,
435 ModestToolBarModes mode)
437 ModestWindowPrivate *parent_priv;
438 ModestMsgViewWindowPrivate *priv;
439 /* GtkWidget *widget = NULL; */
441 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
443 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
444 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
446 /* Sets current toolbar mode */
447 priv->current_toolbar_mode = mode;
449 /* Update toolbar dimming state */
450 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
453 case TOOLBAR_MODE_NORMAL:
454 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
455 /* gtk_action_set_sensitive (widget, TRUE); */
456 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
457 /* gtk_action_set_sensitive (widget, TRUE); */
458 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
459 /* gtk_action_set_sensitive (widget, TRUE); */
460 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
461 /* gtk_action_set_sensitive (widget, TRUE); */
463 if (priv->prev_toolitem)
464 gtk_widget_show (priv->prev_toolitem);
466 if (priv->next_toolitem)
467 gtk_widget_show (priv->next_toolitem);
469 if (priv->progress_toolitem)
470 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
471 if (priv->progress_bar)
472 gtk_widget_hide (priv->progress_bar);
474 if (priv->cancel_toolitem)
475 gtk_widget_hide (priv->cancel_toolitem);
477 /* Hide toolbar if optimized view is enabled */
478 if (priv->optimized_view) {
479 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
480 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
484 case TOOLBAR_MODE_TRANSFER:
485 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
486 /* gtk_action_set_sensitive (widget, FALSE); */
487 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
488 /* gtk_action_set_sensitive (widget, FALSE); */
489 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
490 /* gtk_action_set_sensitive (widget, FALSE); */
491 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
492 /* gtk_action_set_sensitive (widget, FALSE); */
494 if (priv->prev_toolitem)
495 gtk_widget_hide (priv->prev_toolitem);
497 if (priv->next_toolitem)
498 gtk_widget_hide (priv->next_toolitem);
500 if (priv->progress_toolitem)
501 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
502 if (priv->progress_bar)
503 gtk_widget_show (priv->progress_bar);
505 if (priv->cancel_toolitem)
506 gtk_widget_show (priv->cancel_toolitem);
508 /* Show toolbar if it's hiden (optimized view ) */
509 if (priv->optimized_view) {
510 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
511 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
516 g_return_if_reached ();
523 menubar_to_menu (GtkUIManager *ui_manager)
525 GtkWidget *main_menu;
527 GList *iter, *children;
529 /* Create new main menu */
530 main_menu = gtk_menu_new();
532 /* Get the menubar from the UI manager */
533 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
535 iter = children = gtk_container_get_children (GTK_CONTAINER (menubar));
539 menu = GTK_WIDGET (iter->data);
540 gtk_widget_reparent(menu, main_menu);
542 iter = g_list_next (iter);
544 g_list_free (children);
550 init_window (ModestMsgViewWindow *obj)
552 GtkWidget *main_vbox;
553 ModestMsgViewWindowPrivate *priv;
554 ModestWindowPrivate *parent_priv;
556 GtkAction *action = NULL;
558 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
559 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
561 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
562 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
563 main_vbox = gtk_vbox_new (FALSE, 6);
566 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
567 conf = modest_runtime_get_conf ();
568 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
569 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
570 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
571 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
572 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
573 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
574 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
575 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
576 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
577 gtk_widget_show (GTK_WIDGET(parent_priv->menubar));
579 #ifdef MODEST_USE_MOZEMBED
580 priv->main_scroll = priv->msg_view;
581 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
583 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
584 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
586 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
587 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
588 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
590 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
591 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
593 priv->find_toolbar = hildon_find_toolbar_new (NULL);
594 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
595 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
596 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
597 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
599 gtk_widget_show_all (GTK_WIDGET(main_vbox));
603 modest_msg_view_window_disconnect_signals (ModestWindow *self)
605 ModestMsgViewWindowPrivate *priv;
606 ModestHeaderView *header_view = NULL;
607 ModestWindow *main_window = NULL;
609 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
611 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
612 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
613 priv->clipboard_change_handler))
614 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
615 priv->clipboard_change_handler);
617 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
618 priv->queue_change_handler))
619 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
620 priv->queue_change_handler);
622 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
623 priv->account_removed_handler))
624 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
625 priv->account_removed_handler);
627 if (priv->header_model) {
628 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
629 priv->row_changed_handler))
630 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
631 priv->row_changed_handler);
633 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
634 priv->row_deleted_handler))
635 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
636 priv->row_deleted_handler);
638 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
639 priv->row_inserted_handler))
640 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
641 priv->row_inserted_handler);
643 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
644 priv->rows_reordered_handler))
645 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
646 priv->rows_reordered_handler);
649 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
650 FALSE); /* don't create */
654 header_view = MODEST_HEADER_VIEW(
655 modest_main_window_get_child_widget(
656 MODEST_MAIN_WINDOW(main_window),
657 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
658 if (header_view == NULL)
661 modest_header_view_remove_observer(header_view,
662 MODEST_HEADER_VIEW_OBSERVER(self));
666 modest_msg_view_window_finalize (GObject *obj)
668 ModestMsgViewWindowPrivate *priv;
670 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
672 /* Sanity check: shouldn't be needed, the window mgr should
673 call this function before */
674 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
676 if (priv->header_model != NULL) {
677 g_object_unref (priv->header_model);
678 priv->header_model = NULL;
681 if (priv->progress_bar_timeout > 0) {
682 g_source_remove (priv->progress_bar_timeout);
683 priv->progress_bar_timeout = 0;
686 if (priv->remove_attachment_banner) {
687 gtk_widget_destroy (priv->remove_attachment_banner);
688 g_object_unref (priv->remove_attachment_banner);
689 priv->remove_attachment_banner = NULL;
692 if (priv->purge_timeout > 0) {
693 g_source_remove (priv->purge_timeout);
694 priv->purge_timeout = 0;
697 if (priv->row_reference) {
698 gtk_tree_row_reference_free (priv->row_reference);
699 priv->row_reference = NULL;
702 if (priv->next_row_reference) {
703 gtk_tree_row_reference_free (priv->next_row_reference);
704 priv->next_row_reference = NULL;
708 g_free (priv->msg_uid);
709 priv->msg_uid = NULL;
712 G_OBJECT_CLASS(parent_class)->finalize (obj);
716 select_next_valid_row (GtkTreeModel *model,
717 GtkTreeRowReference **row_reference,
720 GtkTreeIter tmp_iter;
721 GtkTreePath *path, *next;
722 gboolean retval = FALSE;
724 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
726 path = gtk_tree_row_reference_get_path (*row_reference);
727 gtk_tree_model_get_iter (model, &tmp_iter, path);
728 gtk_tree_row_reference_free (*row_reference);
729 *row_reference = NULL;
731 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
732 next = gtk_tree_model_get_path (model, &tmp_iter);
733 *row_reference = gtk_tree_row_reference_new (model, next);
735 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
736 next = gtk_tree_model_get_path (model, &tmp_iter);
738 /* Ensure that we are not selecting the same */
739 if (gtk_tree_path_compare (path, next) != 0) {
740 *row_reference = gtk_tree_row_reference_new (model, next);
746 gtk_tree_path_free (path);
751 /* TODO: This should be in _init(), with the parameters as properties. */
753 modest_msg_view_window_construct (ModestMsgViewWindow *self,
754 const gchar *modest_account_name,
755 const gchar *msg_uid)
758 ModestMsgViewWindowPrivate *priv = NULL;
759 ModestWindowPrivate *parent_priv = NULL;
760 ModestDimmingRulesGroup *menu_rules_group = NULL;
761 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
762 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
764 obj = G_OBJECT (self);
765 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
766 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
768 priv->msg_uid = g_strdup (msg_uid);
770 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
772 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
773 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
774 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
776 /* Add common dimming rules */
777 modest_dimming_rules_group_add_rules (menu_rules_group,
778 modest_msg_view_menu_dimming_entries,
779 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
780 MODEST_WINDOW (self));
781 modest_dimming_rules_group_add_rules (toolbar_rules_group,
782 modest_msg_view_toolbar_dimming_entries,
783 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
784 MODEST_WINDOW (self));
785 modest_dimming_rules_group_add_rules (clipboard_rules_group,
786 modest_msg_view_clipboard_dimming_entries,
787 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
788 MODEST_WINDOW (self));
790 /* Insert dimming rules group for this window */
791 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
792 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
793 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
794 g_object_unref (menu_rules_group);
795 g_object_unref (toolbar_rules_group);
796 g_object_unref (clipboard_rules_group);
798 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
800 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
802 priv->clipboard_change_handler = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change", G_CALLBACK (modest_msg_view_window_clipboard_owner_change), obj);
803 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
804 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
805 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
806 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
807 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
808 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
809 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
810 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
811 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
812 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
814 g_signal_connect (G_OBJECT (obj), "key-release-event",
815 G_CALLBACK (modest_msg_view_window_key_release_event),
818 g_signal_connect (G_OBJECT (obj), "window-state-event",
819 G_CALLBACK (modest_msg_view_window_window_state_event),
822 g_signal_connect (G_OBJECT (obj), "move-focus",
823 G_CALLBACK (on_move_focus), obj);
825 /* Mail Operation Queue */
826 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
828 G_CALLBACK (on_queue_changed),
831 /* Account manager */
832 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
834 G_CALLBACK(on_account_removed),
837 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
839 priv->last_search = NULL;
841 /* Init the clipboard actions dim status */
842 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
844 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
846 /* Check toolbar dimming rules */
847 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
848 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
852 /* FIXME: parameter checks */
854 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
855 const gchar *modest_account_name,
856 const gchar *msg_uid,
858 GtkTreeRowReference *row_reference)
860 ModestMsgViewWindow *window = NULL;
861 ModestMsgViewWindowPrivate *priv = NULL;
862 TnyFolder *header_folder = NULL;
863 ModestHeaderView *header_view = NULL;
864 ModestWindow *main_window = NULL;
865 ModestWindowMgr *mgr = NULL;
867 mgr = modest_runtime_get_window_mgr ();
868 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
869 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
871 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
873 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
875 /* Remember the message list's TreeModel so we can detect changes
876 * and change the list selection when necessary: */
878 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
880 g_warning ("%s: BUG: no main window", __FUNCTION__);
884 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
885 MODEST_MAIN_WINDOW(main_window),
886 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
887 if (header_view != NULL){
888 header_folder = modest_header_view_get_folder(header_view);
889 g_assert(header_folder != NULL);
890 priv->header_folder_id = tny_folder_get_id(header_folder);
891 g_assert(priv->header_folder_id != NULL);
892 g_object_unref(header_folder);
895 priv->header_model = g_object_ref(model);
896 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
897 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
898 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
900 priv->row_changed_handler = g_signal_connect(
901 GTK_TREE_MODEL(model), "row-changed",
902 G_CALLBACK(modest_msg_view_window_on_row_changed),
904 priv->row_deleted_handler = g_signal_connect(
905 GTK_TREE_MODEL(model), "row-deleted",
906 G_CALLBACK(modest_msg_view_window_on_row_deleted),
908 priv->row_inserted_handler = g_signal_connect (
909 GTK_TREE_MODEL(model), "row-inserted",
910 G_CALLBACK(modest_msg_view_window_on_row_inserted),
912 priv->rows_reordered_handler = g_signal_connect(
913 GTK_TREE_MODEL(model), "rows-reordered",
914 G_CALLBACK(modest_msg_view_window_on_row_reordered),
917 if (header_view != NULL){
918 modest_header_view_add_observer(header_view,
919 MODEST_HEADER_VIEW_OBSERVER(window));
922 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
923 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
924 gtk_widget_show_all (GTK_WIDGET (window));
926 modest_msg_view_window_update_priority (window);
928 /* Check toolbar dimming rules */
929 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
931 return MODEST_WINDOW(window);
935 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
936 const gchar *modest_account_name,
937 const gchar *msg_uid)
939 ModestMsgViewWindow *window = NULL;
940 ModestMsgViewWindowPrivate *priv = NULL;
941 ModestWindowMgr *mgr = NULL;
943 mgr = modest_runtime_get_window_mgr ();
944 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
945 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
946 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
948 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
950 /* Remember that this is a search result,
951 * so we can disable some UI appropriately: */
952 priv->is_search_result = TRUE;
954 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
955 update_window_title (window);
957 return MODEST_WINDOW(window);
961 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
962 const gchar *modest_account_name,
963 const gchar *msg_uid)
966 ModestMsgViewWindowPrivate *priv;
967 ModestWindowMgr *mgr = NULL;
969 g_return_val_if_fail (msg, NULL);
970 mgr = modest_runtime_get_window_mgr ();
971 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
972 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
973 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
974 modest_account_name, msg_uid);
976 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
977 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
979 return MODEST_WINDOW(obj);
982 void modest_msg_view_window_on_row_changed(
983 GtkTreeModel *header_model,
986 ModestMsgViewWindow *window){
987 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
990 void modest_msg_view_window_on_row_deleted(
991 GtkTreeModel *header_model,
993 ModestMsgViewWindow *window){
994 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
997 /* On insertions we check if the folder still has the message we are
998 * showing or do not. If do not, we do nothing. Which means we are still
999 * not attached to any header folder and thus next/prev buttons are
1000 * still dimmed. Once the message that is shown by msg-view is found, the
1001 * new model of header-view will be attached and the references will be set.
1002 * On each further insertions dimming rules will be checked. However
1003 * this requires extra CPU time at least works.
1004 * (An message might be deleted from TnyFolder and thus will not be
1005 * inserted into the model again for example if it is removed by the
1006 * imap server and the header view is refreshed.)
1008 void modest_msg_view_window_on_row_inserted(
1009 GtkTreeModel *new_model,
1010 GtkTreePath *tree_path,
1011 GtkTreeIter *tree_iter,
1012 ModestMsgViewWindow *window){
1013 ModestMsgViewWindowPrivate *priv = NULL;
1014 TnyHeader *header = NULL;
1017 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1019 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1021 /* If we already has a model attached then the message shown by
1022 * msg-view is in it, and thus we do not need any actions but
1023 * to check the dimming rules.*/
1024 if(priv->header_model != NULL){
1025 gtk_tree_row_reference_free(priv->next_row_reference);
1026 priv->next_row_reference = gtk_tree_row_reference_copy(
1027 priv->row_reference);
1028 select_next_valid_row (priv->header_model,
1029 &(priv->next_row_reference), FALSE);
1030 modest_ui_actions_check_toolbar_dimming_rules (
1031 MODEST_WINDOW (window));
1035 /* Check if the newly inserted message is the same we are actually
1036 * showing. IF not, we should remain detached from the header model
1037 * and thus prev and next toolbarbuttons should remain dimmed. */
1038 gtk_tree_model_get (new_model, tree_iter,
1039 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1040 uid = modest_tny_folder_get_header_unique_id(header);
1041 if(!g_str_equal(priv->msg_uid, uid)){
1047 /* Setup row_reference for the actual msg. */
1048 priv->row_reference = gtk_tree_row_reference_new(
1049 new_model, tree_path);
1050 if(priv->row_reference == NULL){
1051 g_warning("No reference for msg header item.");
1055 /* Attach new_model and connect some callback to it to become able
1056 * to detect changes in header-view. */
1057 priv->header_model = g_object_ref(new_model);
1058 g_signal_connect (new_model, "row-changed",
1059 G_CALLBACK (modest_msg_view_window_on_row_changed),
1061 g_signal_connect (new_model, "row-deleted",
1062 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1064 g_signal_connect (new_model, "rows-reordered",
1065 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1068 /* Now set up next_row_reference. */
1069 priv->next_row_reference = gtk_tree_row_reference_copy(
1070 priv->row_reference);
1071 select_next_valid_row (priv->header_model,
1072 &(priv->next_row_reference), FALSE);
1074 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1077 void modest_msg_view_window_on_row_reordered(
1078 GtkTreeModel *header_model,
1082 ModestMsgViewWindow *window){
1083 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1086 /* The modest_msg_view_window_update_model_replaced implements update
1087 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1088 * actually belongs to the header-view is the same as the TnyFolder of
1089 * the message of msg-view or not. If they are different, there is
1090 * nothing to do. If they are the same, then the model has replaced and
1091 * the reference in msg-view shall be replaced from the old model to
1092 * the new model. In this case the view will be detached from it's
1093 * header folder. From this point the next/prev buttons are dimmed.
1095 void modest_msg_view_window_update_model_replaced(
1096 ModestHeaderViewObserver *observer,
1097 GtkTreeModel *model,
1098 const gchar *tny_folder_id){
1099 ModestMsgViewWindowPrivate *priv = NULL;
1100 ModestMsgViewWindow *window = NULL;
1102 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1103 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1105 window = MODEST_MSG_VIEW_WINDOW(observer);
1106 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1108 /* If there is an other folder in the header-view then we do
1109 * not care about it's model (msg list). Else if the
1110 * header-view shows the folder the msg shown by us is in, we
1111 * shall replace our model reference and make some check. */
1112 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1115 /* Model is changed(replaced), so we should forget the old
1116 * one. Because there might be other references and there
1117 * might be some change on the model even if we unreferenced
1118 * it, we need to disconnect our signals here. */
1119 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1120 priv->row_changed_handler))
1121 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1122 priv->row_changed_handler);
1123 priv->row_changed_handler = 0;
1124 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1125 priv->row_deleted_handler))
1126 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1127 priv->row_deleted_handler);
1128 priv->row_deleted_handler = 0;
1129 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1130 priv->row_inserted_handler))
1131 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1132 priv->row_inserted_handler);
1133 priv->row_inserted_handler = 0;
1134 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1135 priv->rows_reordered_handler))
1136 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1137 priv->rows_reordered_handler);
1138 priv->rows_reordered_handler = 0;
1139 g_object_unref(priv->header_model);
1140 priv->header_model = NULL;
1141 g_object_unref(priv->row_reference);
1142 priv->row_reference = NULL;
1143 g_object_unref(priv->next_row_reference);
1144 priv->next_row_reference = NULL;
1146 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1148 g_assert(model != NULL);
1150 /* Also we must connect to the new model for row insertions.
1151 * Only for insertions now. We will need other ones only after
1152 * the msg is show by msg-view is added to the new model. */
1153 priv->row_inserted_handler = g_signal_connect (
1154 model, "row-inserted",
1155 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1160 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1162 ModestMsgViewWindowPrivate *priv= NULL;
1164 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1165 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1167 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1171 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1173 ModestMsgViewWindowPrivate *priv= NULL;
1175 TnyHeader *header = NULL;
1176 GtkTreePath *path = NULL;
1179 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1180 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1182 /* If the message was not obtained from a treemodel,
1183 * for instance if it was opened directly by the search UI:
1185 if (priv->header_model == NULL) {
1186 msg = modest_msg_view_window_get_message (self);
1188 header = tny_msg_get_header (msg);
1189 g_object_unref (msg);
1194 /* Get iter of the currently selected message in the header view: */
1195 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1196 * instead of sometimes retrieving it from the header view?
1197 * Then we wouldn't be dependent on the message actually still being selected
1198 * in the header view. murrayc. */
1199 if (!gtk_tree_row_reference_valid (priv->row_reference))
1201 path = gtk_tree_row_reference_get_path (priv->row_reference);
1202 g_return_val_if_fail (path != NULL, NULL);
1203 gtk_tree_model_get_iter (priv->header_model,
1207 /* Get current message header */
1208 gtk_tree_model_get (priv->header_model, &iter,
1209 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1212 gtk_tree_path_free (path);
1217 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1219 ModestMsgViewWindowPrivate *priv;
1221 g_return_val_if_fail (self, NULL);
1223 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1225 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1229 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1231 ModestMsgViewWindowPrivate *priv;
1233 g_return_val_if_fail (self, NULL);
1235 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1237 return (const gchar*) priv->msg_uid;
1241 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1244 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1245 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1246 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1250 is_active = gtk_toggle_action_get_active (toggle);
1253 gtk_widget_show (priv->find_toolbar);
1254 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1256 gtk_widget_hide (priv->find_toolbar);
1259 /* update the toggle buttons status */
1260 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1261 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1262 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1263 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1268 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1269 ModestMsgViewWindow *obj)
1271 GtkToggleAction *toggle;
1272 ModestWindowPrivate *parent_priv;
1273 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1275 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1276 gtk_toggle_action_set_active (toggle, FALSE);
1280 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1281 ModestMsgViewWindow *obj)
1283 gchar *current_search;
1284 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1286 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1287 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1291 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1293 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1294 g_free (current_search);
1295 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1299 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1301 g_free (priv->last_search);
1302 priv->last_search = g_strdup (current_search);
1303 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1306 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1307 g_free (priv->last_search);
1308 priv->last_search = NULL;
1310 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1313 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1314 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1315 g_free (priv->last_search);
1316 priv->last_search = NULL;
1318 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1322 g_free (current_search);
1327 modest_msg_view_window_set_zoom (ModestWindow *window,
1330 ModestMsgViewWindowPrivate *priv;
1331 ModestWindowPrivate *parent_priv;
1332 GtkAction *action = NULL;
1333 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1335 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1337 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1338 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1339 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1341 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1342 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1344 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1348 modest_msg_view_window_get_zoom (ModestWindow *window)
1350 ModestMsgViewWindowPrivate *priv;
1352 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1354 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1355 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1359 modest_msg_view_window_zoom_plus (ModestWindow *window)
1361 ModestWindowPrivate *parent_priv;
1362 GtkRadioAction *zoom_radio_action;
1363 GSList *group, *node;
1365 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1366 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1367 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1369 group = gtk_radio_action_get_group (zoom_radio_action);
1371 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1372 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1376 for (node = group; node != NULL; node = g_slist_next (node)) {
1377 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1378 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1386 modest_msg_view_window_zoom_minus (ModestWindow *window)
1388 ModestWindowPrivate *parent_priv;
1389 GtkRadioAction *zoom_radio_action;
1390 GSList *group, *node;
1392 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1393 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1394 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1396 group = gtk_radio_action_get_group (zoom_radio_action);
1398 for (node = group; node != NULL; node = g_slist_next (node)) {
1399 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1400 if (node->next != NULL) {
1401 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1404 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1414 modest_msg_view_window_key_release_event (GtkWidget *window,
1418 if (event->type == GDK_KEY_RELEASE) {
1419 switch (event->keyval) {
1421 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1425 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1438 modest_msg_view_window_scroll_up (ModestWindow *window)
1440 ModestMsgViewWindowPrivate *priv;
1441 gboolean return_value;
1443 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1444 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1448 modest_msg_view_window_scroll_down (ModestWindow *window)
1450 ModestMsgViewWindowPrivate *priv;
1451 gboolean return_value;
1453 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1454 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1458 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1461 ModestMsgViewWindowPrivate *priv;
1462 GtkTreeIter tmp_iter;
1463 gboolean is_last_selected;
1465 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1466 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1468 /*if no model (so no rows at all), then virtually we are the last*/
1469 if (!priv->header_model)
1472 path = gtk_tree_row_reference_get_path (priv->row_reference);
1476 is_last_selected = TRUE;
1477 while (is_last_selected) {
1479 gtk_tree_path_next (path);
1480 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1482 gtk_tree_model_get (priv->header_model, &tmp_iter,
1483 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1485 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1486 is_last_selected = FALSE;
1488 gtk_tree_path_free (path);
1489 return is_last_selected;
1493 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1495 ModestMsgViewWindowPrivate *priv;
1497 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1498 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1500 return priv->header_model != NULL;
1504 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1506 ModestMsgViewWindowPrivate *priv;
1508 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1509 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1511 return priv->is_search_result;
1515 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1518 ModestMsgViewWindowPrivate *priv;
1519 gboolean is_first_selected;
1520 GtkTreeIter tmp_iter;
1521 /* gchar * path_string;*/
1523 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1524 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1526 /*if no model (so no rows at all), then virtually we are the first*/
1527 if (!priv->header_model)
1530 path = gtk_tree_row_reference_get_path (priv->row_reference);
1534 /* path_string = gtk_tree_path_to_string (path);
1535 is_first_selected = strcmp (path_string, "0");
1537 g_free (path_string);
1538 gtk_tree_path_free (path);
1540 return is_first_selected;*/
1542 is_first_selected = TRUE;
1543 while (is_first_selected) {
1545 if(!gtk_tree_path_prev (path))
1547 /* Here the 'if' is needless for logic, but let make sure
1548 * iter is valid for gtk_tree_model_get. */
1549 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1551 gtk_tree_model_get (priv->header_model, &tmp_iter,
1552 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1554 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1555 is_first_selected = FALSE;
1557 gtk_tree_path_free (path);
1558 return is_first_selected;
1562 * Reads the message whose summary item is @header. It takes care of
1563 * several things, among others:
1565 * If the message was not previously downloaded then ask the user
1566 * before downloading. If there is no connection launch the connection
1567 * dialog. Update toolbar dimming rules.
1569 * Returns: TRUE if the mail operation was started, otherwise if the
1570 * user do not want to download the message, or if the user do not
1571 * want to connect, then the operation is not issued
1574 message_reader (ModestMsgViewWindow *window,
1575 ModestMsgViewWindowPrivate *priv,
1577 GtkTreeRowReference *row_reference)
1579 ModestMailOperation *mail_op = NULL;
1580 ModestMailOperationTypeOperation op_type;
1581 gboolean already_showing = FALSE;
1582 ModestWindow *msg_window = NULL;
1583 ModestWindowMgr *mgr;
1585 g_return_val_if_fail (row_reference != NULL, FALSE);
1587 mgr = modest_runtime_get_window_mgr ();
1588 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1589 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1592 gtk_window_present (GTK_WINDOW (msg_window));
1593 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1597 /* Msg download completed */
1598 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1599 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1601 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1603 /* Ask the user if he wants to download the message if
1605 if (!tny_device_is_online (modest_runtime_get_device())) {
1606 TnyFolder *folder = NULL;
1607 GtkResponseType response;
1609 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1610 _("mcen_nc_get_msg"));
1611 if (response == GTK_RESPONSE_CANCEL)
1614 /* Offer the connection dialog if necessary */
1615 folder = tny_header_get_folder (header);
1617 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1618 TNY_FOLDER_STORE (folder))) {
1619 g_object_unref (folder);
1622 g_object_unref (folder);
1627 /* New mail operation */
1628 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1629 modest_ui_actions_get_msgs_full_error_handler,
1632 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1633 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1634 g_object_unref (mail_op);
1636 /* Update toolbar dimming rules */
1637 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1643 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1645 ModestMsgViewWindowPrivate *priv;
1646 GtkTreePath *path= NULL;
1647 GtkTreeIter tmp_iter;
1649 gboolean retval = TRUE;
1650 GtkTreeRowReference *row_reference = NULL;
1652 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1653 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1655 /* Update the next row reference if it's not valid. This could
1656 happen if for example the header which it was pointing to,
1657 was deleted. The best place to do it is in the row-deleted
1658 handler but the tinymail model do not work like the glib
1659 tree models and reports the deletion when the row is still
1661 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1662 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1663 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1664 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1667 if (priv->next_row_reference)
1668 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1672 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1674 gtk_tree_model_get_iter (priv->header_model,
1677 gtk_tree_path_free (path);
1679 gtk_tree_model_get (priv->header_model, &tmp_iter,
1680 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1683 /* Read the message & show it */
1684 if (!message_reader (window, priv, header, row_reference)) {
1686 gtk_tree_row_reference_free (row_reference);
1690 g_object_unref (header);
1696 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1698 ModestMsgViewWindowPrivate *priv = NULL;
1699 TnyHeader *header = NULL;
1701 GtkTreePath *path = NULL;
1702 GtkTreeRowReference *row_reference = NULL;
1704 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1705 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1707 /* Check that the model is not empty */
1708 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1711 /* Get the header */
1712 gtk_tree_model_get (priv->header_model,
1714 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1716 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1717 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1718 g_object_unref (header);
1719 return modest_msg_view_window_select_next_message (self);
1722 path = gtk_tree_model_get_path (priv->header_model, &iter);
1723 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1724 gtk_tree_path_free (path);
1726 /* Read the message & show it */
1727 message_reader (self, priv, header, row_reference);
1730 g_object_unref (header);
1736 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1738 ModestMsgViewWindowPrivate *priv = NULL;
1740 GtkTreeRowReference *row_reference = NULL;
1742 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1743 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1745 /* Return inmediatly if there is no header model */
1746 if (!priv->header_model)
1749 path = gtk_tree_row_reference_get_path (priv->row_reference);
1750 while (gtk_tree_path_prev (path)) {
1754 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1755 gtk_tree_model_get (priv->header_model, &iter,
1756 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1760 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1761 g_object_unref (header);
1765 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1766 /* Read the message & show it */
1767 if (!message_reader (window, priv, header, row_reference)) {
1768 gtk_tree_row_reference_free (row_reference);
1769 g_object_unref (header);
1773 gtk_tree_path_free (path);
1774 g_object_unref (header);
1779 gtk_tree_path_free (path);
1784 view_msg_cb (ModestMailOperation *mail_op,
1791 ModestMsgViewWindow *self = NULL;
1792 ModestMsgViewWindowPrivate *priv = NULL;
1793 GtkTreeRowReference *row_reference = NULL;
1795 /* If there was any error */
1796 row_reference = (GtkTreeRowReference *) user_data;
1797 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1798 gtk_tree_row_reference_free (row_reference);
1802 /* Get the window */
1803 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1804 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1805 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1807 /* Update the row reference */
1808 gtk_tree_row_reference_free (priv->row_reference);
1809 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1810 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1811 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1812 gtk_tree_row_reference_free (row_reference);
1814 /* Mark header as read */
1815 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1816 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1818 /* Set new message */
1819 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1820 modest_msg_view_window_update_priority (self);
1821 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1822 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1824 /* Set the new message uid of the window */
1825 if (priv->msg_uid) {
1826 g_free (priv->msg_uid);
1827 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1830 /* Notify the observers */
1831 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1832 0, priv->header_model, priv->row_reference);
1834 /* Free new references */
1835 g_object_unref (self);
1839 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1841 ModestMsgViewWindowPrivate *priv;
1843 TnyFolderType folder_type;
1845 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1847 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1849 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1853 folder = tny_msg_get_folder (msg);
1855 folder_type = tny_folder_get_folder_type (folder);
1856 g_object_unref (folder);
1858 g_object_unref (msg);
1866 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1868 ModestMsgViewWindowPrivate *priv;
1869 TnyHeaderFlags flags = 0;
1871 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1873 if (priv->header_model) {
1876 GtkTreePath *path = NULL;
1878 path = gtk_tree_row_reference_get_path (priv->row_reference);
1879 g_return_if_fail (path != NULL);
1880 gtk_tree_model_get_iter (priv->header_model,
1882 gtk_tree_row_reference_get_path (priv->row_reference));
1884 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1886 flags = tny_header_get_flags (header);
1887 gtk_tree_path_free (path);
1890 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1895 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1897 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1898 ModestWindowPrivate *parent_priv;
1899 ModestWindowMgr *mgr;
1900 gboolean is_fullscreen;
1901 GtkAction *fs_toggle_action;
1904 mgr = modest_runtime_get_window_mgr ();
1905 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1907 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1909 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1910 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1911 if (is_fullscreen != active) {
1912 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1921 set_homogeneous (GtkWidget *widget,
1924 if (GTK_IS_TOOL_ITEM (widget)) {
1925 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1926 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1931 modest_msg_view_window_show_toolbar (ModestWindow *self,
1932 gboolean show_toolbar)
1934 ModestMsgViewWindowPrivate *priv = NULL;
1935 ModestWindowPrivate *parent_priv;
1936 GtkWidget *reply_button = NULL, *menu = NULL;
1937 GtkWidget *placeholder = NULL;
1939 const gchar *action_name;
1942 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1943 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1945 /* Set optimized view status */
1946 priv->optimized_view = !show_toolbar;
1948 if (!parent_priv->toolbar) {
1949 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1951 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1953 /* Set homogeneous toolbar */
1954 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1955 set_homogeneous, NULL);
1957 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1958 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1959 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1960 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1961 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1962 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1963 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1964 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1966 /* Add ProgressBar (Transfer toolbar) */
1967 priv->progress_bar = modest_progress_bar_widget_new ();
1968 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1969 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1970 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1971 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1972 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1974 /* Connect cancel 'clicked' signal to abort progress mode */
1975 g_signal_connect(priv->cancel_toolitem, "clicked",
1976 G_CALLBACK(cancel_progressbar),
1979 /* Add it to the observers list */
1980 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1983 hildon_window_add_toolbar (HILDON_WINDOW (self),
1984 GTK_TOOLBAR (parent_priv->toolbar));
1987 /* Set reply button tap and hold menu */
1988 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1989 "/ToolBar/ToolbarMessageReply");
1990 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1991 "/ToolbarReplyCSM");
1992 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1996 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1997 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1998 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2000 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2001 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
2004 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2005 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2008 /* Update also the actions (to update the toggles in the
2009 menus), we have to do it manually because some other window
2010 of the same time could have changed it (remember that the
2011 toolbar fullscreen mode is shared by all the windows of the
2013 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2014 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2016 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2018 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2019 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2024 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2026 ModestMsgViewWindow *window)
2028 if (!GTK_WIDGET_VISIBLE (window))
2031 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2035 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2037 ModestMsgViewWindowPrivate *priv;
2039 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2040 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2042 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2046 cancel_progressbar (GtkToolButton *toolbutton,
2047 ModestMsgViewWindow *self)
2050 ModestMsgViewWindowPrivate *priv;
2052 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2054 /* Get operation observers and cancel its current operation */
2055 tmp = priv->progress_widgets;
2057 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2058 tmp=g_slist_next(tmp);
2062 observers_empty (ModestMsgViewWindow *self)
2065 ModestMsgViewWindowPrivate *priv;
2066 gboolean is_empty = TRUE;
2067 guint pending_ops = 0;
2069 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2070 tmp = priv->progress_widgets;
2072 /* Check all observers */
2073 while (tmp && is_empty) {
2074 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2075 is_empty = pending_ops == 0;
2077 tmp = g_slist_next(tmp);
2084 on_account_removed (TnyAccountStore *account_store,
2085 TnyAccount *account,
2088 /* Do nothing if it's a transport account, because we only
2089 show the messages of a store account */
2090 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2091 const gchar *parent_acc = NULL;
2092 const gchar *our_acc = NULL;
2094 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2095 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2097 /* Close this window if I'm showing a message of the removed account */
2098 if (strcmp (parent_acc, our_acc) == 0)
2099 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2104 on_queue_changed (ModestMailOperationQueue *queue,
2105 ModestMailOperation *mail_op,
2106 ModestMailOperationQueueNotification type,
2107 ModestMsgViewWindow *self)
2110 ModestMsgViewWindowPrivate *priv;
2111 ModestMailOperationTypeOperation op_type;
2112 ModestToolBarModes mode;
2114 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2115 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2117 /* If this operations was created by another window, do nothing */
2118 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2121 /* Get toolbar mode from operation id*/
2122 op_type = modest_mail_operation_get_type_operation (mail_op);
2124 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2125 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2126 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2127 mode = TOOLBAR_MODE_TRANSFER;
2130 mode = TOOLBAR_MODE_NORMAL;
2134 /* Add operation observers and change toolbar if neccessary*/
2135 tmp = priv->progress_widgets;
2137 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2138 if (mode == TOOLBAR_MODE_TRANSFER) {
2139 /* Enable transfer toolbar mode */
2140 set_toolbar_transfer_mode(self);
2142 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2144 tmp = g_slist_next (tmp);
2149 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2150 if (mode == TOOLBAR_MODE_TRANSFER) {
2152 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2154 tmp = g_slist_next (tmp);
2158 /* If no more operations are being observed, NORMAL mode is enabled again */
2159 if (observers_empty (self)) {
2160 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2168 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2170 ModestMsgViewWindowPrivate *priv;
2171 GList *selected_attachments = NULL;
2173 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2174 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2176 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2178 return selected_attachments;
2182 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2184 ModestMsgViewWindowPrivate *priv;
2185 const gchar *msg_uid;
2186 gchar *attachment_uid = NULL;
2187 gint attachment_index = 0;
2190 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2191 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2192 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2194 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2195 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2196 attachment_index = g_list_index (attachments, mime_part);
2197 g_list_free (attachments);
2199 if (msg_uid && attachment_index >= 0) {
2200 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2203 if (mime_part == NULL) {
2204 gboolean error = FALSE;
2205 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2206 if (selected_attachments == NULL) {
2208 } else if (g_list_length (selected_attachments) > 1) {
2209 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2212 mime_part = (TnyMimePart *) selected_attachments->data;
2213 g_object_ref (mime_part);
2215 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2216 g_list_free (selected_attachments);
2221 g_object_ref (mime_part);
2224 if (tny_mime_part_is_purged (mime_part)) {
2225 g_object_unref (mime_part);
2229 if (!TNY_IS_MSG (mime_part)) {
2230 gchar *filepath = NULL;
2231 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2232 TnyFsStream *temp_stream = NULL;
2233 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid, &filepath);
2236 const gchar *content_type;
2237 content_type = tny_mime_part_get_content_type (mime_part);
2238 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2240 modest_platform_activate_file (filepath, content_type);
2241 g_object_unref (temp_stream);
2243 /* NOTE: files in the temporary area will be automatically
2244 * cleaned after some time if they are no longer in use */
2247 /* message attachment */
2248 TnyHeader *header = NULL;
2249 ModestWindowMgr *mgr;
2250 ModestWindow *msg_win = NULL;
2253 header = tny_msg_get_header (TNY_MSG (mime_part));
2254 mgr = modest_runtime_get_window_mgr ();
2255 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2258 if (msg_win) /* there is already a window for this uid; top it */
2259 gtk_window_present (GTK_WINDOW(msg_win));
2261 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2262 * thus, we don't do anything */
2263 g_warning ("window for is already being created");
2265 /* it's not found, so create a new window for it */
2266 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2267 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2269 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2270 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2271 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2272 modest_window_get_zoom (MODEST_WINDOW (window)));
2273 modest_window_mgr_register_window (mgr, msg_win);
2274 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2275 gtk_widget_show_all (GTK_WIDGET (msg_win));
2278 g_object_unref (mime_part);
2294 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2295 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2296 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2297 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2300 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2304 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2305 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2306 g_free (pair->filename);
2307 g_object_unref (pair->part);
2308 g_slice_free (SaveMimePartPair, pair);
2310 g_list_free (info->pairs);
2313 gtk_widget_destroy (info->banner);
2314 g_object_unref (info->banner);
2315 g_slice_free (SaveMimePartInfo, info);
2320 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2322 if (info->pairs != NULL) {
2323 save_mime_part_to_file (info);
2326 result = info->result;
2328 /* This is a GDK lock because we are an idle callback and
2329 * hildon_banner_show_information is or does Gtk+ code */
2331 gdk_threads_enter (); /* CHECKED */
2332 save_mime_part_info_free (info, TRUE);
2334 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2336 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2338 gdk_threads_leave (); /* CHECKED */
2345 save_mime_part_to_file (SaveMimePartInfo *info)
2347 GnomeVFSResult result;
2348 GnomeVFSHandle *handle;
2350 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2352 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0444);
2353 if (result == GNOME_VFS_OK) {
2354 stream = tny_vfs_stream_new (handle);
2355 tny_mime_part_decode_to_stream (pair->part, stream);
2356 g_object_unref (G_OBJECT (stream));
2357 g_object_unref (pair->part);
2358 g_slice_free (SaveMimePartPair, pair);
2359 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2360 info->result = TRUE;
2362 save_mime_part_info_free (info, FALSE);
2363 info->result = FALSE;
2366 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2371 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2373 gboolean is_ok = TRUE;
2374 gint replaced_files = 0;
2375 const GList *files = info->pairs;
2378 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2379 SaveMimePartPair *pair = iter->data;
2380 if (modest_maemo_utils_file_exists (pair->filename)) {
2384 if (replaced_files) {
2385 GtkWidget *confirm_overwrite_dialog;
2386 const gchar *message = (replaced_files == 1) ?
2387 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2388 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2389 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2392 gtk_widget_destroy (confirm_overwrite_dialog);
2396 save_mime_part_info_free (info, TRUE);
2398 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2399 _CS("sfil_ib_saving"));
2400 info->banner = g_object_ref (banner);
2401 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2402 g_object_unref (banner);
2409 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2411 gboolean clean_list = FALSE;
2412 ModestMsgViewWindowPrivate *priv;
2413 GList *files_to_save = NULL;
2414 GtkWidget *save_dialog = NULL;
2415 gchar *folder = NULL;
2416 gboolean canceled = FALSE;
2417 const gchar *filename = NULL;
2418 gchar *save_multiple_str = NULL;
2420 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2421 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2423 if (mime_parts == NULL) {
2424 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2425 if (mime_parts == NULL)
2430 /* prepare dialog */
2431 if (mime_parts->next == NULL) {
2432 /* only one attachment selected */
2433 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2434 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2435 filename = tny_mime_part_get_filename (mime_part);
2437 g_warning ("Tried to save a non-file attachment");
2441 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2442 g_list_length (mime_parts));
2445 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2446 GTK_FILE_CHOOSER_ACTION_SAVE);
2449 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2450 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2454 if (filename != NULL)
2455 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2458 /* if multiple, set multiple string */
2459 if (save_multiple_str) {
2460 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2464 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2465 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2467 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2468 hildon_banner_show_information
2469 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2473 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2474 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2476 if (tny_mime_part_is_attachment (mime_part)) {
2477 SaveMimePartPair *pair;
2479 if ((mime_parts->next != NULL) &&
2480 (tny_mime_part_get_filename (mime_part) == NULL))
2483 pair = g_slice_new0 (SaveMimePartPair);
2484 if (mime_parts->next == NULL) {
2485 pair->filename = g_strdup (chooser_uri);
2488 g_build_filename (chooser_uri,
2489 tny_mime_part_get_filename (mime_part), NULL);
2491 pair->part = g_object_ref (mime_part);
2492 files_to_save = g_list_prepend (files_to_save, pair);
2496 g_free (chooser_uri);
2499 gtk_widget_destroy (save_dialog);
2502 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2503 g_list_free (mime_parts);
2506 if (files_to_save != NULL) {
2507 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2508 info->pairs = files_to_save;
2509 info->result = TRUE;
2510 save_mime_parts_to_file_with_checks (info);
2515 show_remove_attachment_information (gpointer userdata)
2517 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2518 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2520 /* We're outside the main lock */
2521 gdk_threads_enter ();
2523 if (priv->remove_attachment_banner != NULL) {
2524 gtk_widget_destroy (priv->remove_attachment_banner);
2525 g_object_unref (priv->remove_attachment_banner);
2528 priv->remove_attachment_banner = g_object_ref (
2529 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2531 gdk_threads_leave ();
2537 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2539 ModestMsgViewWindowPrivate *priv;
2540 GList *mime_parts = NULL, *node;
2541 gchar *confirmation_message;
2545 /* TnyFolder *folder; */
2547 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2548 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2551 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2553 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2555 /* Remove already purged messages from mime parts list */
2557 while (node != NULL) {
2558 TnyMimePart *part = TNY_MIME_PART (node->data);
2559 if (tny_mime_part_is_purged (part)) {
2560 GList *deleted_node = node;
2561 node = g_list_next (node);
2562 g_object_unref (part);
2563 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2565 node = g_list_next (node);
2569 if (mime_parts == NULL)
2572 n_attachments = g_list_length (mime_parts);
2573 if (n_attachments == 1) {
2574 const gchar *filename;
2576 if (TNY_IS_MSG (mime_parts->data)) {
2578 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2579 filename = tny_header_get_subject (header);
2580 g_object_unref (header);
2581 if (filename == NULL)
2582 filename = _("mail_va_no_subject");
2584 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2586 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2588 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2589 "mcen_nc_purge_files_text",
2590 n_attachments), n_attachments);
2592 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2593 confirmation_message);
2594 g_free (confirmation_message);
2596 if (response != GTK_RESPONSE_OK)
2599 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2600 /* folder = tny_msg_get_folder (msg); */
2601 /* tny_msg_uncache_attachments (msg); */
2602 /* tny_folder_refresh (folder, NULL); */
2603 /* g_object_unref (folder); */
2605 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2606 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2607 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2610 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2611 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2612 tny_msg_rewrite_cache (msg);
2613 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2615 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2616 g_list_free (mime_parts);
2618 if (priv->purge_timeout > 0) {
2619 g_source_remove (priv->purge_timeout);
2620 priv->purge_timeout = 0;
2623 if (priv->remove_attachment_banner) {
2624 gtk_widget_destroy (priv->remove_attachment_banner);
2625 g_object_unref (priv->remove_attachment_banner);
2626 priv->remove_attachment_banner = NULL;
2634 update_window_title (ModestMsgViewWindow *window)
2636 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2638 TnyHeader *header = NULL;
2639 const gchar *subject = NULL;
2641 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2644 header = tny_msg_get_header (msg);
2645 subject = tny_header_get_subject (header);
2646 g_object_unref (msg);
2649 if ((subject == NULL)||(subject[0] == '\0'))
2650 subject = _("mail_va_no_subject");
2652 gtk_window_set_title (GTK_WINDOW (window), subject);
2656 static void on_move_focus (ModestMsgViewWindow *window,
2657 GtkDirectionType direction,
2660 GtkWidget *current_focus = NULL;
2662 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2663 if ((current_focus != NULL) &&
2664 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2665 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");