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 (op_type,
1604 modest_ui_actions_get_msgs_full_error_handler,
1607 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1608 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1609 g_object_unref (mail_op);
1611 /* Update toolbar dimming rules */
1612 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1618 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1620 ModestMsgViewWindowPrivate *priv;
1621 GtkTreePath *path= NULL;
1622 GtkTreeIter tmp_iter;
1624 gboolean retval = TRUE;
1625 GtkTreeRowReference *row_reference = NULL;
1627 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1628 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1630 /* Update the next row reference if it's not valid. This could
1631 happen if for example the header which it was pointing to,
1632 was deleted. The best place to do it is in the row-deleted
1633 handler but the tinymail model do not work like the glib
1634 tree models and reports the deletion when the row is still
1636 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1637 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1638 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1639 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1642 if (priv->next_row_reference)
1643 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1647 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1649 gtk_tree_model_get_iter (priv->header_model,
1652 gtk_tree_path_free (path);
1654 gtk_tree_model_get (priv->header_model, &tmp_iter,
1655 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1658 /* Read the message & show it */
1659 if (!message_reader (window, priv, header, row_reference)) {
1661 gtk_tree_row_reference_free (row_reference);
1665 g_object_unref (header);
1671 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1673 ModestMsgViewWindowPrivate *priv = NULL;
1674 TnyHeader *header = NULL;
1676 GtkTreePath *path = NULL;
1677 GtkTreeRowReference *row_reference = NULL;
1679 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1680 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1682 /* Check that the model is not empty */
1683 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1686 /* Get the header */
1687 gtk_tree_model_get (priv->header_model,
1689 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1691 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1692 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1693 g_object_unref (header);
1694 return modest_msg_view_window_select_next_message (self);
1697 path = gtk_tree_model_get_path (priv->header_model, &iter);
1698 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1699 gtk_tree_path_free (path);
1701 /* Read the message & show it */
1702 message_reader (self, priv, header, row_reference);
1705 g_object_unref (header);
1711 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1713 ModestMsgViewWindowPrivate *priv = NULL;
1715 GtkTreeRowReference *row_reference = NULL;
1717 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1718 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1720 /* Return inmediatly if there is no header model */
1721 if (!priv->header_model)
1724 path = gtk_tree_row_reference_get_path (priv->row_reference);
1725 while (gtk_tree_path_prev (path)) {
1729 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1730 gtk_tree_model_get (priv->header_model, &iter,
1731 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1735 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1736 g_object_unref (header);
1740 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1741 /* Read the message & show it */
1742 if (!message_reader (window, priv, header, row_reference)) {
1743 gtk_tree_row_reference_free (row_reference);
1744 g_object_unref (header);
1748 gtk_tree_path_free (path);
1749 g_object_unref (header);
1754 gtk_tree_path_free (path);
1759 view_msg_cb (ModestMailOperation *mail_op,
1764 ModestMsgViewWindow *self = NULL;
1765 ModestMsgViewWindowPrivate *priv = NULL;
1766 GtkTreeRowReference *row_reference = NULL;
1768 /* If there was any error */
1769 row_reference = (GtkTreeRowReference *) user_data;
1770 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1771 gtk_tree_row_reference_free (row_reference);
1775 /* Get the window */
1776 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1777 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1778 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1780 /* Update the row reference */
1781 gtk_tree_row_reference_free (priv->row_reference);
1782 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1783 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1784 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1785 gtk_tree_row_reference_free (row_reference);
1787 /* Mark header as read */
1788 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1789 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
1791 /* Set new message */
1792 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), msg);
1793 modest_msg_view_window_update_priority (self);
1794 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1795 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1797 /* Set the new message uid of the window */
1798 if (priv->msg_uid) {
1799 g_free (priv->msg_uid);
1800 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1803 /* Notify the observers */
1804 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1805 0, priv->header_model, priv->row_reference);
1807 /* Free new references */
1808 g_object_unref (self);
1812 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1814 ModestMsgViewWindowPrivate *priv;
1816 TnyFolderType folder_type;
1818 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1820 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1822 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
1826 folder = tny_msg_get_folder (msg);
1829 folder_type = tny_folder_get_folder_type (folder);
1831 if (folder_type == TNY_FOLDER_TYPE_NORMAL || folder_type == TNY_FOLDER_TYPE_UNKNOWN) {
1832 const gchar *fname = tny_folder_get_name (folder);
1833 folder_type = modest_tny_folder_guess_folder_type_from_name (fname);
1836 g_object_unref (folder);
1838 g_object_unref (msg);
1846 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1848 ModestMsgViewWindowPrivate *priv;
1849 TnyHeaderFlags flags = 0;
1851 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1853 if (priv->header_model) {
1856 GtkTreePath *path = NULL;
1858 path = gtk_tree_row_reference_get_path (priv->row_reference);
1859 g_return_if_fail (path != NULL);
1860 gtk_tree_model_get_iter (priv->header_model,
1862 gtk_tree_row_reference_get_path (priv->row_reference));
1864 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1866 flags = tny_header_get_flags (header);
1867 gtk_tree_path_free (path);
1870 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1875 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1877 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1878 ModestWindowPrivate *parent_priv;
1879 ModestWindowMgr *mgr;
1880 gboolean is_fullscreen;
1881 GtkAction *fs_toggle_action;
1884 mgr = modest_runtime_get_window_mgr ();
1885 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1887 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1889 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1890 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1891 if (is_fullscreen != active) {
1892 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1901 set_homogeneous (GtkWidget *widget,
1904 if (GTK_IS_TOOL_ITEM (widget)) {
1905 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1906 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1911 modest_msg_view_window_show_toolbar (ModestWindow *self,
1912 gboolean show_toolbar)
1914 ModestMsgViewWindowPrivate *priv = NULL;
1915 ModestWindowPrivate *parent_priv;
1916 GtkWidget *reply_button = NULL, *menu = NULL;
1917 GtkWidget *placeholder = NULL;
1919 const gchar *action_name;
1922 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1923 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1925 /* Set optimized view status */
1926 priv->optimized_view = !show_toolbar;
1928 if (!parent_priv->toolbar) {
1929 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1931 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1933 /* Set homogeneous toolbar */
1934 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1935 set_homogeneous, NULL);
1937 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1938 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1939 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1940 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1941 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1942 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1943 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1944 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1946 /* Add ProgressBar (Transfer toolbar) */
1947 priv->progress_bar = modest_progress_bar_widget_new ();
1948 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1949 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1950 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1951 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1952 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1954 /* Connect cancel 'clicked' signal to abort progress mode */
1955 g_signal_connect(priv->cancel_toolitem, "clicked",
1956 G_CALLBACK(cancel_progressbar),
1959 /* Add it to the observers list */
1960 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1963 hildon_window_add_toolbar (HILDON_WINDOW (self),
1964 GTK_TOOLBAR (parent_priv->toolbar));
1967 /* Set reply button tap and hold menu */
1968 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1969 "/ToolBar/ToolbarMessageReply");
1970 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1971 "/ToolbarReplyCSM");
1972 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1976 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1977 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1978 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1980 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1981 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1984 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1985 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1988 /* Update also the actions (to update the toggles in the
1989 menus), we have to do it manually because some other window
1990 of the same time could have changed it (remember that the
1991 toolbar fullscreen mode is shared by all the windows of the
1993 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1994 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
1996 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
1998 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1999 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2004 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2006 ModestMsgViewWindow *window)
2008 if (!GTK_WIDGET_VISIBLE (window))
2011 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2015 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2017 ModestMsgViewWindowPrivate *priv;
2019 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2020 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2022 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2026 cancel_progressbar (GtkToolButton *toolbutton,
2027 ModestMsgViewWindow *self)
2030 ModestMsgViewWindowPrivate *priv;
2032 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2034 /* Get operation observers and cancel its current operation */
2035 tmp = priv->progress_widgets;
2037 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2038 tmp=g_slist_next(tmp);
2042 observers_empty (ModestMsgViewWindow *self)
2045 ModestMsgViewWindowPrivate *priv;
2046 gboolean is_empty = TRUE;
2047 guint pending_ops = 0;
2049 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2050 tmp = priv->progress_widgets;
2052 /* Check all observers */
2053 while (tmp && is_empty) {
2054 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2055 is_empty = pending_ops == 0;
2057 tmp = g_slist_next(tmp);
2064 on_account_removed (TnyAccountStore *account_store,
2065 TnyAccount *account,
2068 /* Do nothing if it's a transport account, because we only
2069 show the messages of a store account */
2070 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2071 const gchar *parent_acc = NULL;
2072 const gchar *our_acc = NULL;
2074 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2075 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2077 /* Close this window if I'm showing a message of the removed account */
2078 if (strcmp (parent_acc, our_acc) == 0)
2079 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2084 on_queue_changed (ModestMailOperationQueue *queue,
2085 ModestMailOperation *mail_op,
2086 ModestMailOperationQueueNotification type,
2087 ModestMsgViewWindow *self)
2090 ModestMsgViewWindowPrivate *priv;
2091 ModestMailOperationTypeOperation op_type;
2092 ModestToolBarModes mode;
2094 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2095 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2097 /* If this operations was created by another window, do nothing */
2098 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2101 /* Get toolbar mode from operation id*/
2102 op_type = modest_mail_operation_get_type_operation (mail_op);
2104 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2105 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2106 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2107 mode = TOOLBAR_MODE_TRANSFER;
2110 mode = TOOLBAR_MODE_NORMAL;
2114 /* Add operation observers and change toolbar if neccessary*/
2115 tmp = priv->progress_widgets;
2117 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2118 if (mode == TOOLBAR_MODE_TRANSFER) {
2119 /* Enable transfer toolbar mode */
2120 set_toolbar_transfer_mode(self);
2122 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2124 tmp = g_slist_next (tmp);
2129 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2130 if (mode == TOOLBAR_MODE_TRANSFER) {
2132 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2134 tmp = g_slist_next (tmp);
2138 /* If no more operations are being observed, NORMAL mode is enabled again */
2139 if (observers_empty (self)) {
2140 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2148 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2150 ModestMsgViewWindowPrivate *priv;
2151 GList *selected_attachments = NULL;
2153 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2154 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2156 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2158 return selected_attachments;
2162 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2164 ModestMsgViewWindowPrivate *priv;
2165 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2166 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2168 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2170 if (mime_part == NULL) {
2171 gboolean error = FALSE;
2172 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2173 if (selected_attachments == NULL) {
2175 } else if (g_list_length (selected_attachments) > 1) {
2176 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2179 mime_part = (TnyMimePart *) selected_attachments->data;
2180 g_object_ref (mime_part);
2182 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2183 g_list_free (selected_attachments);
2188 g_object_ref (mime_part);
2191 if (tny_mime_part_is_purged (mime_part)) {
2192 g_object_unref (mime_part);
2196 if (!TNY_IS_MSG (mime_part)) {
2197 gchar *filepath = NULL;
2198 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2199 TnyFsStream *temp_stream = NULL;
2201 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, &filepath);
2204 const gchar *content_type;
2205 content_type = tny_mime_part_get_content_type (mime_part);
2206 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2208 modest_platform_activate_file (filepath, content_type);
2209 g_object_unref (temp_stream);
2211 /* NOTE: files in the temporary area will be automatically
2212 * cleaned after some time if they are no longer in use */
2215 /* message attachment */
2216 TnyHeader *header = NULL;
2217 ModestWindowMgr *mgr;
2218 ModestWindow *msg_win = NULL;
2221 header = tny_msg_get_header (TNY_MSG (mime_part));
2222 mgr = modest_runtime_get_window_mgr ();
2223 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2226 if (msg_win) /* there is already a window for this uid; top it */
2227 gtk_window_present (GTK_WINDOW(msg_win));
2229 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2230 * thus, we don't do anything */
2231 g_warning ("window for is already being created");
2233 /* it's not found, so create a new window for it */
2234 modest_window_mgr_register_header (mgr, header); /* register the uid before building the window */
2235 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2237 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2238 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, NULL);
2239 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2240 modest_window_get_zoom (MODEST_WINDOW (window)));
2241 modest_window_mgr_register_window (mgr, msg_win);
2242 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2243 gtk_widget_show_all (GTK_WIDGET (msg_win));
2246 g_object_unref (mime_part);
2262 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2263 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2264 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2265 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2268 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2272 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2273 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2274 g_free (pair->filename);
2275 g_object_unref (pair->part);
2276 g_slice_free (SaveMimePartPair, pair);
2278 g_list_free (info->pairs);
2281 gtk_widget_destroy (info->banner);
2282 g_object_unref (info->banner);
2283 g_slice_free (SaveMimePartInfo, info);
2288 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2290 if (info->pairs != NULL) {
2291 save_mime_part_to_file (info);
2294 result = info->result;
2296 /* This is a GDK lock because we are an idle callback and
2297 * hildon_banner_show_information is or does Gtk+ code */
2299 gdk_threads_enter (); /* CHECKED */
2300 save_mime_part_info_free (info, TRUE);
2302 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2304 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2306 gdk_threads_leave (); /* CHECKED */
2313 save_mime_part_to_file (SaveMimePartInfo *info)
2315 GnomeVFSResult result;
2316 GnomeVFSHandle *handle;
2318 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2320 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0777);
2321 if (result == GNOME_VFS_OK) {
2322 stream = tny_vfs_stream_new (handle);
2323 tny_mime_part_decode_to_stream (pair->part, stream);
2324 g_object_unref (G_OBJECT (stream));
2325 g_object_unref (pair->part);
2326 g_slice_free (SaveMimePartPair, pair);
2327 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2328 info->result = TRUE;
2330 save_mime_part_info_free (info, FALSE);
2331 info->result = FALSE;
2334 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2339 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2341 gboolean is_ok = TRUE;
2342 gint replaced_files = 0;
2343 const GList *files = info->pairs;
2346 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2347 SaveMimePartPair *pair = iter->data;
2348 if (modest_maemo_utils_file_exists (pair->filename)) {
2352 if (replaced_files) {
2353 GtkWidget *confirm_overwrite_dialog;
2354 const gchar *message = (replaced_files == 1) ?
2355 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2356 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2357 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2360 gtk_widget_destroy (confirm_overwrite_dialog);
2364 save_mime_part_info_free (info, TRUE);
2366 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2367 _CS("sfil_ib_saving"));
2368 info->banner = g_object_ref (banner);
2369 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2370 g_object_unref (banner);
2377 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2379 gboolean clean_list = FALSE;
2380 ModestMsgViewWindowPrivate *priv;
2381 GList *files_to_save = NULL;
2382 GtkWidget *save_dialog = NULL;
2383 gchar *folder = NULL;
2384 gboolean canceled = FALSE;
2385 const gchar *filename = NULL;
2386 gchar *save_multiple_str = NULL;
2388 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2389 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2391 if (mime_parts == NULL) {
2392 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2393 if (mime_parts == NULL)
2398 /* prepare dialog */
2399 if (mime_parts->next == NULL) {
2400 /* only one attachment selected */
2401 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2402 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2403 filename = tny_mime_part_get_filename (mime_part);
2405 g_warning ("Tried to save a non-file attachment");
2409 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2410 g_list_length (mime_parts));
2413 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2414 GTK_FILE_CHOOSER_ACTION_SAVE);
2417 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2418 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2422 if (filename != NULL)
2423 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2426 /* if multiple, set multiple string */
2427 if (save_multiple_str) {
2428 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2432 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2433 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2435 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2436 hildon_banner_show_information
2437 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2441 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2442 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2444 if (tny_mime_part_is_attachment (mime_part)) {
2445 SaveMimePartPair *pair;
2447 if ((mime_parts->next != NULL) &&
2448 (tny_mime_part_get_filename (mime_part) == NULL))
2451 pair = g_slice_new0 (SaveMimePartPair);
2452 if (mime_parts->next == NULL) {
2453 pair->filename = g_strdup (chooser_uri);
2456 g_build_filename (chooser_uri,
2457 tny_mime_part_get_filename (mime_part), NULL);
2459 pair->part = g_object_ref (mime_part);
2460 files_to_save = g_list_prepend (files_to_save, pair);
2464 g_free (chooser_uri);
2467 gtk_widget_destroy (save_dialog);
2470 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2471 g_list_free (mime_parts);
2474 if (files_to_save != NULL) {
2475 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2476 info->pairs = files_to_save;
2477 info->result = TRUE;
2478 save_mime_parts_to_file_with_checks (info);
2483 show_remove_attachment_information (gpointer userdata)
2485 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2486 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2488 if (priv->remove_attachment_banner != NULL) {
2489 gtk_widget_destroy (priv->remove_attachment_banner);
2490 g_object_unref (priv->remove_attachment_banner);
2493 priv->remove_attachment_banner = g_object_ref (
2494 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2500 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2502 ModestMsgViewWindowPrivate *priv;
2503 GList *mime_parts = NULL, *node;
2504 gchar *confirmation_message;
2508 /* TnyFolder *folder; */
2510 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2511 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2514 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2516 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2518 /* Remove already purged messages from mime parts list */
2520 while (node != NULL) {
2521 TnyMimePart *part = TNY_MIME_PART (node->data);
2522 if (tny_mime_part_is_purged (part)) {
2523 GList *deleted_node = node;
2524 node = g_list_next (node);
2525 g_object_unref (part);
2526 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2528 node = g_list_next (node);
2532 if (mime_parts == NULL)
2535 n_attachments = g_list_length (mime_parts);
2536 if (n_attachments == 1) {
2537 const gchar *filename;
2539 if (TNY_IS_MSG (mime_parts->data)) {
2541 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2542 filename = tny_header_get_subject (header);
2543 g_object_unref (header);
2544 if (filename == NULL)
2545 filename = _("mail_va_no_subject");
2547 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2549 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2551 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2552 "mcen_nc_purge_files_text",
2553 n_attachments), n_attachments);
2555 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2556 confirmation_message);
2557 g_free (confirmation_message);
2559 if (response != GTK_RESPONSE_OK)
2562 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2563 /* folder = tny_msg_get_folder (msg); */
2564 /* tny_msg_uncache_attachments (msg); */
2565 /* tny_folder_refresh (folder, NULL); */
2566 /* g_object_unref (folder); */
2568 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2569 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2570 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2573 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
2574 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), NULL);
2575 tny_msg_rewrite_cache (msg);
2576 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), msg);
2578 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2579 g_list_free (mime_parts);
2581 if (priv->purge_timeout > 0) {
2582 g_source_remove (priv->purge_timeout);
2583 priv->purge_timeout = 0;
2586 if (priv->remove_attachment_banner) {
2587 gtk_widget_destroy (priv->remove_attachment_banner);
2588 g_object_unref (priv->remove_attachment_banner);
2589 priv->remove_attachment_banner = NULL;
2597 update_window_title (ModestMsgViewWindow *window)
2599 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2601 TnyHeader *header = NULL;
2602 const gchar *subject = NULL;
2604 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
2606 header = tny_msg_get_header (msg);
2607 subject = tny_header_get_subject (header);
2608 g_object_unref (msg);
2611 if ((subject == NULL)||(subject[0] == '\0'))
2612 subject = _("mail_va_no_subject");
2614 gtk_window_set_title (GTK_WINDOW (window), subject);
2617 static void on_move_focus (ModestMsgViewWindow *window,
2618 GtkDirectionType direction,
2621 GtkWidget *current_focus = NULL;
2623 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2624 if ((current_focus != NULL) &&
2625 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2626 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");