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 <gtkhtml/gtkhtml-search.h>
54 #include "modest-ui-dimming-manager.h"
55 #include <gdk/gdkkeysyms.h>
56 #include <modest-tny-account.h>
59 #define DEFAULT_FOLDER "MyDocs/.documents"
61 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
62 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
63 static void modest_header_view_observer_init(
64 ModestHeaderViewObserverIface *iface_class);
65 static void modest_msg_view_window_finalize (GObject *obj);
66 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
68 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
69 ModestMsgViewWindow *obj);
70 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
71 ModestMsgViewWindow *obj);
73 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
74 static void modest_msg_view_window_set_zoom (ModestWindow *window,
76 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
77 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
78 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
79 static gboolean modest_msg_view_window_key_release_event (GtkWidget *window,
82 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
83 GdkEventWindowState *event,
85 static void modest_msg_view_window_scroll_up (ModestWindow *window);
86 static void modest_msg_view_window_scroll_down (ModestWindow *window);
87 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
89 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
90 gboolean show_toolbar);
92 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
94 ModestMsgViewWindow *window);
95 void modest_msg_view_window_on_row_changed(
96 GtkTreeModel *header_model,
99 ModestMsgViewWindow *window);
101 void modest_msg_view_window_on_row_deleted(
102 GtkTreeModel *header_model,
104 ModestMsgViewWindow *window);
106 void modest_msg_view_window_on_row_inserted(
107 GtkTreeModel *header_model,
108 GtkTreePath *tree_path,
109 GtkTreeIter *tree_iter,
110 ModestMsgViewWindow *window);
112 void modest_msg_view_window_on_row_reordered(
113 GtkTreeModel *header_model,
117 ModestMsgViewWindow *window);
119 void modest_msg_view_window_update_model_replaced(
120 ModestHeaderViewObserver *window,
122 const gchar *tny_folder_id);
124 static void cancel_progressbar (GtkToolButton *toolbutton,
125 ModestMsgViewWindow *self);
127 static void on_queue_changed (ModestMailOperationQueue *queue,
128 ModestMailOperation *mail_op,
129 ModestMailOperationQueueNotification type,
130 ModestMsgViewWindow *self);
132 static void on_account_removed (TnyAccountStore *account_store,
136 static void on_move_focus (ModestMsgViewWindow *window,
137 GtkDirectionType direction,
140 static void view_msg_cb (ModestMailOperation *mail_op,
145 static void set_toolbar_mode (ModestMsgViewWindow *self,
146 ModestToolBarModes mode);
148 static void update_window_title (ModestMsgViewWindow *window);
150 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
153 /* list my signals */
159 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
160 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
161 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
164 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
165 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
166 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
167 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
168 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
169 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
170 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
173 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
174 struct _ModestMsgViewWindowPrivate {
177 GtkWidget *main_scroll;
178 GtkWidget *find_toolbar;
181 /* Progress observers */
182 GtkWidget *progress_bar;
183 GSList *progress_widgets;
186 GtkWidget *progress_toolitem;
187 GtkWidget *cancel_toolitem;
188 GtkWidget *prev_toolitem;
189 GtkWidget *next_toolitem;
190 ModestToolBarModes current_toolbar_mode;
192 /* Optimized view enabled */
193 gboolean optimized_view;
195 /* Whether this was created via the *_new_for_search_result() function. */
196 gboolean is_search_result;
198 /* A reference to the @model of the header view
199 * to allow selecting previous/next messages,
200 * if the message is currently selected in the header view.
202 const gchar *header_folder_id;
203 GtkTreeModel *header_model;
204 GtkTreeRowReference *row_reference;
205 GtkTreeRowReference *next_row_reference;
207 gulong clipboard_change_handler;
208 gulong queue_change_handler;
209 gulong account_removed_handler;
210 gulong row_changed_handler;
211 gulong row_deleted_handler;
212 gulong row_inserted_handler;
213 gulong rows_reordered_handler;
216 GtkWidget *remove_attachment_banner;
218 guint progress_bar_timeout;
223 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
224 MODEST_TYPE_MSG_VIEW_WINDOW, \
225 ModestMsgViewWindowPrivate))
227 static GtkWindowClass *parent_class = NULL;
229 /* uncomment the following if you have defined any signals */
230 static guint signals[LAST_SIGNAL] = {0};
233 modest_msg_view_window_get_type (void)
235 static GType my_type = 0;
237 static const GTypeInfo my_info = {
238 sizeof(ModestMsgViewWindowClass),
239 NULL, /* base init */
240 NULL, /* base finalize */
241 (GClassInitFunc) modest_msg_view_window_class_init,
242 NULL, /* class finalize */
243 NULL, /* class data */
244 sizeof(ModestMsgViewWindow),
246 (GInstanceInitFunc) modest_msg_view_window_init,
249 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
250 "ModestMsgViewWindow",
253 static const GInterfaceInfo modest_header_view_observer_info =
255 (GInterfaceInitFunc) modest_header_view_observer_init,
256 NULL, /* interface_finalize */
257 NULL /* interface_data */
260 g_type_add_interface_static (my_type,
261 MODEST_TYPE_HEADER_VIEW_OBSERVER,
262 &modest_header_view_observer_info);
268 save_state (ModestWindow *self)
270 modest_widget_memory_save (modest_runtime_get_conf (),
272 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
277 restore_settings (ModestMsgViewWindow *self)
279 modest_widget_memory_restore (modest_runtime_get_conf (),
281 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
285 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
287 GObjectClass *gobject_class;
288 ModestWindowClass *modest_window_class;
289 gobject_class = (GObjectClass*) klass;
290 modest_window_class = (ModestWindowClass *) klass;
292 parent_class = g_type_class_peek_parent (klass);
293 gobject_class->finalize = modest_msg_view_window_finalize;
295 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
296 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
297 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
298 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
299 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
300 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
302 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
304 modest_window_class->save_state_func = save_state;
306 signals[MSG_CHANGED_SIGNAL] =
307 g_signal_new ("msg-changed",
308 G_TYPE_FROM_CLASS (gobject_class),
310 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
312 modest_marshal_VOID__POINTER_POINTER,
313 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
316 static void modest_header_view_observer_init(
317 ModestHeaderViewObserverIface *iface_class)
319 iface_class->update_func = modest_msg_view_window_update_model_replaced;
323 modest_msg_view_window_init (ModestMsgViewWindow *obj)
325 ModestMsgViewWindowPrivate *priv;
326 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
328 priv->is_search_result = FALSE;
330 priv->msg_view = NULL;
331 priv->header_model = NULL;
332 priv->header_folder_id = NULL;
333 priv->clipboard_change_handler = 0;
334 priv->queue_change_handler = 0;
335 priv->account_removed_handler = 0;
336 priv->row_changed_handler = 0;
337 priv->row_deleted_handler = 0;
338 priv->row_inserted_handler = 0;
339 priv->rows_reordered_handler = 0;
340 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
342 priv->optimized_view = FALSE;
343 priv->progress_bar_timeout = 0;
344 priv->purge_timeout = 0;
345 priv->remove_attachment_banner = NULL;
346 priv->msg_uid = NULL;
351 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
353 ModestMsgViewWindowPrivate *priv = NULL;
355 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
357 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
359 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
361 if (priv->progress_bar_timeout > 0) {
362 g_source_remove (priv->progress_bar_timeout);
363 priv->progress_bar_timeout = 0;
370 set_toolbar_mode (ModestMsgViewWindow *self,
371 ModestToolBarModes mode)
373 ModestWindowPrivate *parent_priv;
374 ModestMsgViewWindowPrivate *priv;
375 /* GtkWidget *widget = NULL; */
377 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
379 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
380 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
382 /* Sets current toolbar mode */
383 priv->current_toolbar_mode = mode;
385 /* Update toolbar dimming state */
386 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
389 case TOOLBAR_MODE_NORMAL:
390 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
391 /* gtk_action_set_sensitive (widget, TRUE); */
392 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
393 /* gtk_action_set_sensitive (widget, TRUE); */
394 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
395 /* gtk_action_set_sensitive (widget, TRUE); */
396 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
397 /* gtk_action_set_sensitive (widget, TRUE); */
399 if (priv->prev_toolitem)
400 gtk_widget_show (priv->prev_toolitem);
402 if (priv->next_toolitem)
403 gtk_widget_show (priv->next_toolitem);
405 if (priv->progress_toolitem)
406 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
407 if (priv->progress_bar)
408 gtk_widget_hide (priv->progress_bar);
410 if (priv->cancel_toolitem)
411 gtk_widget_hide (priv->cancel_toolitem);
413 /* Hide toolbar if optimized view is enabled */
414 if (priv->optimized_view) {
415 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
416 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
420 case TOOLBAR_MODE_TRANSFER:
421 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
422 /* gtk_action_set_sensitive (widget, FALSE); */
423 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
424 /* gtk_action_set_sensitive (widget, FALSE); */
425 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
426 /* gtk_action_set_sensitive (widget, FALSE); */
427 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
428 /* gtk_action_set_sensitive (widget, FALSE); */
430 if (priv->prev_toolitem)
431 gtk_widget_hide (priv->prev_toolitem);
433 if (priv->next_toolitem)
434 gtk_widget_hide (priv->next_toolitem);
436 if (priv->progress_toolitem)
437 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
438 if (priv->progress_bar)
439 gtk_widget_show (priv->progress_bar);
441 if (priv->cancel_toolitem)
442 gtk_widget_show (priv->cancel_toolitem);
444 /* Show toolbar if it's hiden (optimized view ) */
445 if (priv->optimized_view) {
446 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
447 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
452 g_return_if_reached ();
459 menubar_to_menu (GtkUIManager *ui_manager)
461 GtkWidget *main_menu;
463 GList *iter, *children;
465 /* Create new main menu */
466 main_menu = gtk_menu_new();
468 /* Get the menubar from the UI manager */
469 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
471 iter = children = gtk_container_get_children (GTK_CONTAINER (menubar));
475 menu = GTK_WIDGET (iter->data);
476 gtk_widget_reparent(menu, main_menu);
478 iter = g_list_next (iter);
480 g_list_free (children);
486 init_window (ModestMsgViewWindow *obj, TnyMsg *msg)
488 GtkWidget *main_vbox;
489 ModestMsgViewWindowPrivate *priv;
490 ModestWindowPrivate *parent_priv;
492 GtkAction *action = NULL;
494 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
495 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
497 priv->msg_view = modest_msg_view_new (msg);
498 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
499 main_vbox = gtk_vbox_new (FALSE, 6);
502 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
503 conf = modest_runtime_get_conf ();
504 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
505 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
506 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
507 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
508 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
509 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
510 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
511 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
512 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
513 gtk_widget_show (GTK_WIDGET(parent_priv->menubar));
515 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
516 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
517 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
518 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
520 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
521 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
522 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
524 priv->find_toolbar = hildon_find_toolbar_new (NULL);
525 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
526 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
527 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
528 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
530 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);
531 gtk_widget_show_all (GTK_WIDGET(main_vbox));
535 modest_msg_view_window_disconnect_signals (ModestWindow *self)
537 ModestMsgViewWindowPrivate *priv;
538 ModestHeaderView *header_view = NULL;
539 ModestMainWindow *main_window = NULL;
540 ModestWindowMgr *window_mgr = NULL;
542 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
544 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
545 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
546 priv->clipboard_change_handler))
547 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
548 priv->clipboard_change_handler);
550 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
551 priv->queue_change_handler))
552 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
553 priv->queue_change_handler);
555 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
556 priv->account_removed_handler))
557 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
558 priv->account_removed_handler);
560 if (priv->header_model) {
561 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
562 priv->row_changed_handler))
563 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
564 priv->row_changed_handler);
566 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
567 priv->row_deleted_handler))
568 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
569 priv->row_deleted_handler);
571 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
572 priv->row_inserted_handler))
573 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
574 priv->row_inserted_handler);
576 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
577 priv->rows_reordered_handler))
578 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
579 priv->rows_reordered_handler);
582 window_mgr = modest_runtime_get_window_mgr();
583 g_assert(window_mgr != NULL);
585 main_window = MODEST_MAIN_WINDOW(
586 modest_window_mgr_get_main_window(window_mgr));
588 if(main_window == NULL)
591 header_view = MODEST_HEADER_VIEW(
592 modest_main_window_get_child_widget(
593 main_window, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
595 if (header_view == NULL)
598 modest_header_view_remove_observer(header_view,
599 MODEST_HEADER_VIEW_OBSERVER(self));
603 modest_msg_view_window_finalize (GObject *obj)
605 ModestMsgViewWindowPrivate *priv;
607 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
609 /* Sanity check: shouldn't be needed, the window mgr should
610 call this function before */
611 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
613 if (priv->header_model != NULL) {
614 g_object_unref (priv->header_model);
615 priv->header_model = NULL;
618 if (priv->progress_bar_timeout > 0) {
619 g_source_remove (priv->progress_bar_timeout);
620 priv->progress_bar_timeout = 0;
623 if (priv->remove_attachment_banner) {
624 gtk_widget_destroy (priv->remove_attachment_banner);
625 g_object_unref (priv->remove_attachment_banner);
626 priv->remove_attachment_banner = NULL;
629 if (priv->purge_timeout > 0) {
630 g_source_remove (priv->purge_timeout);
631 priv->purge_timeout = 0;
634 if (priv->row_reference) {
635 gtk_tree_row_reference_free (priv->row_reference);
636 priv->row_reference = NULL;
639 if (priv->next_row_reference) {
640 gtk_tree_row_reference_free (priv->next_row_reference);
641 priv->next_row_reference = NULL;
645 g_free (priv->msg_uid);
646 priv->msg_uid = NULL;
649 G_OBJECT_CLASS(parent_class)->finalize (obj);
653 select_next_valid_row (GtkTreeModel *model,
654 GtkTreeRowReference **row_reference,
657 GtkTreeIter tmp_iter;
658 GtkTreePath *path, *next;
659 gboolean retval = FALSE;
661 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
663 path = gtk_tree_row_reference_get_path (*row_reference);
664 gtk_tree_model_get_iter (model, &tmp_iter, path);
665 gtk_tree_row_reference_free (*row_reference);
666 *row_reference = NULL;
668 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
669 next = gtk_tree_model_get_path (model, &tmp_iter);
670 *row_reference = gtk_tree_row_reference_new (model, next);
672 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
673 next = gtk_tree_model_get_path (model, &tmp_iter);
675 /* Ensure that we are not selecting the same */
676 if (gtk_tree_path_compare (path, next) != 0) {
677 *row_reference = gtk_tree_row_reference_new (model, next);
683 gtk_tree_path_free (path);
688 /* TODO: This should be in _init(), with the parameters as properties. */
690 modest_msg_view_window_construct (ModestMsgViewWindow *self, TnyMsg *msg,
691 const gchar *modest_account_name,
692 const gchar *msg_uid)
695 ModestMsgViewWindowPrivate *priv = NULL;
696 ModestWindowPrivate *parent_priv = NULL;
697 ModestDimmingRulesGroup *menu_rules_group = NULL;
698 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
699 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
700 GtkActionGroup *action_group = NULL;
701 GError *error = NULL;
702 GdkPixbuf *window_icon;
704 g_return_if_fail (msg);
706 obj = G_OBJECT (self);
707 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
708 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
710 priv->msg_uid = g_strdup (msg_uid);
712 parent_priv->ui_manager = gtk_ui_manager_new();
713 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
715 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
716 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
718 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
719 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
720 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
722 /* Add common actions */
723 gtk_action_group_add_actions (action_group,
724 modest_action_entries,
725 G_N_ELEMENTS (modest_action_entries),
727 gtk_action_group_add_toggle_actions (action_group,
728 modest_toggle_action_entries,
729 G_N_ELEMENTS (modest_toggle_action_entries),
731 gtk_action_group_add_toggle_actions (action_group,
732 msg_view_toggle_action_entries,
733 G_N_ELEMENTS (msg_view_toggle_action_entries),
735 gtk_action_group_add_radio_actions (action_group,
736 msg_view_zoom_action_entries,
737 G_N_ELEMENTS (msg_view_zoom_action_entries),
739 G_CALLBACK (modest_ui_actions_on_change_zoom),
742 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
743 g_object_unref (action_group);
745 /* Load the UI definition */
746 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
749 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
750 g_error_free (error);
755 /* Add common dimming rules */
756 modest_dimming_rules_group_add_rules (menu_rules_group,
757 modest_msg_view_menu_dimming_entries,
758 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
759 MODEST_WINDOW (self));
760 modest_dimming_rules_group_add_rules (toolbar_rules_group,
761 modest_msg_view_toolbar_dimming_entries,
762 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
763 MODEST_WINDOW (self));
764 modest_dimming_rules_group_add_rules (clipboard_rules_group,
765 modest_msg_view_clipboard_dimming_entries,
766 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
767 MODEST_WINDOW (self));
769 /* Insert dimming rules group for this window */
770 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
771 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
772 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
773 g_object_unref (menu_rules_group);
774 g_object_unref (toolbar_rules_group);
775 g_object_unref (clipboard_rules_group);
777 /* Add accelerators */
778 gtk_window_add_accel_group (GTK_WINDOW (obj),
779 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
782 init_window (MODEST_MSG_VIEW_WINDOW(obj), msg);
783 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
785 /* Set window icon */
786 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
788 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
789 g_object_unref (window_icon);
792 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
794 g_signal_connect (G_OBJECT(priv->msg_view), "link_clicked",
795 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
796 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
797 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
798 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
799 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
800 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
801 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
802 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
803 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
805 g_signal_connect (G_OBJECT (obj), "key-release-event",
806 G_CALLBACK (modest_msg_view_window_key_release_event),
809 g_signal_connect (G_OBJECT (obj), "window-state-event",
810 G_CALLBACK (modest_msg_view_window_window_state_event),
813 g_signal_connect (G_OBJECT (obj), "move-focus",
814 G_CALLBACK (on_move_focus), obj);
816 /* Mail Operation Queue */
817 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
819 G_CALLBACK (on_queue_changed),
822 /* Account manager */
823 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
825 G_CALLBACK(on_account_removed),
828 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
830 priv->last_search = NULL;
832 /* Init the clipboard actions dim status */
833 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
835 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
837 /* Check toolbar dimming rules */
838 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
839 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
844 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
845 const gchar *modest_account_name,
846 const gchar *msg_uid,
848 GtkTreeRowReference *row_reference)
850 ModestMsgViewWindow *window = NULL;
851 ModestMsgViewWindowPrivate *priv = NULL;
852 TnyFolder *header_folder = NULL;
853 ModestHeaderView *header_view = NULL;
854 ModestMainWindow *main_window = NULL;
855 ModestWindowMgr *window_mgr = NULL;
857 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
858 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
859 modest_msg_view_window_construct (window, msg, modest_account_name, msg_uid);
861 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
863 /* Remember the message list's TreeModel so we can detect changes
864 * and change the list selection when necessary: */
865 window_mgr = modest_runtime_get_window_mgr();
866 g_assert(window_mgr != NULL);
867 main_window = MODEST_MAIN_WINDOW(
868 modest_window_mgr_get_main_window(window_mgr));
869 g_assert(main_window != NULL);
870 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
871 main_window, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
872 if (header_view != NULL){
873 header_folder = modest_header_view_get_folder(header_view);
874 g_assert(header_folder != NULL);
875 priv->header_folder_id = tny_folder_get_id(header_folder);
876 g_assert(priv->header_folder_id != NULL);
877 g_object_unref(header_folder);
880 priv->header_model = g_object_ref(model);
881 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
882 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
883 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
885 priv->row_changed_handler = g_signal_connect(
886 GTK_TREE_MODEL(model), "row-changed",
887 G_CALLBACK(modest_msg_view_window_on_row_changed),
889 priv->row_deleted_handler = g_signal_connect(
890 GTK_TREE_MODEL(model), "row-deleted",
891 G_CALLBACK(modest_msg_view_window_on_row_deleted),
893 priv->row_inserted_handler = g_signal_connect (
894 GTK_TREE_MODEL(model), "row-inserted",
895 G_CALLBACK(modest_msg_view_window_on_row_inserted),
897 priv->rows_reordered_handler = g_signal_connect(
898 GTK_TREE_MODEL(model), "rows-reordered",
899 G_CALLBACK(modest_msg_view_window_on_row_reordered),
902 if (header_view != NULL){
903 modest_header_view_add_observer(header_view,
904 MODEST_HEADER_VIEW_OBSERVER(window));
907 modest_msg_view_window_update_priority (window);
909 /* Check toolbar dimming rules */
910 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
912 return MODEST_WINDOW(window);
916 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
917 const gchar *modest_account_name,
918 const gchar *msg_uid)
920 ModestMsgViewWindow *window = NULL;
921 ModestMsgViewWindowPrivate *priv = NULL;
923 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
924 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
925 modest_msg_view_window_construct (window, msg, modest_account_name, msg_uid);
927 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
929 /* Remember that this is a search result,
930 * so we can disable some UI appropriately: */
931 priv->is_search_result = TRUE;
933 return MODEST_WINDOW(window);
937 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
938 const gchar *modest_account_name,
939 const gchar *msg_uid)
942 g_return_val_if_fail (msg, NULL);
944 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
945 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
946 msg, modest_account_name, msg_uid);
948 return MODEST_WINDOW(obj);
951 void modest_msg_view_window_on_row_changed(
952 GtkTreeModel *header_model,
955 ModestMsgViewWindow *window){
956 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
959 void modest_msg_view_window_on_row_deleted(
960 GtkTreeModel *header_model,
962 ModestMsgViewWindow *window){
963 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
966 /* On insertions we check if the folder still has the message we are
967 * showing or do not. If do not, we do nothing. Which means we are still
968 * not attached to any header folder and thus next/prev buttons are
969 * still dimmed. Once the message that is shown by msg-view is found, the
970 * new model of header-view will be attached and the references will be set.
971 * On each further insertions dimming rules will be checked. However
972 * this requires extra CPU time at least works.
973 * (An message might be deleted from TnyFolder and thus will not be
974 * inserted into the model again for example if it is removed by the
975 * imap server and the header view is refreshed.)
977 void modest_msg_view_window_on_row_inserted(
978 GtkTreeModel *new_model,
979 GtkTreePath *tree_path,
980 GtkTreeIter *tree_iter,
981 ModestMsgViewWindow *window){
982 ModestMsgViewWindowPrivate *priv = NULL;
983 TnyHeader *header = NULL;
986 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
988 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
990 /* If we already has a model attached then the message shown by
991 * msg-view is in it, and thus we do not need any actions but
992 * to check the dimming rules.*/
993 if(priv->header_model != NULL){
994 gtk_tree_row_reference_free(priv->next_row_reference);
995 priv->next_row_reference = gtk_tree_row_reference_copy(
996 priv->row_reference);
997 select_next_valid_row (priv->header_model,
998 &(priv->next_row_reference), FALSE);
999 modest_ui_actions_check_toolbar_dimming_rules (
1000 MODEST_WINDOW (window));
1004 /* Check if the newly inserted message is the same we are actually
1005 * showing. IF not, we should remain detached from the header model
1006 * and thus prev and next toolbarbuttons should remain dimmed. */
1007 gtk_tree_model_get (new_model, tree_iter,
1008 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1009 uid = modest_tny_folder_get_header_unique_id(header);
1010 if(!g_str_equal(priv->msg_uid, uid)){
1016 /* Setup row_reference for the actual msg. */
1017 priv->row_reference = gtk_tree_row_reference_new(
1018 new_model, tree_path);
1019 if(priv->row_reference == NULL){
1020 g_warning("No reference for msg header item.");
1024 /* Attach new_model and connect some callback to it to become able
1025 * to detect changes in header-view. */
1026 priv->header_model = g_object_ref(new_model);
1027 g_signal_connect (new_model, "row-changed",
1028 G_CALLBACK (modest_msg_view_window_on_row_changed),
1030 g_signal_connect (new_model, "row-deleted",
1031 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1033 g_signal_connect (new_model, "rows-reordered",
1034 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1037 /* Now set up next_row_reference. */
1038 priv->next_row_reference = gtk_tree_row_reference_copy(
1039 priv->row_reference);
1040 select_next_valid_row (priv->header_model,
1041 &(priv->next_row_reference), FALSE);
1043 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1046 void modest_msg_view_window_on_row_reordered(
1047 GtkTreeModel *header_model,
1051 ModestMsgViewWindow *window){
1052 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1055 /* The modest_msg_view_window_update_model_replaced implements update
1056 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1057 * actually belongs to the header-view is the same as the TnyFolder of
1058 * the message of msg-view or not. If they are different, there is
1059 * nothing to do. If they are the same, then the model has replaced and
1060 * the reference in msg-view shall be replaced from the old model to
1061 * the new model. In this case the view will be detached from it's
1062 * header folder. From this point the next/prev buttons are dimmed.
1064 void modest_msg_view_window_update_model_replaced(
1065 ModestHeaderViewObserver *observer,
1066 GtkTreeModel *model,
1067 const gchar *tny_folder_id){
1068 ModestMsgViewWindowPrivate *priv = NULL;
1069 ModestMsgViewWindow *window = NULL;
1071 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1072 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1074 window = MODEST_MSG_VIEW_WINDOW(observer);
1075 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1077 /* If there is an other folder in the header-view then we do
1078 * not care about it's model (msg list). Else if the
1079 * header-view shows the folder the msg shown by us is in, we
1080 * shall replace our model reference and make some check. */
1081 if(tny_folder_id == NULL ||
1082 !g_str_equal(tny_folder_id, priv->header_folder_id))
1085 /* Model is changed(replaced), so we should forget the old
1086 * one. Because there might be other references and there
1087 * might be some change on the model even if we unreferenced
1088 * it, we need to disconnect our signals here. */
1089 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1090 priv->row_changed_handler))
1091 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1092 priv->row_changed_handler);
1093 priv->row_changed_handler = 0;
1094 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1095 priv->row_deleted_handler))
1096 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1097 priv->row_deleted_handler);
1098 priv->row_deleted_handler = 0;
1099 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1100 priv->row_inserted_handler))
1101 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1102 priv->row_inserted_handler);
1103 priv->row_inserted_handler = 0;
1104 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1105 priv->rows_reordered_handler))
1106 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1107 priv->rows_reordered_handler);
1108 priv->rows_reordered_handler = 0;
1109 g_object_unref(priv->header_model);
1110 priv->header_model = NULL;
1111 g_object_unref(priv->row_reference);
1112 priv->row_reference = NULL;
1113 g_object_unref(priv->next_row_reference);
1114 priv->next_row_reference = NULL;
1116 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1118 if(tny_folder_id == NULL)
1121 g_assert(model != NULL);
1123 /* Also we must connect to the new model for row insertions.
1124 * Only for insertions now. We will need other ones only after
1125 * the msg is show by msg-view is added to the new model. */
1126 priv->row_inserted_handler = g_signal_connect (
1127 model, "row-inserted",
1128 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1133 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1135 ModestMsgViewWindowPrivate *priv= NULL;
1137 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1138 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1140 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1144 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1146 ModestMsgViewWindowPrivate *priv= NULL;
1148 TnyHeader *header = NULL;
1149 GtkTreePath *path = NULL;
1152 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1153 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1155 /* If the message was not obtained from a treemodel,
1156 * for instance if it was opened directly by the search UI:
1158 if (priv->header_model == NULL) {
1159 msg = modest_msg_view_window_get_message (self);
1160 header = tny_msg_get_header (msg);
1161 g_object_unref (msg);
1165 /* Get iter of the currently selected message in the header view: */
1166 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1167 * instead of sometimes retrieving it from the header view?
1168 * Then we wouldn't be dependent on the message actually still being selected
1169 * in the header view. murrayc. */
1170 if (!gtk_tree_row_reference_valid (priv->row_reference))
1172 path = gtk_tree_row_reference_get_path (priv->row_reference);
1173 g_return_val_if_fail (path != NULL, NULL);
1174 gtk_tree_model_get_iter (priv->header_model,
1178 /* Get current message header */
1179 gtk_tree_model_get (priv->header_model, &iter,
1180 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1183 gtk_tree_path_free (path);
1188 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1190 ModestMsgView *msg_view;
1191 ModestMsgViewWindowPrivate *priv;
1193 g_return_val_if_fail (self, NULL);
1195 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1197 msg_view = MODEST_MSG_VIEW (priv->msg_view);
1199 return modest_msg_view_get_message (msg_view);
1203 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1205 ModestMsgViewWindowPrivate *priv;
1207 g_return_val_if_fail (self, NULL);
1209 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1211 return (const gchar*) priv->msg_uid;
1215 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1218 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1219 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1220 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1224 is_active = gtk_toggle_action_get_active (toggle);
1227 gtk_widget_show (priv->find_toolbar);
1228 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1230 gtk_widget_hide (priv->find_toolbar);
1233 /* update the toggle buttons status */
1234 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1235 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1236 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1237 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1242 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1243 ModestMsgViewWindow *obj)
1245 GtkToggleAction *toggle;
1246 ModestWindowPrivate *parent_priv;
1247 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1249 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1250 gtk_toggle_action_set_active (toggle, FALSE);
1254 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1255 ModestMsgViewWindow *obj)
1257 gchar *current_search;
1258 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1260 if (modest_msg_view_get_message_is_empty (MODEST_MSG_VIEW (priv->msg_view))) {
1261 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1265 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1267 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1268 g_free (current_search);
1269 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1273 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1275 g_free (priv->last_search);
1276 priv->last_search = g_strdup (current_search);
1277 result = modest_msg_view_search (MODEST_MSG_VIEW (priv->msg_view),
1280 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1281 g_free (priv->last_search);
1282 priv->last_search = NULL;
1284 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1287 if (!modest_msg_view_search_next (MODEST_MSG_VIEW (priv->msg_view))) {
1288 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1289 g_free (priv->last_search);
1290 priv->last_search = NULL;
1292 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1296 g_free (current_search);
1301 modest_msg_view_window_set_zoom (ModestWindow *window,
1304 ModestMsgViewWindowPrivate *priv;
1305 ModestWindowPrivate *parent_priv;
1306 GtkAction *action = NULL;
1307 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1309 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1311 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1312 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1313 modest_msg_view_set_zoom (MODEST_MSG_VIEW (priv->msg_view), zoom);
1315 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1316 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1318 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1322 modest_msg_view_window_get_zoom (ModestWindow *window)
1324 ModestMsgViewWindowPrivate *priv;
1326 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1328 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1329 return modest_msg_view_get_zoom (MODEST_MSG_VIEW (priv->msg_view));
1333 modest_msg_view_window_zoom_plus (ModestWindow *window)
1335 ModestWindowPrivate *parent_priv;
1336 GtkRadioAction *zoom_radio_action;
1337 GSList *group, *node;
1339 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1340 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1341 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1343 group = gtk_radio_action_get_group (zoom_radio_action);
1345 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1346 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1350 for (node = group; node != NULL; node = g_slist_next (node)) {
1351 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1352 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1360 modest_msg_view_window_zoom_minus (ModestWindow *window)
1362 ModestWindowPrivate *parent_priv;
1363 GtkRadioAction *zoom_radio_action;
1364 GSList *group, *node;
1366 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1367 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1368 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1370 group = gtk_radio_action_get_group (zoom_radio_action);
1372 for (node = group; node != NULL; node = g_slist_next (node)) {
1373 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1374 if (node->next != NULL) {
1375 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1378 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1388 modest_msg_view_window_key_release_event (GtkWidget *window,
1392 if (event->type == GDK_KEY_RELEASE) {
1393 switch (event->keyval) {
1395 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1399 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1412 modest_msg_view_window_scroll_up (ModestWindow *window)
1414 ModestMsgViewWindowPrivate *priv;
1415 gboolean return_value;
1417 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1418 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1422 modest_msg_view_window_scroll_down (ModestWindow *window)
1424 ModestMsgViewWindowPrivate *priv;
1425 gboolean return_value;
1427 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1428 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1432 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1435 ModestMsgViewWindowPrivate *priv;
1436 GtkTreeIter tmp_iter;
1437 gboolean is_last_selected;
1439 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1440 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1442 /*if no model (so no rows at all), then virtually we are the last*/
1443 if (!priv->header_model)
1446 path = gtk_tree_row_reference_get_path (priv->row_reference);
1450 is_last_selected = TRUE;
1451 while (is_last_selected) {
1453 gtk_tree_path_next (path);
1454 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1456 gtk_tree_model_get (priv->header_model, &tmp_iter,
1457 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1459 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1460 is_last_selected = FALSE;
1462 gtk_tree_path_free (path);
1463 return is_last_selected;
1467 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1469 ModestMsgViewWindowPrivate *priv;
1471 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1472 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1474 return priv->header_model != NULL;
1478 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1480 ModestMsgViewWindowPrivate *priv;
1482 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1483 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1485 return priv->is_search_result;
1489 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1492 ModestMsgViewWindowPrivate *priv;
1493 gboolean is_first_selected;
1494 GtkTreeIter tmp_iter;
1495 /* gchar * path_string;*/
1497 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1498 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1500 /*if no model (so no rows at all), then virtually we are the first*/
1501 if (!priv->header_model)
1504 path = gtk_tree_row_reference_get_path (priv->row_reference);
1508 /* path_string = gtk_tree_path_to_string (path);
1509 is_first_selected = strcmp (path_string, "0");
1511 g_free (path_string);
1512 gtk_tree_path_free (path);
1514 return is_first_selected;*/
1516 is_first_selected = TRUE;
1517 while (is_first_selected) {
1519 if(!gtk_tree_path_prev (path))
1521 /* Here the 'if' is needless for logic, but let make sure
1522 * iter is valid for gtk_tree_model_get. */
1523 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1525 gtk_tree_model_get (priv->header_model, &tmp_iter,
1526 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1528 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1529 is_first_selected = FALSE;
1531 gtk_tree_path_free (path);
1532 return is_first_selected;
1536 * Reads the message whose summary item is @header. It takes care of
1537 * several things, among others:
1539 * If the message was not previously downloaded then ask the user
1540 * before downloading. If there is no connection launch the connection
1541 * dialog. Update toolbar dimming rules.
1543 * Returns: TRUE if the mail operation was started, otherwise if the
1544 * user do not want to download the message, or if the user do not
1545 * want to connect, then the operation is not issued
1548 message_reader (ModestMsgViewWindow *window,
1549 ModestMsgViewWindowPrivate *priv,
1551 GtkTreeRowReference *row_reference)
1553 ModestMailOperation *mail_op = NULL;
1554 ModestMailOperationTypeOperation op_type;
1555 gboolean already_showing = FALSE;
1556 ModestWindow *msg_window = NULL;
1557 ModestWindowMgr *mgr;
1559 g_return_val_if_fail (row_reference != NULL, FALSE);
1561 mgr = modest_runtime_get_window_mgr ();
1562 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1563 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1566 gtk_window_present (GTK_WINDOW (msg_window));
1567 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1571 /* Msg download completed */
1572 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1573 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1575 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1577 /* Ask the user if he wants to download the message if
1579 if (!tny_device_is_online (modest_runtime_get_device())) {
1580 TnyFolder *folder = NULL;
1581 GtkResponseType response;
1583 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1584 _("mcen_nc_get_msg"));
1585 if (response == GTK_RESPONSE_CANCEL)
1588 /* Offer the connection dialog if necessary */
1589 folder = tny_header_get_folder (header);
1591 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1592 TNY_FOLDER_STORE (folder))) {
1593 g_object_unref (folder);
1596 g_object_unref (folder);
1601 /* New mail operation */
1602 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1603 modest_ui_actions_get_msgs_full_error_handler,
1606 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1607 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1608 g_object_unref (mail_op);
1610 /* Update toolbar dimming rules */
1611 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1617 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1619 ModestMsgViewWindowPrivate *priv;
1620 GtkTreePath *path= NULL;
1621 GtkTreeIter tmp_iter;
1623 gboolean retval = TRUE;
1624 GtkTreeRowReference *row_reference = NULL;
1626 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1627 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1629 /* Update the next row reference if it's not valid. This could
1630 happen if for example the header which it was pointing to,
1631 was deleted. The best place to do it is in the row-deleted
1632 handler but the tinymail model do not work like the glib
1633 tree models and reports the deletion when the row is still
1635 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1636 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1637 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1638 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1641 if (priv->next_row_reference)
1642 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1646 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1648 gtk_tree_model_get_iter (priv->header_model,
1651 gtk_tree_path_free (path);
1653 gtk_tree_model_get (priv->header_model, &tmp_iter,
1654 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1657 /* Read the message & show it */
1658 if (!message_reader (window, priv, header, row_reference)) {
1660 gtk_tree_row_reference_free (row_reference);
1664 g_object_unref (header);
1670 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1672 ModestMsgViewWindowPrivate *priv = NULL;
1673 TnyHeader *header = NULL;
1675 GtkTreePath *path = NULL;
1676 GtkTreeRowReference *row_reference = NULL;
1678 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1679 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1681 /* Check that the model is not empty */
1682 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1685 /* Get the header */
1686 gtk_tree_model_get (priv->header_model,
1688 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1690 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1691 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1692 g_object_unref (header);
1693 return modest_msg_view_window_select_next_message (self);
1696 path = gtk_tree_model_get_path (priv->header_model, &iter);
1697 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1698 gtk_tree_path_free (path);
1700 /* Read the message & show it */
1701 message_reader (self, priv, header, row_reference);
1704 g_object_unref (header);
1710 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1712 ModestMsgViewWindowPrivate *priv = NULL;
1714 GtkTreeRowReference *row_reference = NULL;
1716 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1717 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1719 /* Return inmediatly if there is no header model */
1720 if (!priv->header_model)
1723 path = gtk_tree_row_reference_get_path (priv->row_reference);
1724 while (gtk_tree_path_prev (path)) {
1728 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1729 gtk_tree_model_get (priv->header_model, &iter,
1730 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1734 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1735 g_object_unref (header);
1739 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1740 /* Read the message & show it */
1741 if (!message_reader (window, priv, header, row_reference)) {
1742 gtk_tree_row_reference_free (row_reference);
1743 g_object_unref (header);
1747 gtk_tree_path_free (path);
1748 g_object_unref (header);
1753 gtk_tree_path_free (path);
1758 view_msg_cb (ModestMailOperation *mail_op,
1763 ModestMsgViewWindow *self = NULL;
1764 ModestMsgViewWindowPrivate *priv = NULL;
1765 GtkTreeRowReference *row_reference = NULL;
1767 /* If there was any error */
1768 row_reference = (GtkTreeRowReference *) user_data;
1769 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1770 gtk_tree_row_reference_free (row_reference);
1774 /* Get the window */
1775 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1776 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1777 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1779 /* Update the row reference */
1780 gtk_tree_row_reference_free (priv->row_reference);
1781 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1782 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1783 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1784 gtk_tree_row_reference_free (row_reference);
1786 /* Mark header as read */
1787 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1788 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
1790 /* Set new message */
1791 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), msg);
1792 modest_msg_view_window_update_priority (self);
1793 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1794 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1796 /* Set the new message uid of the window */
1797 if (priv->msg_uid) {
1798 g_free (priv->msg_uid);
1799 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1802 /* Notify the observers */
1803 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1804 0, priv->header_model, priv->row_reference);
1806 /* Free new references */
1807 g_object_unref (self);
1811 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1813 ModestMsgViewWindowPrivate *priv;
1815 TnyFolderType folder_type;
1817 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1819 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1821 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
1825 folder = tny_msg_get_folder (msg);
1828 folder_type = tny_folder_get_folder_type (folder);
1830 if (folder_type == TNY_FOLDER_TYPE_NORMAL || folder_type == TNY_FOLDER_TYPE_UNKNOWN) {
1831 const gchar *fname = tny_folder_get_name (folder);
1832 folder_type = modest_tny_folder_guess_folder_type_from_name (fname);
1835 g_object_unref (folder);
1837 g_object_unref (msg);
1845 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1847 ModestMsgViewWindowPrivate *priv;
1848 TnyHeaderFlags flags = 0;
1850 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1852 if (priv->header_model) {
1855 GtkTreePath *path = NULL;
1857 path = gtk_tree_row_reference_get_path (priv->row_reference);
1858 g_return_if_fail (path != NULL);
1859 gtk_tree_model_get_iter (priv->header_model,
1861 gtk_tree_row_reference_get_path (priv->row_reference));
1863 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1865 flags = tny_header_get_flags (header);
1866 gtk_tree_path_free (path);
1869 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1874 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1876 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1877 ModestWindowPrivate *parent_priv;
1878 ModestWindowMgr *mgr;
1879 gboolean is_fullscreen;
1880 GtkAction *fs_toggle_action;
1883 mgr = modest_runtime_get_window_mgr ();
1884 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1886 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1888 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1889 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1890 if (is_fullscreen != active) {
1891 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1900 set_homogeneous (GtkWidget *widget,
1903 if (GTK_IS_TOOL_ITEM (widget)) {
1904 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1905 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1910 modest_msg_view_window_show_toolbar (ModestWindow *self,
1911 gboolean show_toolbar)
1913 ModestMsgViewWindowPrivate *priv = NULL;
1914 ModestWindowPrivate *parent_priv;
1915 GtkWidget *reply_button = NULL, *menu = NULL;
1916 GtkWidget *placeholder = NULL;
1918 const gchar *action_name;
1921 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1922 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1924 /* Set optimized view status */
1925 priv->optimized_view = !show_toolbar;
1927 if (!parent_priv->toolbar) {
1928 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1930 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1932 /* Set homogeneous toolbar */
1933 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1934 set_homogeneous, NULL);
1936 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1937 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1938 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1939 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1940 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1941 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1942 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1943 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1945 /* Add ProgressBar (Transfer toolbar) */
1946 priv->progress_bar = modest_progress_bar_widget_new ();
1947 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1948 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1949 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1950 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1951 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1953 /* Connect cancel 'clicked' signal to abort progress mode */
1954 g_signal_connect(priv->cancel_toolitem, "clicked",
1955 G_CALLBACK(cancel_progressbar),
1958 /* Add it to the observers list */
1959 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1962 hildon_window_add_toolbar (HILDON_WINDOW (self),
1963 GTK_TOOLBAR (parent_priv->toolbar));
1966 /* Set reply button tap and hold menu */
1967 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1968 "/ToolBar/ToolbarMessageReply");
1969 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1970 "/ToolbarReplyCSM");
1971 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1975 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1976 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1977 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1979 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1980 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1983 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1984 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1987 /* Update also the actions (to update the toggles in the
1988 menus), we have to do it manually because some other window
1989 of the same time could have changed it (remember that the
1990 toolbar fullscreen mode is shared by all the windows of the
1992 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1993 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
1995 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
1997 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1998 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2003 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2005 ModestMsgViewWindow *window)
2007 if (!GTK_WIDGET_VISIBLE (window))
2010 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2014 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2016 ModestMsgViewWindowPrivate *priv;
2018 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2019 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2021 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2025 cancel_progressbar (GtkToolButton *toolbutton,
2026 ModestMsgViewWindow *self)
2029 ModestMsgViewWindowPrivate *priv;
2031 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2033 /* Get operation observers and cancel its current operation */
2034 tmp = priv->progress_widgets;
2036 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2037 tmp=g_slist_next(tmp);
2041 observers_empty (ModestMsgViewWindow *self)
2044 ModestMsgViewWindowPrivate *priv;
2045 gboolean is_empty = TRUE;
2046 guint pending_ops = 0;
2048 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2049 tmp = priv->progress_widgets;
2051 /* Check all observers */
2052 while (tmp && is_empty) {
2053 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2054 is_empty = pending_ops == 0;
2056 tmp = g_slist_next(tmp);
2063 on_account_removed (TnyAccountStore *account_store,
2064 TnyAccount *account,
2067 /* Do nothing if it's a transport account, because we only
2068 show the messages of a store account */
2069 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2070 const gchar *parent_acc = NULL;
2071 const gchar *our_acc = NULL;
2073 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2074 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2076 /* Close this window if I'm showing a message of the removed account */
2077 if (strcmp (parent_acc, our_acc) == 0)
2078 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2083 on_queue_changed (ModestMailOperationQueue *queue,
2084 ModestMailOperation *mail_op,
2085 ModestMailOperationQueueNotification type,
2086 ModestMsgViewWindow *self)
2089 ModestMsgViewWindowPrivate *priv;
2090 ModestMailOperationTypeOperation op_type;
2091 ModestToolBarModes mode;
2093 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2094 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2096 /* If this operations was created by another window, do nothing */
2097 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2100 /* Get toolbar mode from operation id*/
2101 op_type = modest_mail_operation_get_type_operation (mail_op);
2103 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2104 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2105 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2106 mode = TOOLBAR_MODE_TRANSFER;
2109 mode = TOOLBAR_MODE_NORMAL;
2113 /* Add operation observers and change toolbar if neccessary*/
2114 tmp = priv->progress_widgets;
2116 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2117 if (mode == TOOLBAR_MODE_TRANSFER) {
2118 /* Enable transfer toolbar mode */
2119 set_toolbar_transfer_mode(self);
2121 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2123 tmp = g_slist_next (tmp);
2128 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2129 if (mode == TOOLBAR_MODE_TRANSFER) {
2131 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2133 tmp = g_slist_next (tmp);
2137 /* If no more operations are being observed, NORMAL mode is enabled again */
2138 if (observers_empty (self)) {
2139 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2147 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2149 ModestMsgViewWindowPrivate *priv;
2150 GList *selected_attachments = NULL;
2152 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2153 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2155 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2157 return selected_attachments;
2161 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2163 ModestMsgViewWindowPrivate *priv;
2164 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2165 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2167 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2169 if (mime_part == NULL) {
2170 gboolean error = FALSE;
2171 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2172 if (selected_attachments == NULL) {
2174 } else if (g_list_length (selected_attachments) > 1) {
2175 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2178 mime_part = (TnyMimePart *) selected_attachments->data;
2179 g_object_ref (mime_part);
2181 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2182 g_list_free (selected_attachments);
2187 g_object_ref (mime_part);
2190 if (tny_mime_part_is_purged (mime_part)) {
2191 g_object_unref (mime_part);
2195 if (!TNY_IS_MSG (mime_part)) {
2196 gchar *filepath = NULL;
2197 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2198 TnyFsStream *temp_stream = NULL;
2200 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, &filepath);
2203 const gchar *content_type;
2204 content_type = tny_mime_part_get_content_type (mime_part);
2205 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2207 modest_platform_activate_file (filepath, content_type);
2208 g_object_unref (temp_stream);
2210 /* NOTE: files in the temporary area will be automatically
2211 * cleaned after some time if they are no longer in use */
2214 /* message attachment */
2215 TnyHeader *header = NULL;
2216 ModestWindowMgr *mgr;
2217 ModestWindow *msg_win = NULL;
2220 header = tny_msg_get_header (TNY_MSG (mime_part));
2221 mgr = modest_runtime_get_window_mgr ();
2222 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2225 if (msg_win) /* there is already a window for this uid; top it */
2226 gtk_window_present (GTK_WINDOW(msg_win));
2228 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2229 * thus, we don't do anything */
2230 g_warning ("window for is already being created");
2232 /* it's not found, so create a new window for it */
2233 modest_window_mgr_register_header (mgr, header); /* register the uid before building the window */
2234 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2236 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2237 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, NULL);
2238 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2239 modest_window_get_zoom (MODEST_WINDOW (window)));
2240 modest_window_mgr_register_window (mgr, msg_win);
2241 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2242 gtk_widget_show_all (GTK_WIDGET (msg_win));
2245 g_object_unref (mime_part);
2261 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2262 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2263 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2264 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2267 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2271 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2272 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2273 g_free (pair->filename);
2274 g_object_unref (pair->part);
2275 g_slice_free (SaveMimePartPair, pair);
2277 g_list_free (info->pairs);
2280 gtk_widget_destroy (info->banner);
2281 g_object_unref (info->banner);
2282 g_slice_free (SaveMimePartInfo, info);
2287 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2289 if (info->pairs != NULL) {
2290 save_mime_part_to_file (info);
2293 result = info->result;
2295 /* This is a GDK lock because we are an idle callback and
2296 * hildon_banner_show_information is or does Gtk+ code */
2298 gdk_threads_enter (); /* CHECKED */
2299 save_mime_part_info_free (info, TRUE);
2301 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2303 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2305 gdk_threads_leave (); /* CHECKED */
2312 save_mime_part_to_file (SaveMimePartInfo *info)
2314 GnomeVFSResult result;
2315 GnomeVFSHandle *handle;
2317 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2319 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0777);
2320 if (result == GNOME_VFS_OK) {
2321 stream = tny_vfs_stream_new (handle);
2322 tny_mime_part_decode_to_stream (pair->part, stream);
2323 g_object_unref (G_OBJECT (stream));
2324 g_object_unref (pair->part);
2325 g_slice_free (SaveMimePartPair, pair);
2326 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2327 info->result = TRUE;
2329 save_mime_part_info_free (info, FALSE);
2330 info->result = FALSE;
2333 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2338 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2340 gboolean is_ok = TRUE;
2341 gint replaced_files = 0;
2342 const GList *files = info->pairs;
2345 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2346 SaveMimePartPair *pair = iter->data;
2347 if (modest_maemo_utils_file_exists (pair->filename)) {
2351 if (replaced_files) {
2352 GtkWidget *confirm_overwrite_dialog;
2353 const gchar *message = (replaced_files == 1) ?
2354 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2355 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2356 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2359 gtk_widget_destroy (confirm_overwrite_dialog);
2363 save_mime_part_info_free (info, TRUE);
2365 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2366 _CS("sfil_ib_saving"));
2367 info->banner = g_object_ref (banner);
2368 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2369 g_object_unref (banner);
2376 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2378 gboolean clean_list = FALSE;
2379 ModestMsgViewWindowPrivate *priv;
2380 GList *files_to_save = NULL;
2381 GtkWidget *save_dialog = NULL;
2382 gchar *folder = NULL;
2383 gboolean canceled = FALSE;
2384 const gchar *filename = NULL;
2385 gchar *save_multiple_str = NULL;
2387 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2388 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2390 if (mime_parts == NULL) {
2391 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2392 if (mime_parts == NULL)
2397 /* prepare dialog */
2398 if (mime_parts->next == NULL) {
2399 /* only one attachment selected */
2400 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2401 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2402 filename = tny_mime_part_get_filename (mime_part);
2404 g_warning ("Tried to save a non-file attachment");
2408 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2409 g_list_length (mime_parts));
2412 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2413 GTK_FILE_CHOOSER_ACTION_SAVE);
2416 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2417 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2421 if (filename != NULL)
2422 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2425 /* if multiple, set multiple string */
2426 if (save_multiple_str) {
2427 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2431 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2432 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2434 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2435 hildon_banner_show_information
2436 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2440 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2441 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2443 if (tny_mime_part_is_attachment (mime_part)) {
2444 SaveMimePartPair *pair;
2446 if ((mime_parts->next != NULL) &&
2447 (tny_mime_part_get_filename (mime_part) == NULL))
2450 pair = g_slice_new0 (SaveMimePartPair);
2451 if (mime_parts->next == NULL) {
2452 pair->filename = g_strdup (chooser_uri);
2455 g_build_filename (chooser_uri,
2456 tny_mime_part_get_filename (mime_part), NULL);
2458 pair->part = g_object_ref (mime_part);
2459 files_to_save = g_list_prepend (files_to_save, pair);
2463 g_free (chooser_uri);
2466 gtk_widget_destroy (save_dialog);
2469 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2470 g_list_free (mime_parts);
2473 if (files_to_save != NULL) {
2474 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2475 info->pairs = files_to_save;
2476 info->result = TRUE;
2477 save_mime_parts_to_file_with_checks (info);
2482 show_remove_attachment_information (gpointer userdata)
2484 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2485 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2487 if (priv->remove_attachment_banner != NULL) {
2488 gtk_widget_destroy (priv->remove_attachment_banner);
2489 g_object_unref (priv->remove_attachment_banner);
2492 priv->remove_attachment_banner = g_object_ref (
2493 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2499 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2501 ModestMsgViewWindowPrivate *priv;
2502 GList *mime_parts = NULL, *node;
2503 gchar *confirmation_message;
2507 /* TnyFolder *folder; */
2509 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2510 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2513 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2515 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2517 /* Remove already purged messages from mime parts list */
2519 while (node != NULL) {
2520 TnyMimePart *part = TNY_MIME_PART (node->data);
2521 if (tny_mime_part_is_purged (part)) {
2522 GList *deleted_node = node;
2523 node = g_list_next (node);
2524 g_object_unref (part);
2525 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2527 node = g_list_next (node);
2531 if (mime_parts == NULL)
2534 n_attachments = g_list_length (mime_parts);
2535 if (n_attachments == 1) {
2536 const gchar *filename;
2538 if (TNY_IS_MSG (mime_parts->data)) {
2540 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2541 filename = tny_header_get_subject (header);
2542 g_object_unref (header);
2543 if (filename == NULL)
2544 filename = _("mail_va_no_subject");
2546 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2548 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2550 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2551 "mcen_nc_purge_files_text",
2552 n_attachments), n_attachments);
2554 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2555 confirmation_message);
2556 g_free (confirmation_message);
2558 if (response != GTK_RESPONSE_OK)
2561 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2562 /* folder = tny_msg_get_folder (msg); */
2563 /* tny_msg_uncache_attachments (msg); */
2564 /* tny_folder_refresh (folder, NULL); */
2565 /* g_object_unref (folder); */
2567 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2568 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2569 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2572 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
2573 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), NULL);
2574 tny_msg_rewrite_cache (msg);
2575 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), msg);
2577 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2578 g_list_free (mime_parts);
2580 if (priv->purge_timeout > 0) {
2581 g_source_remove (priv->purge_timeout);
2582 priv->purge_timeout = 0;
2585 if (priv->remove_attachment_banner) {
2586 gtk_widget_destroy (priv->remove_attachment_banner);
2587 g_object_unref (priv->remove_attachment_banner);
2588 priv->remove_attachment_banner = NULL;
2596 update_window_title (ModestMsgViewWindow *window)
2598 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2600 TnyHeader *header = NULL;
2601 const gchar *subject = NULL;
2603 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
2605 header = tny_msg_get_header (msg);
2606 subject = tny_header_get_subject (header);
2607 g_object_unref (msg);
2610 if ((subject == NULL)||(subject[0] == '\0'))
2611 subject = _("mail_va_no_subject");
2613 gtk_window_set_title (GTK_WINDOW (window), subject);
2616 static void on_move_focus (ModestMsgViewWindow *window,
2617 GtkDirectionType direction,
2620 GtkWidget *current_focus = NULL;
2622 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2623 if ((current_focus != NULL) &&
2624 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2625 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");