1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <glib/gi18n.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
34 #include <tny-mime-part.h>
35 #include <tny-vfs-stream.h>
36 #include "modest-marshal.h"
37 #include "modest-platform.h"
38 #include <modest-maemo-utils.h>
39 #include <modest-tny-msg.h>
40 #include <modest-msg-view-window.h>
41 #include <modest-attachments-view.h>
42 #include <modest-main-window-ui.h>
43 #include "modest-msg-view-window-ui-dimming.h"
44 #include <modest-widget-memory.h>
45 #include <modest-runtime.h>
46 #include <modest-window-priv.h>
47 #include <modest-tny-folder.h>
48 #include <modest-text-utils.h>
49 #include <modest-account-mgr-helpers.h>
50 #include "modest-progress-bar-widget.h"
51 #include "modest-defs.h"
52 #include "modest-hildon-includes.h"
53 #include "modest-ui-dimming-manager.h"
54 #include <gdk/gdkkeysyms.h>
55 #include <modest-tny-account.h>
56 #include <modest-mime-part-view.h>
57 #include <modest-isearch-view.h>
60 #include <glib/gstdio.h>
62 #define DEFAULT_FOLDER "MyDocs/.documents"
64 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
65 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
66 static void modest_header_view_observer_init(
67 ModestHeaderViewObserverIface *iface_class);
68 static void modest_msg_view_window_finalize (GObject *obj);
69 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
71 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
72 ModestMsgViewWindow *obj);
73 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
74 ModestMsgViewWindow *obj);
76 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
77 static void modest_msg_view_window_set_zoom (ModestWindow *window,
79 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
80 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
81 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
82 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
85 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
86 GdkEventWindowState *event,
88 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
90 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
91 gboolean show_toolbar);
93 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
95 ModestMsgViewWindow *window);
96 void modest_msg_view_window_on_row_changed(
97 GtkTreeModel *header_model,
100 ModestMsgViewWindow *window);
102 void modest_msg_view_window_on_row_deleted(
103 GtkTreeModel *header_model,
105 ModestMsgViewWindow *window);
107 void modest_msg_view_window_on_row_inserted(
108 GtkTreeModel *header_model,
109 GtkTreePath *tree_path,
110 GtkTreeIter *tree_iter,
111 ModestMsgViewWindow *window);
113 void modest_msg_view_window_on_row_reordered(
114 GtkTreeModel *header_model,
118 ModestMsgViewWindow *window);
120 void modest_msg_view_window_update_model_replaced(
121 ModestHeaderViewObserver *window,
123 const gchar *tny_folder_id);
125 static void cancel_progressbar (GtkToolButton *toolbutton,
126 ModestMsgViewWindow *self);
128 static void on_queue_changed (ModestMailOperationQueue *queue,
129 ModestMailOperation *mail_op,
130 ModestMailOperationQueueNotification type,
131 ModestMsgViewWindow *self);
133 static void on_account_removed (TnyAccountStore *account_store,
137 static void on_move_focus (GtkWidget *widget,
138 GtkDirectionType direction,
141 static void view_msg_cb (ModestMailOperation *mail_op,
148 static void set_toolbar_mode (ModestMsgViewWindow *self,
149 ModestToolBarModes mode);
151 static void update_window_title (ModestMsgViewWindow *window);
153 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
154 static void init_window (ModestMsgViewWindow *obj);
157 /* list my signals */
163 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
164 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
165 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
168 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
169 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
170 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
171 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
172 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
173 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
174 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
177 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
178 struct _ModestMsgViewWindowPrivate {
181 GtkWidget *main_scroll;
182 GtkWidget *find_toolbar;
185 /* Progress observers */
186 GtkWidget *progress_bar;
187 GSList *progress_widgets;
190 GtkWidget *progress_toolitem;
191 GtkWidget *cancel_toolitem;
192 GtkWidget *prev_toolitem;
193 GtkWidget *next_toolitem;
194 ModestToolBarModes current_toolbar_mode;
196 /* Optimized view enabled */
197 gboolean optimized_view;
199 /* Whether this was created via the *_new_for_search_result() function. */
200 gboolean is_search_result;
202 /* A reference to the @model of the header view
203 * to allow selecting previous/next messages,
204 * if the message is currently selected in the header view.
206 const gchar *header_folder_id;
207 GtkTreeModel *header_model;
208 GtkTreeRowReference *row_reference;
209 GtkTreeRowReference *next_row_reference;
211 gulong clipboard_change_handler;
212 gulong queue_change_handler;
213 gulong account_removed_handler;
214 gulong row_changed_handler;
215 gulong row_deleted_handler;
216 gulong row_inserted_handler;
217 gulong rows_reordered_handler;
220 GtkWidget *remove_attachment_banner;
222 guint progress_bar_timeout;
227 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
228 MODEST_TYPE_MSG_VIEW_WINDOW, \
229 ModestMsgViewWindowPrivate))
231 static GtkWindowClass *parent_class = NULL;
233 /* uncomment the following if you have defined any signals */
234 static guint signals[LAST_SIGNAL] = {0};
237 modest_msg_view_window_get_type (void)
239 static GType my_type = 0;
241 static const GTypeInfo my_info = {
242 sizeof(ModestMsgViewWindowClass),
243 NULL, /* base init */
244 NULL, /* base finalize */
245 (GClassInitFunc) modest_msg_view_window_class_init,
246 NULL, /* class finalize */
247 NULL, /* class data */
248 sizeof(ModestMsgViewWindow),
250 (GInstanceInitFunc) modest_msg_view_window_init,
253 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
254 "ModestMsgViewWindow",
257 static const GInterfaceInfo modest_header_view_observer_info =
259 (GInterfaceInitFunc) modest_header_view_observer_init,
260 NULL, /* interface_finalize */
261 NULL /* interface_data */
264 g_type_add_interface_static (my_type,
265 MODEST_TYPE_HEADER_VIEW_OBSERVER,
266 &modest_header_view_observer_info);
272 save_state (ModestWindow *self)
274 modest_widget_memory_save (modest_runtime_get_conf (),
276 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
281 restore_settings (ModestMsgViewWindow *self)
284 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
287 conf = modest_runtime_get_conf ();
288 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
289 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
290 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
291 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
292 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
293 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
294 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
295 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
296 modest_widget_memory_restore (conf,
298 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
302 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
304 GObjectClass *gobject_class;
305 ModestWindowClass *modest_window_class;
306 gobject_class = (GObjectClass*) klass;
307 modest_window_class = (ModestWindowClass *) klass;
309 parent_class = g_type_class_peek_parent (klass);
310 gobject_class->finalize = modest_msg_view_window_finalize;
312 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
313 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
314 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
315 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
316 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
317 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
319 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
321 modest_window_class->save_state_func = save_state;
323 signals[MSG_CHANGED_SIGNAL] =
324 g_signal_new ("msg-changed",
325 G_TYPE_FROM_CLASS (gobject_class),
327 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
329 modest_marshal_VOID__POINTER_POINTER,
330 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
333 static void modest_header_view_observer_init(
334 ModestHeaderViewObserverIface *iface_class)
336 iface_class->update_func = modest_msg_view_window_update_model_replaced;
340 modest_msg_view_window_init (ModestMsgViewWindow *obj)
342 ModestMsgViewWindowPrivate *priv;
343 ModestWindowPrivate *parent_priv = NULL;
344 GtkActionGroup *action_group = NULL;
345 GError *error = NULL;
346 GdkPixbuf *window_icon;
348 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
349 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
350 parent_priv->ui_manager = gtk_ui_manager_new();
352 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
353 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
355 /* Add common actions */
356 gtk_action_group_add_actions (action_group,
357 modest_action_entries,
358 G_N_ELEMENTS (modest_action_entries),
360 gtk_action_group_add_toggle_actions (action_group,
361 modest_toggle_action_entries,
362 G_N_ELEMENTS (modest_toggle_action_entries),
364 gtk_action_group_add_toggle_actions (action_group,
365 msg_view_toggle_action_entries,
366 G_N_ELEMENTS (msg_view_toggle_action_entries),
368 gtk_action_group_add_radio_actions (action_group,
369 msg_view_zoom_action_entries,
370 G_N_ELEMENTS (msg_view_zoom_action_entries),
372 G_CALLBACK (modest_ui_actions_on_change_zoom),
375 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
376 g_object_unref (action_group);
378 /* Load the UI definition */
379 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
382 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
383 g_error_free (error);
388 /* Add accelerators */
389 gtk_window_add_accel_group (GTK_WINDOW (obj),
390 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
392 priv->is_search_result = FALSE;
394 priv->msg_view = NULL;
395 priv->header_model = NULL;
396 priv->header_folder_id = NULL;
397 priv->clipboard_change_handler = 0;
398 priv->queue_change_handler = 0;
399 priv->account_removed_handler = 0;
400 priv->row_changed_handler = 0;
401 priv->row_deleted_handler = 0;
402 priv->row_inserted_handler = 0;
403 priv->rows_reordered_handler = 0;
404 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
406 priv->optimized_view = FALSE;
407 priv->progress_bar_timeout = 0;
408 priv->purge_timeout = 0;
409 priv->remove_attachment_banner = NULL;
410 priv->msg_uid = NULL;
413 init_window (MODEST_MSG_VIEW_WINDOW(obj));
414 /* Set window icon */
415 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
417 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
418 g_object_unref (window_icon);
422 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
423 GTK_WINDOW(obj),"applications_email_viewer");
428 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
430 ModestMsgViewWindowPrivate *priv = NULL;
432 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
434 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
436 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
438 if (priv->progress_bar_timeout > 0) {
439 g_source_remove (priv->progress_bar_timeout);
440 priv->progress_bar_timeout = 0;
447 set_toolbar_mode (ModestMsgViewWindow *self,
448 ModestToolBarModes mode)
450 ModestWindowPrivate *parent_priv;
451 ModestMsgViewWindowPrivate *priv;
452 /* GtkWidget *widget = NULL; */
454 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
456 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
457 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
459 /* Sets current toolbar mode */
460 priv->current_toolbar_mode = mode;
462 /* Update toolbar dimming state */
463 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
466 case TOOLBAR_MODE_NORMAL:
467 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
468 /* gtk_action_set_sensitive (widget, TRUE); */
469 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
470 /* gtk_action_set_sensitive (widget, TRUE); */
471 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
472 /* gtk_action_set_sensitive (widget, TRUE); */
473 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
474 /* gtk_action_set_sensitive (widget, TRUE); */
476 if (priv->prev_toolitem)
477 gtk_widget_show (priv->prev_toolitem);
479 if (priv->next_toolitem)
480 gtk_widget_show (priv->next_toolitem);
482 if (priv->progress_toolitem)
483 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
484 if (priv->progress_bar)
485 gtk_widget_hide (priv->progress_bar);
487 if (priv->cancel_toolitem)
488 gtk_widget_hide (priv->cancel_toolitem);
490 /* Hide toolbar if optimized view is enabled */
491 if (priv->optimized_view) {
492 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
493 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
497 case TOOLBAR_MODE_TRANSFER:
498 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
499 /* gtk_action_set_sensitive (widget, FALSE); */
500 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
501 /* gtk_action_set_sensitive (widget, FALSE); */
502 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
503 /* gtk_action_set_sensitive (widget, FALSE); */
504 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
505 /* gtk_action_set_sensitive (widget, FALSE); */
507 if (priv->prev_toolitem)
508 gtk_widget_hide (priv->prev_toolitem);
510 if (priv->next_toolitem)
511 gtk_widget_hide (priv->next_toolitem);
513 if (priv->progress_toolitem)
514 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
515 if (priv->progress_bar)
516 gtk_widget_show (priv->progress_bar);
518 if (priv->cancel_toolitem)
519 gtk_widget_show (priv->cancel_toolitem);
521 /* Show toolbar if it's hiden (optimized view ) */
522 if (priv->optimized_view) {
523 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
524 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
529 g_return_if_reached ();
536 menubar_to_menu (GtkUIManager *ui_manager)
538 GtkWidget *main_menu;
540 /* Get the menubar from the UI manager */
541 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
547 init_window (ModestMsgViewWindow *obj)
549 GtkWidget *main_vbox;
550 ModestMsgViewWindowPrivate *priv;
551 ModestWindowPrivate *parent_priv;
553 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
554 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
556 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
557 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
558 main_vbox = gtk_vbox_new (FALSE, 6);
560 #ifdef MODEST_USE_MOZEMBED
561 priv->main_scroll = priv->msg_view;
562 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
564 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
565 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
567 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
568 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
569 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
571 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
572 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
574 priv->find_toolbar = hildon_find_toolbar_new (NULL);
575 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
576 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
578 gtk_widget_show_all (GTK_WIDGET(main_vbox));
582 modest_msg_view_window_disconnect_signals (ModestWindow *self)
584 ModestMsgViewWindowPrivate *priv;
585 ModestHeaderView *header_view = NULL;
586 ModestWindow *main_window = NULL;
588 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
590 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
591 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
592 priv->clipboard_change_handler))
593 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
594 priv->clipboard_change_handler);
596 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
597 priv->queue_change_handler))
598 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
599 priv->queue_change_handler);
601 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
602 priv->account_removed_handler))
603 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
604 priv->account_removed_handler);
606 if (priv->header_model) {
607 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
608 priv->row_changed_handler))
609 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
610 priv->row_changed_handler);
612 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
613 priv->row_deleted_handler))
614 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
615 priv->row_deleted_handler);
617 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
618 priv->row_inserted_handler))
619 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
620 priv->row_inserted_handler);
622 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
623 priv->rows_reordered_handler))
624 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
625 priv->rows_reordered_handler);
628 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
629 FALSE); /* don't create */
633 header_view = MODEST_HEADER_VIEW(
634 modest_main_window_get_child_widget(
635 MODEST_MAIN_WINDOW(main_window),
636 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
637 if (header_view == NULL)
640 modest_header_view_remove_observer(header_view,
641 MODEST_HEADER_VIEW_OBSERVER(self));
645 modest_msg_view_window_finalize (GObject *obj)
647 ModestMsgViewWindowPrivate *priv;
649 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
651 /* Sanity check: shouldn't be needed, the window mgr should
652 call this function before */
653 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
655 if (priv->header_model != NULL) {
656 g_object_unref (priv->header_model);
657 priv->header_model = NULL;
660 if (priv->progress_bar_timeout > 0) {
661 g_source_remove (priv->progress_bar_timeout);
662 priv->progress_bar_timeout = 0;
665 if (priv->remove_attachment_banner) {
666 gtk_widget_destroy (priv->remove_attachment_banner);
667 g_object_unref (priv->remove_attachment_banner);
668 priv->remove_attachment_banner = NULL;
671 if (priv->purge_timeout > 0) {
672 g_source_remove (priv->purge_timeout);
673 priv->purge_timeout = 0;
676 if (priv->row_reference) {
677 gtk_tree_row_reference_free (priv->row_reference);
678 priv->row_reference = NULL;
681 if (priv->next_row_reference) {
682 gtk_tree_row_reference_free (priv->next_row_reference);
683 priv->next_row_reference = NULL;
687 g_free (priv->msg_uid);
688 priv->msg_uid = NULL;
691 G_OBJECT_CLASS(parent_class)->finalize (obj);
695 select_next_valid_row (GtkTreeModel *model,
696 GtkTreeRowReference **row_reference,
699 GtkTreeIter tmp_iter;
700 GtkTreePath *path, *next;
701 gboolean retval = FALSE;
703 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
705 path = gtk_tree_row_reference_get_path (*row_reference);
706 gtk_tree_model_get_iter (model, &tmp_iter, path);
707 gtk_tree_row_reference_free (*row_reference);
708 *row_reference = NULL;
710 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
711 next = gtk_tree_model_get_path (model, &tmp_iter);
712 *row_reference = gtk_tree_row_reference_new (model, next);
714 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
715 next = gtk_tree_model_get_path (model, &tmp_iter);
717 /* Ensure that we are not selecting the same */
718 if (gtk_tree_path_compare (path, next) != 0) {
719 *row_reference = gtk_tree_row_reference_new (model, next);
725 gtk_tree_path_free (path);
730 /* TODO: This should be in _init(), with the parameters as properties. */
732 modest_msg_view_window_construct (ModestMsgViewWindow *self,
733 const gchar *modest_account_name,
734 const gchar *msg_uid)
737 ModestMsgViewWindowPrivate *priv = NULL;
738 ModestWindowPrivate *parent_priv = NULL;
739 ModestDimmingRulesGroup *menu_rules_group = NULL;
740 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
741 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
743 obj = G_OBJECT (self);
744 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
745 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
747 priv->msg_uid = g_strdup (msg_uid);
750 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
751 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
752 gtk_widget_show (parent_priv->menubar);
753 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
755 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
756 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
757 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
759 /* Add common dimming rules */
760 modest_dimming_rules_group_add_rules (menu_rules_group,
761 modest_msg_view_menu_dimming_entries,
762 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
763 MODEST_WINDOW (self));
764 modest_dimming_rules_group_add_rules (toolbar_rules_group,
765 modest_msg_view_toolbar_dimming_entries,
766 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
767 MODEST_WINDOW (self));
768 modest_dimming_rules_group_add_rules (clipboard_rules_group,
769 modest_msg_view_clipboard_dimming_entries,
770 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
771 MODEST_WINDOW (self));
773 /* Insert dimming rules group for this window */
774 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
775 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
776 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
777 g_object_unref (menu_rules_group);
778 g_object_unref (toolbar_rules_group);
779 g_object_unref (clipboard_rules_group);
781 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
783 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
785 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);
786 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
787 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
788 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
789 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
790 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
791 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
792 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
793 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
794 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
795 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
797 g_signal_connect (G_OBJECT (obj), "key-release-event",
798 G_CALLBACK (modest_msg_view_window_key_event),
801 g_signal_connect (G_OBJECT (obj), "key-press-event",
802 G_CALLBACK (modest_msg_view_window_key_event),
805 g_signal_connect (G_OBJECT (obj), "window-state-event",
806 G_CALLBACK (modest_msg_view_window_window_state_event),
809 g_signal_connect (G_OBJECT (obj), "move-focus",
810 G_CALLBACK (on_move_focus), obj);
812 /* Mail Operation Queue */
813 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
815 G_CALLBACK (on_queue_changed),
818 /* Account manager */
819 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
821 G_CALLBACK(on_account_removed),
824 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
826 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
827 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
828 priv->last_search = NULL;
830 /* Init the clipboard actions dim status */
831 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
833 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
835 /* Check toolbar dimming rules */
836 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
837 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
841 /* FIXME: parameter checks */
843 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
844 const gchar *modest_account_name,
845 const gchar *msg_uid,
847 GtkTreeRowReference *row_reference)
849 ModestMsgViewWindow *window = NULL;
850 ModestMsgViewWindowPrivate *priv = NULL;
851 TnyFolder *header_folder = NULL;
852 ModestHeaderView *header_view = NULL;
853 ModestWindow *main_window = NULL;
854 ModestWindowMgr *mgr = NULL;
856 mgr = modest_runtime_get_window_mgr ();
857 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
858 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
860 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
862 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
864 /* Remember the message list's TreeModel so we can detect changes
865 * and change the list selection when necessary: */
867 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
869 g_warning ("%s: BUG: no main window", __FUNCTION__);
873 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
874 MODEST_MAIN_WINDOW(main_window),
875 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
876 if (header_view != NULL){
877 header_folder = modest_header_view_get_folder(header_view);
878 g_assert(header_folder != NULL);
879 priv->header_folder_id = tny_folder_get_id(header_folder);
880 g_assert(priv->header_folder_id != NULL);
881 g_object_unref(header_folder);
884 priv->header_model = g_object_ref(model);
885 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
886 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
887 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
889 priv->row_changed_handler = g_signal_connect(
890 GTK_TREE_MODEL(model), "row-changed",
891 G_CALLBACK(modest_msg_view_window_on_row_changed),
893 priv->row_deleted_handler = g_signal_connect(
894 GTK_TREE_MODEL(model), "row-deleted",
895 G_CALLBACK(modest_msg_view_window_on_row_deleted),
897 priv->row_inserted_handler = g_signal_connect (
898 GTK_TREE_MODEL(model), "row-inserted",
899 G_CALLBACK(modest_msg_view_window_on_row_inserted),
901 priv->rows_reordered_handler = g_signal_connect(
902 GTK_TREE_MODEL(model), "rows-reordered",
903 G_CALLBACK(modest_msg_view_window_on_row_reordered),
906 if (header_view != NULL){
907 modest_header_view_add_observer(header_view,
908 MODEST_HEADER_VIEW_OBSERVER(window));
911 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
912 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
913 gtk_widget_show_all (GTK_WIDGET (window));
915 modest_msg_view_window_update_priority (window);
917 /* Check toolbar dimming rules */
918 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
920 return MODEST_WINDOW(window);
924 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
925 const gchar *modest_account_name,
926 const gchar *msg_uid)
928 ModestMsgViewWindow *window = NULL;
929 ModestMsgViewWindowPrivate *priv = NULL;
930 ModestWindowMgr *mgr = NULL;
932 mgr = modest_runtime_get_window_mgr ();
933 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
934 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
935 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
937 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
939 /* Remember that this is a search result,
940 * so we can disable some UI appropriately: */
941 priv->is_search_result = TRUE;
943 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
944 update_window_title (window);
946 return MODEST_WINDOW(window);
950 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
951 const gchar *modest_account_name,
952 const gchar *msg_uid)
955 ModestMsgViewWindowPrivate *priv;
956 ModestWindowMgr *mgr = NULL;
958 g_return_val_if_fail (msg, NULL);
959 mgr = modest_runtime_get_window_mgr ();
960 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
961 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
962 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
963 modest_account_name, msg_uid);
965 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
966 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
968 return MODEST_WINDOW(obj);
971 void modest_msg_view_window_on_row_changed(
972 GtkTreeModel *header_model,
975 ModestMsgViewWindow *window){
976 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
979 void modest_msg_view_window_on_row_deleted(
980 GtkTreeModel *header_model,
982 ModestMsgViewWindow *window){
983 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
986 /* On insertions we check if the folder still has the message we are
987 * showing or do not. If do not, we do nothing. Which means we are still
988 * not attached to any header folder and thus next/prev buttons are
989 * still dimmed. Once the message that is shown by msg-view is found, the
990 * new model of header-view will be attached and the references will be set.
991 * On each further insertions dimming rules will be checked. However
992 * this requires extra CPU time at least works.
993 * (An message might be deleted from TnyFolder and thus will not be
994 * inserted into the model again for example if it is removed by the
995 * imap server and the header view is refreshed.)
997 void modest_msg_view_window_on_row_inserted(
998 GtkTreeModel *new_model,
999 GtkTreePath *tree_path,
1000 GtkTreeIter *tree_iter,
1001 ModestMsgViewWindow *window){
1002 ModestMsgViewWindowPrivate *priv = NULL;
1003 TnyHeader *header = NULL;
1006 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1008 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1010 /* If we already has a model attached then the message shown by
1011 * msg-view is in it, and thus we do not need any actions but
1012 * to check the dimming rules.*/
1013 if(priv->header_model != NULL){
1014 gtk_tree_row_reference_free(priv->next_row_reference);
1015 priv->next_row_reference = gtk_tree_row_reference_copy(
1016 priv->row_reference);
1017 select_next_valid_row (priv->header_model,
1018 &(priv->next_row_reference), FALSE);
1019 modest_ui_actions_check_toolbar_dimming_rules (
1020 MODEST_WINDOW (window));
1024 /* Check if the newly inserted message is the same we are actually
1025 * showing. IF not, we should remain detached from the header model
1026 * and thus prev and next toolbarbuttons should remain dimmed. */
1027 gtk_tree_model_get (new_model, tree_iter,
1028 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1029 uid = modest_tny_folder_get_header_unique_id(header);
1030 g_object_unref(G_OBJECT(header));
1032 if(!g_str_equal(priv->msg_uid, uid)){
1038 /* Setup row_reference for the actual msg. */
1039 priv->row_reference = gtk_tree_row_reference_new(
1040 new_model, tree_path);
1041 if(priv->row_reference == NULL){
1042 g_warning("No reference for msg header item.");
1046 /* Attach new_model and connect some callback to it to become able
1047 * to detect changes in header-view. */
1048 priv->header_model = g_object_ref(new_model);
1049 g_signal_connect (new_model, "row-changed",
1050 G_CALLBACK (modest_msg_view_window_on_row_changed),
1052 g_signal_connect (new_model, "row-deleted",
1053 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1055 g_signal_connect (new_model, "rows-reordered",
1056 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1059 /* Now set up next_row_reference. */
1060 priv->next_row_reference = gtk_tree_row_reference_copy(
1061 priv->row_reference);
1062 select_next_valid_row (priv->header_model,
1063 &(priv->next_row_reference), FALSE);
1065 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1068 void modest_msg_view_window_on_row_reordered(
1069 GtkTreeModel *header_model,
1073 ModestMsgViewWindow *window){
1074 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1077 /* The modest_msg_view_window_update_model_replaced implements update
1078 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1079 * actually belongs to the header-view is the same as the TnyFolder of
1080 * the message of msg-view or not. If they are different, there is
1081 * nothing to do. If they are the same, then the model has replaced and
1082 * the reference in msg-view shall be replaced from the old model to
1083 * the new model. In this case the view will be detached from it's
1084 * header folder. From this point the next/prev buttons are dimmed.
1086 void modest_msg_view_window_update_model_replaced(
1087 ModestHeaderViewObserver *observer,
1088 GtkTreeModel *model,
1089 const gchar *tny_folder_id){
1090 ModestMsgViewWindowPrivate *priv = NULL;
1091 ModestMsgViewWindow *window = NULL;
1093 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1094 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1096 window = MODEST_MSG_VIEW_WINDOW(observer);
1097 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1099 /* If there is an other folder in the header-view then we do
1100 * not care about it's model (msg list). Else if the
1101 * header-view shows the folder the msg shown by us is in, we
1102 * shall replace our model reference and make some check. */
1103 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1106 /* Model is changed(replaced), so we should forget the old
1107 * one. Because there might be other references and there
1108 * might be some change on the model even if we unreferenced
1109 * it, we need to disconnect our signals here. */
1110 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1111 priv->row_changed_handler))
1112 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1113 priv->row_changed_handler);
1114 priv->row_changed_handler = 0;
1115 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1116 priv->row_deleted_handler))
1117 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1118 priv->row_deleted_handler);
1119 priv->row_deleted_handler = 0;
1120 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1121 priv->row_inserted_handler))
1122 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1123 priv->row_inserted_handler);
1124 priv->row_inserted_handler = 0;
1125 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1126 priv->rows_reordered_handler))
1127 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1128 priv->rows_reordered_handler);
1129 priv->rows_reordered_handler = 0;
1130 g_object_unref(priv->header_model);
1131 priv->header_model = NULL;
1132 g_object_unref(priv->row_reference);
1133 priv->row_reference = NULL;
1134 g_object_unref(priv->next_row_reference);
1135 priv->next_row_reference = NULL;
1137 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1139 g_assert(model != NULL);
1141 /* Also we must connect to the new model for row insertions.
1142 * Only for insertions now. We will need other ones only after
1143 * the msg is show by msg-view is added to the new model. */
1144 priv->row_inserted_handler = g_signal_connect (
1145 model, "row-inserted",
1146 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1151 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1153 ModestMsgViewWindowPrivate *priv= NULL;
1155 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1156 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1158 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1162 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1164 ModestMsgViewWindowPrivate *priv= NULL;
1166 TnyHeader *header = NULL;
1167 GtkTreePath *path = NULL;
1170 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1171 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1173 /* If the message was not obtained from a treemodel,
1174 * for instance if it was opened directly by the search UI:
1176 if (priv->header_model == NULL) {
1177 msg = modest_msg_view_window_get_message (self);
1179 header = tny_msg_get_header (msg);
1180 g_object_unref (msg);
1185 /* Get iter of the currently selected message in the header view: */
1186 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1187 * instead of sometimes retrieving it from the header view?
1188 * Then we wouldn't be dependent on the message actually still being selected
1189 * in the header view. murrayc. */
1190 if (!gtk_tree_row_reference_valid (priv->row_reference))
1192 path = gtk_tree_row_reference_get_path (priv->row_reference);
1193 g_return_val_if_fail (path != NULL, NULL);
1194 gtk_tree_model_get_iter (priv->header_model,
1198 /* Get current message header */
1199 gtk_tree_model_get (priv->header_model, &iter,
1200 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1203 gtk_tree_path_free (path);
1208 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1210 ModestMsgViewWindowPrivate *priv;
1212 g_return_val_if_fail (self, NULL);
1214 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1216 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1220 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1222 ModestMsgViewWindowPrivate *priv;
1224 g_return_val_if_fail (self, NULL);
1226 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1228 return (const gchar*) priv->msg_uid;
1232 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1235 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1236 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1237 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1241 is_active = gtk_toggle_action_get_active (toggle);
1244 gtk_widget_show (priv->find_toolbar);
1245 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1247 gtk_widget_hide (priv->find_toolbar);
1250 /* update the toggle buttons status */
1251 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1252 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1253 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1254 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1259 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1260 ModestMsgViewWindow *obj)
1262 GtkToggleAction *toggle;
1263 ModestWindowPrivate *parent_priv;
1264 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1266 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1267 gtk_toggle_action_set_active (toggle, FALSE);
1271 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1272 ModestMsgViewWindow *obj)
1274 gchar *current_search;
1275 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1277 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1278 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1282 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1284 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1285 g_free (current_search);
1286 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1290 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1292 g_free (priv->last_search);
1293 priv->last_search = g_strdup (current_search);
1294 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1297 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1298 g_free (priv->last_search);
1299 priv->last_search = NULL;
1301 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1304 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1305 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1306 g_free (priv->last_search);
1307 priv->last_search = NULL;
1309 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1313 g_free (current_search);
1318 modest_msg_view_window_set_zoom (ModestWindow *window,
1321 ModestMsgViewWindowPrivate *priv;
1322 ModestWindowPrivate *parent_priv;
1323 GtkAction *action = NULL;
1324 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1326 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1328 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1329 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1330 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1332 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1333 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1335 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1339 modest_msg_view_window_get_zoom (ModestWindow *window)
1341 ModestMsgViewWindowPrivate *priv;
1343 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1345 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1346 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1350 modest_msg_view_window_zoom_plus (ModestWindow *window)
1352 ModestWindowPrivate *parent_priv;
1353 GtkRadioAction *zoom_radio_action;
1354 GSList *group, *node;
1356 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1357 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1358 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1360 group = gtk_radio_action_get_group (zoom_radio_action);
1362 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1363 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1367 for (node = group; node != NULL; node = g_slist_next (node)) {
1368 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1369 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1377 modest_msg_view_window_zoom_minus (ModestWindow *window)
1379 ModestWindowPrivate *parent_priv;
1380 GtkRadioAction *zoom_radio_action;
1381 GSList *group, *node;
1383 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1384 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1385 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1387 group = gtk_radio_action_get_group (zoom_radio_action);
1389 for (node = group; node != NULL; node = g_slist_next (node)) {
1390 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1391 if (node->next != NULL) {
1392 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1395 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1405 modest_msg_view_window_key_event (GtkWidget *window,
1410 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1411 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1412 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1413 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1414 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1415 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1416 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1417 gboolean return_value;
1419 if (event->type == GDK_KEY_RELEASE) {
1420 GtkScrollType scroll_type;
1422 switch (event->keyval) {
1425 scroll_type = GTK_SCROLL_STEP_UP; break;
1428 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1430 case GDK_KP_Page_Up:
1431 scroll_type = GTK_SCROLL_PAGE_UP; break;
1433 case GDK_KP_Page_Down:
1434 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1437 scroll_type = GTK_SCROLL_START; break;
1440 scroll_type = GTK_SCROLL_END; break;
1441 default: scroll_type = GTK_SCROLL_NONE;
1444 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1445 scroll_type, FALSE, &return_value);
1456 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1459 ModestMsgViewWindowPrivate *priv;
1460 GtkTreeIter tmp_iter;
1461 gboolean is_last_selected;
1463 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1464 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1466 /*if no model (so no rows at all), then virtually we are the last*/
1467 if (!priv->header_model)
1470 path = gtk_tree_row_reference_get_path (priv->row_reference);
1474 is_last_selected = TRUE;
1475 while (is_last_selected) {
1477 gtk_tree_path_next (path);
1478 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1480 gtk_tree_model_get (priv->header_model, &tmp_iter,
1481 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1484 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1485 is_last_selected = FALSE;
1486 g_object_unref(G_OBJECT(header));
1489 gtk_tree_path_free (path);
1490 return is_last_selected;
1494 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1496 ModestMsgViewWindowPrivate *priv;
1498 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1499 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1501 return priv->header_model != NULL;
1505 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1507 ModestMsgViewWindowPrivate *priv;
1509 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1510 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1512 return priv->is_search_result;
1516 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1519 ModestMsgViewWindowPrivate *priv;
1520 gboolean is_first_selected;
1521 GtkTreeIter tmp_iter;
1522 /* gchar * path_string;*/
1524 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1525 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1527 /*if no model (so no rows at all), then virtually we are the first*/
1528 if (!priv->header_model)
1531 path = gtk_tree_row_reference_get_path (priv->row_reference);
1535 /* path_string = gtk_tree_path_to_string (path);
1536 is_first_selected = strcmp (path_string, "0");
1538 g_free (path_string);
1539 gtk_tree_path_free (path);
1541 return is_first_selected;*/
1543 is_first_selected = TRUE;
1544 while (is_first_selected) {
1546 if(!gtk_tree_path_prev (path))
1548 /* Here the 'if' is needless for logic, but let make sure
1549 * iter is valid for gtk_tree_model_get. */
1550 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1552 gtk_tree_model_get (priv->header_model, &tmp_iter,
1553 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1556 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1557 is_first_selected = FALSE;
1558 g_object_unref(G_OBJECT(header));
1561 gtk_tree_path_free (path);
1562 return is_first_selected;
1566 * Reads the message whose summary item is @header. It takes care of
1567 * several things, among others:
1569 * If the message was not previously downloaded then ask the user
1570 * before downloading. If there is no connection launch the connection
1571 * dialog. Update toolbar dimming rules.
1573 * Returns: TRUE if the mail operation was started, otherwise if the
1574 * user do not want to download the message, or if the user do not
1575 * want to connect, then the operation is not issued
1578 message_reader (ModestMsgViewWindow *window,
1579 ModestMsgViewWindowPrivate *priv,
1581 GtkTreeRowReference *row_reference)
1583 ModestMailOperation *mail_op = NULL;
1584 ModestMailOperationTypeOperation op_type;
1585 gboolean already_showing = FALSE;
1586 ModestWindow *msg_window = NULL;
1587 ModestWindowMgr *mgr;
1589 g_return_val_if_fail (row_reference != NULL, FALSE);
1591 mgr = modest_runtime_get_window_mgr ();
1592 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1593 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1596 gtk_window_present (GTK_WINDOW (msg_window));
1597 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1601 /* Msg download completed */
1602 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1603 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1605 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1607 /* Ask the user if he wants to download the message if
1609 if (!tny_device_is_online (modest_runtime_get_device())) {
1610 TnyFolder *folder = NULL;
1611 GtkResponseType response;
1613 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1614 _("mcen_nc_get_msg"));
1615 if (response == GTK_RESPONSE_CANCEL)
1618 /* Offer the connection dialog if necessary */
1619 folder = tny_header_get_folder (header);
1621 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1622 TNY_FOLDER_STORE (folder))) {
1623 g_object_unref (folder);
1626 g_object_unref (folder);
1631 /* New mail operation */
1632 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1633 modest_ui_actions_get_msgs_full_error_handler,
1636 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1637 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1638 g_object_unref (mail_op);
1640 /* Update toolbar dimming rules */
1641 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1647 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1649 ModestMsgViewWindowPrivate *priv;
1650 GtkTreePath *path= NULL;
1651 GtkTreeIter tmp_iter;
1653 gboolean retval = TRUE;
1654 GtkTreeRowReference *row_reference = NULL;
1656 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1657 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1659 /* Update the next row reference if it's not valid. This could
1660 happen if for example the header which it was pointing to,
1661 was deleted. The best place to do it is in the row-deleted
1662 handler but the tinymail model do not work like the glib
1663 tree models and reports the deletion when the row is still
1665 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1666 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1667 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1668 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1671 if (priv->next_row_reference)
1672 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1676 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1678 gtk_tree_model_get_iter (priv->header_model,
1681 gtk_tree_path_free (path);
1683 gtk_tree_model_get (priv->header_model, &tmp_iter,
1684 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1687 /* Read the message & show it */
1688 if (!message_reader (window, priv, header, row_reference)) {
1690 gtk_tree_row_reference_free (row_reference);
1694 g_object_unref (header);
1700 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1702 ModestMsgViewWindowPrivate *priv = NULL;
1703 TnyHeader *header = NULL;
1705 GtkTreePath *path = NULL;
1706 GtkTreeRowReference *row_reference = NULL;
1708 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1709 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1711 /* Check that the model is not empty */
1712 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1715 /* Get the header */
1716 gtk_tree_model_get (priv->header_model,
1718 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1720 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1721 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1722 g_object_unref (header);
1723 return modest_msg_view_window_select_next_message (self);
1726 path = gtk_tree_model_get_path (priv->header_model, &iter);
1727 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1728 gtk_tree_path_free (path);
1730 /* Read the message & show it */
1731 message_reader (self, priv, header, row_reference);
1734 g_object_unref (header);
1740 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1742 ModestMsgViewWindowPrivate *priv = NULL;
1744 GtkTreeRowReference *row_reference = NULL;
1746 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1747 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1749 /* Return inmediatly if there is no header model */
1750 if (!priv->header_model)
1753 path = gtk_tree_row_reference_get_path (priv->row_reference);
1754 while (gtk_tree_path_prev (path)) {
1758 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1759 gtk_tree_model_get (priv->header_model, &iter,
1760 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1764 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1765 g_object_unref (header);
1769 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1770 /* Read the message & show it */
1771 if (!message_reader (window, priv, header, row_reference)) {
1772 gtk_tree_row_reference_free (row_reference);
1773 g_object_unref (header);
1777 gtk_tree_path_free (path);
1778 g_object_unref (header);
1783 gtk_tree_path_free (path);
1788 view_msg_cb (ModestMailOperation *mail_op,
1795 ModestMsgViewWindow *self = NULL;
1796 ModestMsgViewWindowPrivate *priv = NULL;
1797 GtkTreeRowReference *row_reference = NULL;
1799 /* If there was any error */
1800 row_reference = (GtkTreeRowReference *) user_data;
1801 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1802 gtk_tree_row_reference_free (row_reference);
1806 /* Get the window */
1807 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1808 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1809 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1811 /* Update the row reference */
1812 gtk_tree_row_reference_free (priv->row_reference);
1813 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1814 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1815 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1816 gtk_tree_row_reference_free (row_reference);
1818 /* Mark header as read */
1819 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1820 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1822 /* Set new message */
1823 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1824 modest_msg_view_window_update_priority (self);
1825 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1826 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1828 /* Set the new message uid of the window */
1829 if (priv->msg_uid) {
1830 g_free (priv->msg_uid);
1831 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1834 /* Notify the observers */
1835 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1836 0, priv->header_model, priv->row_reference);
1838 /* Free new references */
1839 g_object_unref (self);
1843 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1845 ModestMsgViewWindowPrivate *priv;
1847 TnyFolderType folder_type;
1849 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1851 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1853 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1857 folder = tny_msg_get_folder (msg);
1859 folder_type = tny_folder_get_folder_type (folder);
1860 g_object_unref (folder);
1862 g_object_unref (msg);
1870 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1872 ModestMsgViewWindowPrivate *priv;
1873 TnyHeaderFlags flags = 0;
1875 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1877 if (priv->header_model) {
1880 GtkTreePath *path = NULL;
1882 path = gtk_tree_row_reference_get_path (priv->row_reference);
1883 g_return_if_fail (path != NULL);
1884 gtk_tree_model_get_iter (priv->header_model,
1886 gtk_tree_row_reference_get_path (priv->row_reference));
1888 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1891 flags = tny_header_get_flags (header);
1892 g_object_unref(G_OBJECT(header));
1894 gtk_tree_path_free (path);
1897 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1902 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1904 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1905 ModestWindowPrivate *parent_priv;
1906 ModestWindowMgr *mgr;
1907 gboolean is_fullscreen;
1908 GtkAction *fs_toggle_action;
1911 mgr = modest_runtime_get_window_mgr ();
1912 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1914 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1916 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1917 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1918 if (is_fullscreen != active) {
1919 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1928 set_homogeneous (GtkWidget *widget,
1931 if (GTK_IS_TOOL_ITEM (widget)) {
1932 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1933 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1938 modest_msg_view_window_show_toolbar (ModestWindow *self,
1939 gboolean show_toolbar)
1941 ModestMsgViewWindowPrivate *priv = NULL;
1942 ModestWindowPrivate *parent_priv;
1943 GtkWidget *reply_button = NULL, *menu = NULL;
1944 GtkWidget *placeholder = NULL;
1946 const gchar *action_name;
1949 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1950 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1952 /* Set optimized view status */
1953 priv->optimized_view = !show_toolbar;
1955 if (!parent_priv->toolbar) {
1956 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1958 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1960 /* Set homogeneous toolbar */
1961 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1962 set_homogeneous, NULL);
1964 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1965 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1966 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1967 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1968 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1969 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1970 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1971 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1973 /* Add ProgressBar (Transfer toolbar) */
1974 priv->progress_bar = modest_progress_bar_widget_new ();
1975 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1976 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1977 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1978 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1979 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1981 /* Connect cancel 'clicked' signal to abort progress mode */
1982 g_signal_connect(priv->cancel_toolitem, "clicked",
1983 G_CALLBACK(cancel_progressbar),
1986 /* Add it to the observers list */
1987 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1990 hildon_window_add_toolbar (HILDON_WINDOW (self),
1991 GTK_TOOLBAR (parent_priv->toolbar));
1994 /* Set reply button tap and hold menu */
1995 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1996 "/ToolBar/ToolbarMessageReply");
1997 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1998 "/ToolbarReplyCSM");
1999 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2003 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2004 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2005 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2007 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2008 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2009 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2011 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2014 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2015 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2018 /* Update also the actions (to update the toggles in the
2019 menus), we have to do it manually because some other window
2020 of the same time could have changed it (remember that the
2021 toolbar fullscreen mode is shared by all the windows of the
2023 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2024 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2026 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2028 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2029 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2034 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2036 ModestMsgViewWindow *window)
2038 if (!GTK_WIDGET_VISIBLE (window))
2041 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2045 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2047 ModestMsgViewWindowPrivate *priv;
2049 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2050 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2052 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2056 cancel_progressbar (GtkToolButton *toolbutton,
2057 ModestMsgViewWindow *self)
2060 ModestMsgViewWindowPrivate *priv;
2062 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2064 /* Get operation observers and cancel its current operation */
2065 tmp = priv->progress_widgets;
2067 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2068 tmp=g_slist_next(tmp);
2072 observers_empty (ModestMsgViewWindow *self)
2075 ModestMsgViewWindowPrivate *priv;
2076 gboolean is_empty = TRUE;
2077 guint pending_ops = 0;
2079 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2080 tmp = priv->progress_widgets;
2082 /* Check all observers */
2083 while (tmp && is_empty) {
2084 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2085 is_empty = pending_ops == 0;
2087 tmp = g_slist_next(tmp);
2094 on_account_removed (TnyAccountStore *account_store,
2095 TnyAccount *account,
2098 /* Do nothing if it's a transport account, because we only
2099 show the messages of a store account */
2100 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2101 const gchar *parent_acc = NULL;
2102 const gchar *our_acc = NULL;
2104 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2105 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2107 /* Close this window if I'm showing a message of the removed account */
2108 if (strcmp (parent_acc, our_acc) == 0)
2109 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2114 on_queue_changed (ModestMailOperationQueue *queue,
2115 ModestMailOperation *mail_op,
2116 ModestMailOperationQueueNotification type,
2117 ModestMsgViewWindow *self)
2120 ModestMsgViewWindowPrivate *priv;
2121 ModestMailOperationTypeOperation op_type;
2122 ModestToolBarModes mode;
2124 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2125 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2127 /* If this operations was created by another window, do nothing */
2128 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2131 /* Get toolbar mode from operation id*/
2132 op_type = modest_mail_operation_get_type_operation (mail_op);
2134 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2135 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2136 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2137 mode = TOOLBAR_MODE_TRANSFER;
2140 mode = TOOLBAR_MODE_NORMAL;
2144 /* Add operation observers and change toolbar if neccessary*/
2145 tmp = priv->progress_widgets;
2147 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2148 if (mode == TOOLBAR_MODE_TRANSFER) {
2149 /* Enable transfer toolbar mode */
2150 set_toolbar_transfer_mode(self);
2152 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2154 tmp = g_slist_next (tmp);
2159 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2160 if (mode == TOOLBAR_MODE_TRANSFER) {
2162 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2164 tmp = g_slist_next (tmp);
2168 /* If no more operations are being observed, NORMAL mode is enabled again */
2169 if (observers_empty (self)) {
2170 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2178 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2180 ModestMsgViewWindowPrivate *priv;
2181 GList *selected_attachments = NULL;
2183 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2184 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2186 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2188 return selected_attachments;
2192 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2194 ModestMsgViewWindowPrivate *priv;
2195 const gchar *msg_uid;
2196 gchar *attachment_uid = NULL;
2197 gint attachment_index = 0;
2200 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2201 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2202 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2204 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2205 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2206 attachment_index = g_list_index (attachments, mime_part);
2207 g_list_free (attachments);
2209 if (msg_uid && attachment_index >= 0) {
2210 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2213 if (mime_part == NULL) {
2214 gboolean error = FALSE;
2215 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2216 if (selected_attachments == NULL) {
2218 } else if (g_list_length (selected_attachments) > 1) {
2219 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2222 mime_part = (TnyMimePart *) selected_attachments->data;
2223 g_object_ref (mime_part);
2225 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2226 g_list_free (selected_attachments);
2231 g_object_ref (mime_part);
2234 if (tny_mime_part_is_purged (mime_part)) {
2235 g_object_unref (mime_part);
2239 if (!TNY_IS_MSG (mime_part)) {
2240 gchar *filepath = NULL;
2241 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2242 TnyFsStream *temp_stream = NULL;
2243 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid,
2247 const gchar *content_type;
2248 content_type = tny_mime_part_get_content_type (mime_part);
2249 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2251 /* make the file read-only */
2252 if (g_chmod(filepath, 0444) != 0)
2253 g_warning ("%s: failed to set file '%s' to read-only: %s",
2254 __FUNCTION__, filepath, strerror(errno));
2256 modest_platform_activate_file (filepath, content_type);
2257 g_object_unref (temp_stream);
2259 /* NOTE: files in the temporary area will be automatically
2260 * cleaned after some time if they are no longer in use */
2263 /* message attachment */
2264 TnyHeader *header = NULL;
2265 ModestWindowMgr *mgr;
2266 ModestWindow *msg_win = NULL;
2269 header = tny_msg_get_header (TNY_MSG (mime_part));
2270 mgr = modest_runtime_get_window_mgr ();
2271 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2274 if (msg_win) /* there is already a window for this uid; top it */
2275 gtk_window_present (GTK_WINDOW(msg_win));
2277 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2278 * thus, we don't do anything */
2279 g_warning ("window for is already being created");
2281 /* it's not found, so create a new window for it */
2282 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2283 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2285 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2286 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2287 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2288 modest_window_get_zoom (MODEST_WINDOW (window)));
2289 modest_window_mgr_register_window (mgr, msg_win);
2290 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2291 gtk_widget_show_all (GTK_WIDGET (msg_win));
2294 g_object_unref (mime_part);
2310 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2311 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2312 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2313 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2316 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2320 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2321 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2322 g_free (pair->filename);
2323 g_object_unref (pair->part);
2324 g_slice_free (SaveMimePartPair, pair);
2326 g_list_free (info->pairs);
2329 gtk_widget_destroy (info->banner);
2330 g_object_unref (info->banner);
2331 g_slice_free (SaveMimePartInfo, info);
2336 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2338 if (info->pairs != NULL) {
2339 save_mime_part_to_file (info);
2342 result = info->result;
2344 /* This is a GDK lock because we are an idle callback and
2345 * hildon_banner_show_information is or does Gtk+ code */
2347 gdk_threads_enter (); /* CHECKED */
2348 save_mime_part_info_free (info, TRUE);
2350 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2352 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2354 gdk_threads_leave (); /* CHECKED */
2361 save_mime_part_to_file (SaveMimePartInfo *info)
2363 GnomeVFSResult result;
2364 GnomeVFSHandle *handle;
2366 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2368 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2369 if (result == GNOME_VFS_OK) {
2370 stream = tny_vfs_stream_new (handle);
2371 tny_mime_part_decode_to_stream (pair->part, stream);
2372 g_object_unref (G_OBJECT (stream));
2373 g_object_unref (pair->part);
2374 g_slice_free (SaveMimePartPair, pair);
2375 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2376 info->result = TRUE;
2378 save_mime_part_info_free (info, FALSE);
2379 info->result = FALSE;
2382 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2387 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2389 gboolean is_ok = TRUE;
2390 gint replaced_files = 0;
2391 const GList *files = info->pairs;
2394 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2395 SaveMimePartPair *pair = iter->data;
2396 if (modest_maemo_utils_file_exists (pair->filename)) {
2400 if (replaced_files) {
2401 GtkWidget *confirm_overwrite_dialog;
2402 const gchar *message = (replaced_files == 1) ?
2403 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2404 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2405 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2408 gtk_widget_destroy (confirm_overwrite_dialog);
2412 save_mime_part_info_free (info, TRUE);
2414 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2415 _CS("sfil_ib_saving"));
2416 info->banner = g_object_ref (banner);
2417 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2418 g_object_unref (banner);
2425 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2427 gboolean clean_list = FALSE;
2428 ModestMsgViewWindowPrivate *priv;
2429 GList *files_to_save = NULL;
2430 GtkWidget *save_dialog = NULL;
2431 gchar *folder = NULL;
2432 gboolean canceled = FALSE;
2433 const gchar *filename = NULL;
2434 gchar *save_multiple_str = NULL;
2436 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2437 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2439 if (mime_parts == NULL) {
2440 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2441 if (mime_parts == NULL)
2446 /* prepare dialog */
2447 if (mime_parts->next == NULL) {
2448 /* only one attachment selected */
2449 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2450 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2451 filename = tny_mime_part_get_filename (mime_part);
2453 g_warning ("Tried to save a non-file attachment");
2457 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2458 g_list_length (mime_parts));
2461 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2462 GTK_FILE_CHOOSER_ACTION_SAVE);
2465 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2466 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2470 if (filename != NULL)
2471 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2474 /* if multiple, set multiple string */
2475 if (save_multiple_str) {
2476 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2480 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2481 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2483 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2484 hildon_banner_show_information
2485 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2489 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2490 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2492 if (tny_mime_part_is_attachment (mime_part)) {
2493 SaveMimePartPair *pair;
2495 if ((mime_parts->next != NULL) &&
2496 (tny_mime_part_get_filename (mime_part) == NULL))
2499 pair = g_slice_new0 (SaveMimePartPair);
2500 if (mime_parts->next == NULL) {
2501 pair->filename = g_strdup (chooser_uri);
2504 g_build_filename (chooser_uri,
2505 tny_mime_part_get_filename (mime_part), NULL);
2507 pair->part = g_object_ref (mime_part);
2508 files_to_save = g_list_prepend (files_to_save, pair);
2512 g_free (chooser_uri);
2515 gtk_widget_destroy (save_dialog);
2518 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2519 g_list_free (mime_parts);
2522 if (files_to_save != NULL) {
2523 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2524 info->pairs = files_to_save;
2525 info->result = TRUE;
2526 save_mime_parts_to_file_with_checks (info);
2531 show_remove_attachment_information (gpointer userdata)
2533 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2534 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2536 /* We're outside the main lock */
2537 gdk_threads_enter ();
2539 if (priv->remove_attachment_banner != NULL) {
2540 gtk_widget_destroy (priv->remove_attachment_banner);
2541 g_object_unref (priv->remove_attachment_banner);
2544 priv->remove_attachment_banner = g_object_ref (
2545 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2547 gdk_threads_leave ();
2553 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2555 ModestMsgViewWindowPrivate *priv;
2556 GList *mime_parts = NULL, *node;
2557 gchar *confirmation_message;
2561 /* TnyFolder *folder; */
2563 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2564 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2567 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2569 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2571 /* Remove already purged messages from mime parts list */
2573 while (node != NULL) {
2574 TnyMimePart *part = TNY_MIME_PART (node->data);
2575 if (tny_mime_part_is_purged (part)) {
2576 GList *deleted_node = node;
2577 node = g_list_next (node);
2578 g_object_unref (part);
2579 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2581 node = g_list_next (node);
2585 if (mime_parts == NULL)
2588 n_attachments = g_list_length (mime_parts);
2589 if (n_attachments == 1) {
2590 const gchar *filename;
2592 if (TNY_IS_MSG (mime_parts->data)) {
2594 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2595 filename = tny_header_get_subject (header);
2596 g_object_unref (header);
2597 if (filename == NULL)
2598 filename = _("mail_va_no_subject");
2600 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2602 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2604 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2605 "mcen_nc_purge_files_text",
2606 n_attachments), n_attachments);
2608 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2609 confirmation_message);
2610 g_free (confirmation_message);
2612 if (response != GTK_RESPONSE_OK)
2615 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2616 /* folder = tny_msg_get_folder (msg); */
2617 /* tny_msg_uncache_attachments (msg); */
2618 /* tny_folder_refresh (folder, NULL); */
2619 /* g_object_unref (folder); */
2621 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2622 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2623 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2626 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2627 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2628 tny_msg_rewrite_cache (msg);
2629 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2631 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2632 g_list_free (mime_parts);
2634 if (priv->purge_timeout > 0) {
2635 g_source_remove (priv->purge_timeout);
2636 priv->purge_timeout = 0;
2639 if (priv->remove_attachment_banner) {
2640 gtk_widget_destroy (priv->remove_attachment_banner);
2641 g_object_unref (priv->remove_attachment_banner);
2642 priv->remove_attachment_banner = NULL;
2650 update_window_title (ModestMsgViewWindow *window)
2652 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2654 TnyHeader *header = NULL;
2655 const gchar *subject = NULL;
2657 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2660 header = tny_msg_get_header (msg);
2661 subject = tny_header_get_subject (header);
2662 g_object_unref (msg);
2665 if ((subject == NULL)||(subject[0] == '\0'))
2666 subject = _("mail_va_no_subject");
2668 gtk_window_set_title (GTK_WINDOW (window), subject);
2672 static void on_move_focus (GtkWidget *widget,
2673 GtkDirectionType direction,
2676 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");