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;
229 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
230 MODEST_TYPE_MSG_VIEW_WINDOW, \
231 ModestMsgViewWindowPrivate))
233 static GtkWindowClass *parent_class = NULL;
235 /* uncomment the following if you have defined any signals */
236 static guint signals[LAST_SIGNAL] = {0};
239 modest_msg_view_window_get_type (void)
241 static GType my_type = 0;
243 static const GTypeInfo my_info = {
244 sizeof(ModestMsgViewWindowClass),
245 NULL, /* base init */
246 NULL, /* base finalize */
247 (GClassInitFunc) modest_msg_view_window_class_init,
248 NULL, /* class finalize */
249 NULL, /* class data */
250 sizeof(ModestMsgViewWindow),
252 (GInstanceInitFunc) modest_msg_view_window_init,
255 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
256 "ModestMsgViewWindow",
259 static const GInterfaceInfo modest_header_view_observer_info =
261 (GInterfaceInitFunc) modest_header_view_observer_init,
262 NULL, /* interface_finalize */
263 NULL /* interface_data */
266 g_type_add_interface_static (my_type,
267 MODEST_TYPE_HEADER_VIEW_OBSERVER,
268 &modest_header_view_observer_info);
274 save_state (ModestWindow *self)
276 modest_widget_memory_save (modest_runtime_get_conf (),
278 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
283 restore_settings (ModestMsgViewWindow *self)
286 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
289 conf = modest_runtime_get_conf ();
290 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
291 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
292 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
293 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
294 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
295 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
296 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
297 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
298 modest_widget_memory_restore (conf,
300 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
304 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
306 GObjectClass *gobject_class;
307 ModestWindowClass *modest_window_class;
308 gobject_class = (GObjectClass*) klass;
309 modest_window_class = (ModestWindowClass *) klass;
311 parent_class = g_type_class_peek_parent (klass);
312 gobject_class->finalize = modest_msg_view_window_finalize;
314 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
315 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
316 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
317 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
318 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
319 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
321 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
323 modest_window_class->save_state_func = save_state;
325 signals[MSG_CHANGED_SIGNAL] =
326 g_signal_new ("msg-changed",
327 G_TYPE_FROM_CLASS (gobject_class),
329 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
331 modest_marshal_VOID__POINTER_POINTER,
332 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
335 static void modest_header_view_observer_init(
336 ModestHeaderViewObserverIface *iface_class)
338 iface_class->update_func = modest_msg_view_window_update_model_replaced;
342 modest_msg_view_window_init (ModestMsgViewWindow *obj)
344 ModestMsgViewWindowPrivate *priv;
345 ModestWindowPrivate *parent_priv = NULL;
346 GtkActionGroup *action_group = NULL;
347 GError *error = NULL;
348 GdkPixbuf *window_icon;
350 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
351 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
352 parent_priv->ui_manager = gtk_ui_manager_new();
354 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
355 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
357 /* Add common actions */
358 gtk_action_group_add_actions (action_group,
359 modest_action_entries,
360 G_N_ELEMENTS (modest_action_entries),
362 gtk_action_group_add_toggle_actions (action_group,
363 modest_toggle_action_entries,
364 G_N_ELEMENTS (modest_toggle_action_entries),
366 gtk_action_group_add_toggle_actions (action_group,
367 msg_view_toggle_action_entries,
368 G_N_ELEMENTS (msg_view_toggle_action_entries),
370 gtk_action_group_add_radio_actions (action_group,
371 msg_view_zoom_action_entries,
372 G_N_ELEMENTS (msg_view_zoom_action_entries),
374 G_CALLBACK (modest_ui_actions_on_change_zoom),
377 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
378 g_object_unref (action_group);
380 /* Load the UI definition */
381 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
384 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
385 g_error_free (error);
390 /* Add accelerators */
391 gtk_window_add_accel_group (GTK_WINDOW (obj),
392 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
394 priv->is_search_result = FALSE;
396 priv->msg_view = NULL;
397 priv->header_model = NULL;
398 priv->header_folder_id = NULL;
399 priv->clipboard_change_handler = 0;
400 priv->queue_change_handler = 0;
401 priv->account_removed_handler = 0;
402 priv->row_changed_handler = 0;
403 priv->row_deleted_handler = 0;
404 priv->row_inserted_handler = 0;
405 priv->rows_reordered_handler = 0;
406 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
408 priv->optimized_view = FALSE;
409 priv->progress_bar_timeout = 0;
410 priv->purge_timeout = 0;
411 priv->remove_attachment_banner = NULL;
412 priv->msg_uid = NULL;
414 priv->sighandlers = NULL;
417 init_window (MODEST_MSG_VIEW_WINDOW(obj));
418 /* Set window icon */
419 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
421 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
422 g_object_unref (window_icon);
426 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
427 GTK_WINDOW(obj),"applications_email_viewer");
432 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
434 ModestMsgViewWindowPrivate *priv = NULL;
436 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
438 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
440 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
442 if (priv->progress_bar_timeout > 0) {
443 g_source_remove (priv->progress_bar_timeout);
444 priv->progress_bar_timeout = 0;
451 set_toolbar_mode (ModestMsgViewWindow *self,
452 ModestToolBarModes mode)
454 ModestWindowPrivate *parent_priv;
455 ModestMsgViewWindowPrivate *priv;
456 /* GtkWidget *widget = NULL; */
458 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
460 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
461 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
463 /* Sets current toolbar mode */
464 priv->current_toolbar_mode = mode;
466 /* Update toolbar dimming state */
467 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
470 case TOOLBAR_MODE_NORMAL:
471 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
472 /* gtk_action_set_sensitive (widget, TRUE); */
473 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
474 /* gtk_action_set_sensitive (widget, TRUE); */
475 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
476 /* gtk_action_set_sensitive (widget, TRUE); */
477 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
478 /* gtk_action_set_sensitive (widget, TRUE); */
480 if (priv->prev_toolitem)
481 gtk_widget_show (priv->prev_toolitem);
483 if (priv->next_toolitem)
484 gtk_widget_show (priv->next_toolitem);
486 if (priv->progress_toolitem)
487 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
488 if (priv->progress_bar)
489 gtk_widget_hide (priv->progress_bar);
491 if (priv->cancel_toolitem)
492 gtk_widget_hide (priv->cancel_toolitem);
494 /* Hide toolbar if optimized view is enabled */
495 if (priv->optimized_view) {
496 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
497 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
501 case TOOLBAR_MODE_TRANSFER:
502 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
503 /* gtk_action_set_sensitive (widget, FALSE); */
504 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
505 /* gtk_action_set_sensitive (widget, FALSE); */
506 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
507 /* gtk_action_set_sensitive (widget, FALSE); */
508 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
509 /* gtk_action_set_sensitive (widget, FALSE); */
511 if (priv->prev_toolitem)
512 gtk_widget_hide (priv->prev_toolitem);
514 if (priv->next_toolitem)
515 gtk_widget_hide (priv->next_toolitem);
517 if (priv->progress_bar)
518 gtk_widget_show (priv->progress_bar);
520 if (priv->progress_toolitem) {
521 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
522 gtk_widget_show (priv->progress_toolitem);
525 if (priv->cancel_toolitem)
526 gtk_widget_show (priv->cancel_toolitem);
528 /* Show toolbar if it's hiden (optimized view ) */
529 if (priv->optimized_view) {
530 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
531 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
536 g_return_if_reached ();
543 menubar_to_menu (GtkUIManager *ui_manager)
545 GtkWidget *main_menu;
547 /* Get the menubar from the UI manager */
548 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
554 init_window (ModestMsgViewWindow *obj)
556 GtkWidget *main_vbox;
557 ModestMsgViewWindowPrivate *priv;
558 ModestWindowPrivate *parent_priv;
560 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
561 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
563 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
564 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
565 main_vbox = gtk_vbox_new (FALSE, 6);
567 #ifdef MODEST_USE_MOZEMBED
568 priv->main_scroll = priv->msg_view;
569 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
571 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
572 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
574 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
575 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
576 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
578 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
579 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
581 priv->find_toolbar = hildon_find_toolbar_new (NULL);
582 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
583 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
585 gtk_widget_show_all (GTK_WIDGET(main_vbox));
589 modest_msg_view_window_disconnect_signals (ModestWindow *self)
591 ModestMsgViewWindowPrivate *priv;
592 ModestHeaderView *header_view = NULL;
593 ModestWindow *main_window = NULL;
595 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
597 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
598 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
599 priv->clipboard_change_handler))
600 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
601 priv->clipboard_change_handler);
603 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
604 priv->queue_change_handler))
605 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
606 priv->queue_change_handler);
608 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
609 priv->account_removed_handler))
610 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
611 priv->account_removed_handler);
613 if (priv->header_model) {
614 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
615 priv->row_changed_handler))
616 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
617 priv->row_changed_handler);
619 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
620 priv->row_deleted_handler))
621 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
622 priv->row_deleted_handler);
624 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
625 priv->row_inserted_handler))
626 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
627 priv->row_inserted_handler);
629 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
630 priv->rows_reordered_handler))
631 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
632 priv->rows_reordered_handler);
635 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
636 priv->sighandlers = NULL;
638 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
639 FALSE); /* don't create */
643 header_view = MODEST_HEADER_VIEW(
644 modest_main_window_get_child_widget(
645 MODEST_MAIN_WINDOW(main_window),
646 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
647 if (header_view == NULL)
650 modest_header_view_remove_observer(header_view,
651 MODEST_HEADER_VIEW_OBSERVER(self));
655 modest_msg_view_window_finalize (GObject *obj)
657 ModestMsgViewWindowPrivate *priv;
659 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
661 /* Sanity check: shouldn't be needed, the window mgr should
662 call this function before */
663 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
665 if (priv->header_model != NULL) {
666 g_object_unref (priv->header_model);
667 priv->header_model = NULL;
670 if (priv->progress_bar_timeout > 0) {
671 g_source_remove (priv->progress_bar_timeout);
672 priv->progress_bar_timeout = 0;
675 if (priv->remove_attachment_banner) {
676 gtk_widget_destroy (priv->remove_attachment_banner);
677 g_object_unref (priv->remove_attachment_banner);
678 priv->remove_attachment_banner = NULL;
681 if (priv->purge_timeout > 0) {
682 g_source_remove (priv->purge_timeout);
683 priv->purge_timeout = 0;
686 if (priv->row_reference) {
687 gtk_tree_row_reference_free (priv->row_reference);
688 priv->row_reference = NULL;
691 if (priv->next_row_reference) {
692 gtk_tree_row_reference_free (priv->next_row_reference);
693 priv->next_row_reference = NULL;
697 g_free (priv->msg_uid);
698 priv->msg_uid = NULL;
701 G_OBJECT_CLASS(parent_class)->finalize (obj);
705 select_next_valid_row (GtkTreeModel *model,
706 GtkTreeRowReference **row_reference,
709 GtkTreeIter tmp_iter;
710 GtkTreePath *path, *next;
711 gboolean retval = FALSE;
713 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
715 path = gtk_tree_row_reference_get_path (*row_reference);
716 gtk_tree_model_get_iter (model, &tmp_iter, path);
717 gtk_tree_row_reference_free (*row_reference);
718 *row_reference = NULL;
720 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
721 next = gtk_tree_model_get_path (model, &tmp_iter);
722 *row_reference = gtk_tree_row_reference_new (model, next);
724 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
725 next = gtk_tree_model_get_path (model, &tmp_iter);
727 /* Ensure that we are not selecting the same */
728 if (gtk_tree_path_compare (path, next) != 0) {
729 *row_reference = gtk_tree_row_reference_new (model, next);
735 gtk_tree_path_free (path);
740 /* TODO: This should be in _init(), with the parameters as properties. */
742 modest_msg_view_window_construct (ModestMsgViewWindow *self,
743 const gchar *modest_account_name,
744 const gchar *msg_uid)
747 ModestMsgViewWindowPrivate *priv = NULL;
748 ModestWindowPrivate *parent_priv = NULL;
749 ModestDimmingRulesGroup *menu_rules_group = NULL;
750 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
751 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
753 obj = G_OBJECT (self);
754 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
755 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
757 priv->msg_uid = g_strdup (msg_uid);
760 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
761 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
762 gtk_widget_show (parent_priv->menubar);
763 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
765 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
766 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
767 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
769 /* Add common dimming rules */
770 modest_dimming_rules_group_add_rules (menu_rules_group,
771 modest_msg_view_menu_dimming_entries,
772 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
773 MODEST_WINDOW (self));
774 modest_dimming_rules_group_add_rules (toolbar_rules_group,
775 modest_msg_view_toolbar_dimming_entries,
776 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
777 MODEST_WINDOW (self));
778 modest_dimming_rules_group_add_rules (clipboard_rules_group,
779 modest_msg_view_clipboard_dimming_entries,
780 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
781 MODEST_WINDOW (self));
783 /* Insert dimming rules group for this window */
784 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
785 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
786 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
787 g_object_unref (menu_rules_group);
788 g_object_unref (toolbar_rules_group);
789 g_object_unref (clipboard_rules_group);
791 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
793 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
795 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);
796 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
797 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
798 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
799 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
800 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
801 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
802 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
803 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
804 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
805 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
807 g_signal_connect (G_OBJECT (obj), "key-release-event",
808 G_CALLBACK (modest_msg_view_window_key_event),
811 g_signal_connect (G_OBJECT (obj), "key-press-event",
812 G_CALLBACK (modest_msg_view_window_key_event),
815 g_signal_connect (G_OBJECT (obj), "window-state-event",
816 G_CALLBACK (modest_msg_view_window_window_state_event),
819 g_signal_connect (G_OBJECT (obj), "move-focus",
820 G_CALLBACK (on_move_focus), obj);
822 /* Mail Operation Queue */
823 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
825 G_CALLBACK (on_queue_changed),
828 /* Account manager */
829 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
831 G_CALLBACK(on_account_removed),
834 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
836 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
837 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
838 priv->last_search = NULL;
840 /* Init the clipboard actions dim status */
841 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
843 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
845 /* Check toolbar dimming rules */
846 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
847 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
851 /* FIXME: parameter checks */
853 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
854 const gchar *modest_account_name,
855 const gchar *msg_uid,
857 GtkTreeRowReference *row_reference)
859 ModestMsgViewWindow *window = NULL;
860 ModestMsgViewWindowPrivate *priv = NULL;
861 TnyFolder *header_folder = NULL;
862 ModestHeaderView *header_view = NULL;
863 ModestWindow *main_window = NULL;
864 ModestWindowMgr *mgr = NULL;
866 mgr = modest_runtime_get_window_mgr ();
867 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
868 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
870 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
872 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
874 /* Remember the message list's TreeModel so we can detect changes
875 * and change the list selection when necessary: */
877 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
879 g_warning ("%s: BUG: no main window", __FUNCTION__);
883 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
884 MODEST_MAIN_WINDOW(main_window),
885 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
886 if (header_view != NULL){
887 header_folder = modest_header_view_get_folder(header_view);
888 g_assert(header_folder != NULL);
889 priv->header_folder_id = tny_folder_get_id(header_folder);
890 g_assert(priv->header_folder_id != NULL);
891 g_object_unref(header_folder);
894 priv->header_model = g_object_ref(model);
895 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
896 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
897 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
899 priv->row_changed_handler = g_signal_connect(
900 GTK_TREE_MODEL(model), "row-changed",
901 G_CALLBACK(modest_msg_view_window_on_row_changed),
903 priv->row_deleted_handler = g_signal_connect(
904 GTK_TREE_MODEL(model), "row-deleted",
905 G_CALLBACK(modest_msg_view_window_on_row_deleted),
907 priv->row_inserted_handler = g_signal_connect (
908 GTK_TREE_MODEL(model), "row-inserted",
909 G_CALLBACK(modest_msg_view_window_on_row_inserted),
911 priv->rows_reordered_handler = g_signal_connect(
912 GTK_TREE_MODEL(model), "rows-reordered",
913 G_CALLBACK(modest_msg_view_window_on_row_reordered),
916 if (header_view != NULL){
917 modest_header_view_add_observer(header_view,
918 MODEST_HEADER_VIEW_OBSERVER(window));
921 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
922 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
923 gtk_widget_show_all (GTK_WIDGET (window));
925 modest_msg_view_window_update_priority (window);
927 /* Check toolbar dimming rules */
928 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
930 return MODEST_WINDOW(window);
934 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
935 const gchar *modest_account_name,
936 const gchar *msg_uid)
938 ModestMsgViewWindow *window = NULL;
939 ModestMsgViewWindowPrivate *priv = NULL;
940 ModestWindowMgr *mgr = NULL;
942 mgr = modest_runtime_get_window_mgr ();
943 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
944 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
945 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
947 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
949 /* Remember that this is a search result,
950 * so we can disable some UI appropriately: */
951 priv->is_search_result = TRUE;
953 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
954 update_window_title (window);
956 return MODEST_WINDOW(window);
960 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
961 const gchar *modest_account_name,
962 const gchar *msg_uid)
965 ModestMsgViewWindowPrivate *priv;
966 ModestWindowMgr *mgr = NULL;
968 g_return_val_if_fail (msg, NULL);
969 mgr = modest_runtime_get_window_mgr ();
970 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
971 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
972 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
973 modest_account_name, msg_uid);
975 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
976 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
978 return MODEST_WINDOW(obj);
981 void modest_msg_view_window_on_row_changed(
982 GtkTreeModel *header_model,
985 ModestMsgViewWindow *window){
986 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
989 void modest_msg_view_window_on_row_deleted(
990 GtkTreeModel *header_model,
992 ModestMsgViewWindow *window){
993 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
996 /* On insertions we check if the folder still has the message we are
997 * showing or do not. If do not, we do nothing. Which means we are still
998 * not attached to any header folder and thus next/prev buttons are
999 * still dimmed. Once the message that is shown by msg-view is found, the
1000 * new model of header-view will be attached and the references will be set.
1001 * On each further insertions dimming rules will be checked. However
1002 * this requires extra CPU time at least works.
1003 * (An message might be deleted from TnyFolder and thus will not be
1004 * inserted into the model again for example if it is removed by the
1005 * imap server and the header view is refreshed.)
1007 void modest_msg_view_window_on_row_inserted(
1008 GtkTreeModel *new_model,
1009 GtkTreePath *tree_path,
1010 GtkTreeIter *tree_iter,
1011 ModestMsgViewWindow *window){
1012 ModestMsgViewWindowPrivate *priv = NULL;
1013 TnyHeader *header = NULL;
1016 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1018 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1020 /* If we already has a model attached then the message shown by
1021 * msg-view is in it, and thus we do not need any actions but
1022 * to check the dimming rules.*/
1023 if(priv->header_model != NULL){
1024 gtk_tree_row_reference_free(priv->next_row_reference);
1025 priv->next_row_reference = gtk_tree_row_reference_copy(
1026 priv->row_reference);
1027 select_next_valid_row (priv->header_model,
1028 &(priv->next_row_reference), FALSE);
1029 modest_ui_actions_check_toolbar_dimming_rules (
1030 MODEST_WINDOW (window));
1034 /* Check if the newly inserted message is the same we are actually
1035 * showing. IF not, we should remain detached from the header model
1036 * and thus prev and next toolbarbuttons should remain dimmed. */
1037 gtk_tree_model_get (new_model, tree_iter,
1038 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1039 uid = modest_tny_folder_get_header_unique_id(header);
1040 g_object_unref(G_OBJECT(header));
1042 if(!g_str_equal(priv->msg_uid, uid)){
1048 /* Setup row_reference for the actual msg. */
1049 priv->row_reference = gtk_tree_row_reference_new(
1050 new_model, tree_path);
1051 if(priv->row_reference == NULL){
1052 g_warning("No reference for msg header item.");
1056 /* Attach new_model and connect some callback to it to become able
1057 * to detect changes in header-view. */
1058 priv->header_model = g_object_ref(new_model);
1059 g_signal_connect (new_model, "row-changed",
1060 G_CALLBACK (modest_msg_view_window_on_row_changed),
1062 g_signal_connect (new_model, "row-deleted",
1063 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1065 g_signal_connect (new_model, "rows-reordered",
1066 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1069 /* Now set up next_row_reference. */
1070 priv->next_row_reference = gtk_tree_row_reference_copy(
1071 priv->row_reference);
1072 select_next_valid_row (priv->header_model,
1073 &(priv->next_row_reference), FALSE);
1075 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1078 void modest_msg_view_window_on_row_reordered(
1079 GtkTreeModel *header_model,
1083 ModestMsgViewWindow *window){
1084 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1087 /* The modest_msg_view_window_update_model_replaced implements update
1088 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1089 * actually belongs to the header-view is the same as the TnyFolder of
1090 * the message of msg-view or not. If they are different, there is
1091 * nothing to do. If they are the same, then the model has replaced and
1092 * the reference in msg-view shall be replaced from the old model to
1093 * the new model. In this case the view will be detached from it's
1094 * header folder. From this point the next/prev buttons are dimmed.
1096 void modest_msg_view_window_update_model_replaced(
1097 ModestHeaderViewObserver *observer,
1098 GtkTreeModel *model,
1099 const gchar *tny_folder_id){
1100 ModestMsgViewWindowPrivate *priv = NULL;
1101 ModestMsgViewWindow *window = NULL;
1103 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1104 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1106 window = MODEST_MSG_VIEW_WINDOW(observer);
1107 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1109 /* If there is an other folder in the header-view then we do
1110 * not care about it's model (msg list). Else if the
1111 * header-view shows the folder the msg shown by us is in, we
1112 * shall replace our model reference and make some check. */
1113 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1116 /* Model is changed(replaced), so we should forget the old
1117 * one. Because there might be other references and there
1118 * might be some change on the model even if we unreferenced
1119 * it, we need to disconnect our signals here. */
1120 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1121 priv->row_changed_handler))
1122 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1123 priv->row_changed_handler);
1124 priv->row_changed_handler = 0;
1125 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1126 priv->row_deleted_handler))
1127 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1128 priv->row_deleted_handler);
1129 priv->row_deleted_handler = 0;
1130 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1131 priv->row_inserted_handler))
1132 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1133 priv->row_inserted_handler);
1134 priv->row_inserted_handler = 0;
1135 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1136 priv->rows_reordered_handler))
1137 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1138 priv->rows_reordered_handler);
1139 priv->rows_reordered_handler = 0;
1140 g_object_unref(priv->header_model);
1141 priv->header_model = NULL;
1142 g_object_unref(priv->row_reference);
1143 priv->row_reference = NULL;
1144 g_object_unref(priv->next_row_reference);
1145 priv->next_row_reference = NULL;
1147 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1149 g_assert(model != NULL);
1151 /* Also we must connect to the new model for row insertions.
1152 * Only for insertions now. We will need other ones only after
1153 * the msg is show by msg-view is added to the new model. */
1154 priv->row_inserted_handler = g_signal_connect (
1155 model, "row-inserted",
1156 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1161 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1163 ModestMsgViewWindowPrivate *priv= NULL;
1165 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1166 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1168 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1172 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1174 ModestMsgViewWindowPrivate *priv= NULL;
1176 TnyHeader *header = NULL;
1177 GtkTreePath *path = NULL;
1180 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1181 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1183 /* If the message was not obtained from a treemodel,
1184 * for instance if it was opened directly by the search UI:
1186 if (priv->header_model == NULL) {
1187 msg = modest_msg_view_window_get_message (self);
1189 header = tny_msg_get_header (msg);
1190 g_object_unref (msg);
1195 /* Get iter of the currently selected message in the header view: */
1196 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1197 * instead of sometimes retrieving it from the header view?
1198 * Then we wouldn't be dependent on the message actually still being selected
1199 * in the header view. murrayc. */
1200 if (!gtk_tree_row_reference_valid (priv->row_reference))
1202 path = gtk_tree_row_reference_get_path (priv->row_reference);
1203 g_return_val_if_fail (path != NULL, NULL);
1204 gtk_tree_model_get_iter (priv->header_model,
1208 /* Get current message header */
1209 gtk_tree_model_get (priv->header_model, &iter,
1210 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1213 gtk_tree_path_free (path);
1218 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1220 ModestMsgViewWindowPrivate *priv;
1222 g_return_val_if_fail (self, NULL);
1224 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1226 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1230 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1232 ModestMsgViewWindowPrivate *priv;
1234 g_return_val_if_fail (self, NULL);
1236 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1238 return (const gchar*) priv->msg_uid;
1242 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1245 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1246 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1247 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1251 is_active = gtk_toggle_action_get_active (toggle);
1254 gtk_widget_show (priv->find_toolbar);
1255 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1257 gtk_widget_hide (priv->find_toolbar);
1260 /* update the toggle buttons status */
1261 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1262 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1263 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1264 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1269 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1270 ModestMsgViewWindow *obj)
1272 GtkToggleAction *toggle;
1273 ModestWindowPrivate *parent_priv;
1274 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1276 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1277 gtk_toggle_action_set_active (toggle, FALSE);
1281 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1282 ModestMsgViewWindow *obj)
1284 gchar *current_search;
1285 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1287 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1288 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1292 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1294 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1295 g_free (current_search);
1296 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1300 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1302 g_free (priv->last_search);
1303 priv->last_search = g_strdup (current_search);
1304 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1307 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1308 g_free (priv->last_search);
1309 priv->last_search = NULL;
1311 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1314 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1315 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1316 g_free (priv->last_search);
1317 priv->last_search = NULL;
1319 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1323 g_free (current_search);
1328 modest_msg_view_window_set_zoom (ModestWindow *window,
1331 ModestMsgViewWindowPrivate *priv;
1332 ModestWindowPrivate *parent_priv;
1333 GtkAction *action = NULL;
1334 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1336 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1338 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1339 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1340 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1342 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1343 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1345 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1349 modest_msg_view_window_get_zoom (ModestWindow *window)
1351 ModestMsgViewWindowPrivate *priv;
1353 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1355 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1356 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1360 modest_msg_view_window_zoom_plus (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 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1373 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1377 for (node = group; node != NULL; node = g_slist_next (node)) {
1378 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1379 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1387 modest_msg_view_window_zoom_minus (ModestWindow *window)
1389 ModestWindowPrivate *parent_priv;
1390 GtkRadioAction *zoom_radio_action;
1391 GSList *group, *node;
1393 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1394 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1395 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1397 group = gtk_radio_action_get_group (zoom_radio_action);
1399 for (node = group; node != NULL; node = g_slist_next (node)) {
1400 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1401 if (node->next != NULL) {
1402 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1405 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1415 modest_msg_view_window_key_event (GtkWidget *window,
1420 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1421 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1422 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1423 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1424 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1425 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1426 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1427 gboolean return_value;
1429 if (event->type == GDK_KEY_RELEASE) {
1430 GtkScrollType scroll_type;
1432 switch (event->keyval) {
1435 scroll_type = GTK_SCROLL_STEP_UP; break;
1438 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1440 case GDK_KP_Page_Up:
1441 scroll_type = GTK_SCROLL_PAGE_UP; break;
1443 case GDK_KP_Page_Down:
1444 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1447 scroll_type = GTK_SCROLL_START; break;
1450 scroll_type = GTK_SCROLL_END; break;
1451 default: scroll_type = GTK_SCROLL_NONE;
1454 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1455 scroll_type, FALSE, &return_value);
1466 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1469 ModestMsgViewWindowPrivate *priv;
1470 GtkTreeIter tmp_iter;
1471 gboolean is_last_selected;
1473 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1474 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1476 /*if no model (so no rows at all), then virtually we are the last*/
1477 if (!priv->header_model)
1480 path = gtk_tree_row_reference_get_path (priv->row_reference);
1484 is_last_selected = TRUE;
1485 while (is_last_selected) {
1487 gtk_tree_path_next (path);
1488 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1490 gtk_tree_model_get (priv->header_model, &tmp_iter,
1491 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1494 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1495 is_last_selected = FALSE;
1496 g_object_unref(G_OBJECT(header));
1499 gtk_tree_path_free (path);
1500 return is_last_selected;
1504 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1506 ModestMsgViewWindowPrivate *priv;
1508 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1509 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1511 return priv->header_model != NULL;
1515 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1517 ModestMsgViewWindowPrivate *priv;
1519 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1520 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1522 return priv->is_search_result;
1526 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1529 ModestMsgViewWindowPrivate *priv;
1530 gboolean is_first_selected;
1531 GtkTreeIter tmp_iter;
1532 /* gchar * path_string;*/
1534 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1535 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1537 /*if no model (so no rows at all), then virtually we are the first*/
1538 if (!priv->header_model)
1541 path = gtk_tree_row_reference_get_path (priv->row_reference);
1545 /* path_string = gtk_tree_path_to_string (path);
1546 is_first_selected = strcmp (path_string, "0");
1548 g_free (path_string);
1549 gtk_tree_path_free (path);
1551 return is_first_selected;*/
1553 is_first_selected = TRUE;
1554 while (is_first_selected) {
1556 if(!gtk_tree_path_prev (path))
1558 /* Here the 'if' is needless for logic, but let make sure
1559 * iter is valid for gtk_tree_model_get. */
1560 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1562 gtk_tree_model_get (priv->header_model, &tmp_iter,
1563 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1566 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1567 is_first_selected = FALSE;
1568 g_object_unref(G_OBJECT(header));
1571 gtk_tree_path_free (path);
1572 return is_first_selected;
1576 * Reads the message whose summary item is @header. It takes care of
1577 * several things, among others:
1579 * If the message was not previously downloaded then ask the user
1580 * before downloading. If there is no connection launch the connection
1581 * dialog. Update toolbar dimming rules.
1583 * Returns: TRUE if the mail operation was started, otherwise if the
1584 * user do not want to download the message, or if the user do not
1585 * want to connect, then the operation is not issued
1588 message_reader (ModestMsgViewWindow *window,
1589 ModestMsgViewWindowPrivate *priv,
1591 GtkTreeRowReference *row_reference)
1593 ModestMailOperation *mail_op = NULL;
1594 gboolean already_showing = FALSE;
1595 ModestWindow *msg_window = NULL;
1596 ModestWindowMgr *mgr;
1598 g_return_val_if_fail (row_reference != NULL, FALSE);
1600 mgr = modest_runtime_get_window_mgr ();
1601 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1602 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1605 gtk_window_present (GTK_WINDOW (msg_window));
1606 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1610 /* Msg download completed */
1611 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1612 /* Ask the user if he wants to download the message if
1614 if (!tny_device_is_online (modest_runtime_get_device())) {
1615 TnyFolder *folder = NULL;
1616 GtkResponseType response;
1618 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1619 _("mcen_nc_get_msg"));
1620 if (response == GTK_RESPONSE_CANCEL)
1623 /* Offer the connection dialog if necessary */
1624 folder = tny_header_get_folder (header);
1626 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1627 TNY_FOLDER_STORE (folder))) {
1628 g_object_unref (folder);
1631 g_object_unref (folder);
1636 /* New mail operation */
1637 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1638 modest_ui_actions_get_msgs_full_error_handler,
1641 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1642 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1643 g_object_unref (mail_op);
1645 /* Update toolbar dimming rules */
1646 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1652 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1654 ModestMsgViewWindowPrivate *priv;
1655 GtkTreePath *path= NULL;
1656 GtkTreeIter tmp_iter;
1658 gboolean retval = TRUE;
1659 GtkTreeRowReference *row_reference = NULL;
1661 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1662 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1664 /* Update the next row reference if it's not valid. This could
1665 happen if for example the header which it was pointing to,
1666 was deleted. The best place to do it is in the row-deleted
1667 handler but the tinymail model do not work like the glib
1668 tree models and reports the deletion when the row is still
1670 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1671 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1672 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1673 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1676 if (priv->next_row_reference)
1677 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1681 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1683 gtk_tree_model_get_iter (priv->header_model,
1686 gtk_tree_path_free (path);
1688 gtk_tree_model_get (priv->header_model, &tmp_iter,
1689 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1692 /* Read the message & show it */
1693 if (!message_reader (window, priv, header, row_reference)) {
1695 gtk_tree_row_reference_free (row_reference);
1699 g_object_unref (header);
1705 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1707 ModestMsgViewWindowPrivate *priv = NULL;
1708 TnyHeader *header = NULL;
1710 GtkTreePath *path = NULL;
1711 GtkTreeRowReference *row_reference = NULL;
1713 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1714 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1716 /* Check that the model is not empty */
1717 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1720 /* Get the header */
1721 gtk_tree_model_get (priv->header_model,
1723 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1725 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1726 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1727 g_object_unref (header);
1728 return modest_msg_view_window_select_next_message (self);
1731 path = gtk_tree_model_get_path (priv->header_model, &iter);
1732 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1733 gtk_tree_path_free (path);
1735 /* Read the message & show it */
1736 message_reader (self, priv, header, row_reference);
1739 g_object_unref (header);
1745 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1747 ModestMsgViewWindowPrivate *priv = NULL;
1749 GtkTreeRowReference *row_reference = NULL;
1751 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1752 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1754 /* Return inmediatly if there is no header model */
1755 if (!priv->header_model)
1758 path = gtk_tree_row_reference_get_path (priv->row_reference);
1759 while (gtk_tree_path_prev (path)) {
1763 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1764 gtk_tree_model_get (priv->header_model, &iter,
1765 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1769 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1770 g_object_unref (header);
1774 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1775 /* Read the message & show it */
1776 if (!message_reader (window, priv, header, row_reference)) {
1777 gtk_tree_row_reference_free (row_reference);
1778 g_object_unref (header);
1782 gtk_tree_path_free (path);
1783 g_object_unref (header);
1788 gtk_tree_path_free (path);
1793 view_msg_cb (ModestMailOperation *mail_op,
1800 ModestMsgViewWindow *self = NULL;
1801 ModestMsgViewWindowPrivate *priv = NULL;
1802 GtkTreeRowReference *row_reference = NULL;
1804 /* If there was any error */
1805 row_reference = (GtkTreeRowReference *) user_data;
1806 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1807 gtk_tree_row_reference_free (row_reference);
1811 /* Get the window */
1812 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1813 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1814 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1816 /* Update the row reference */
1817 gtk_tree_row_reference_free (priv->row_reference);
1818 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1819 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1820 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1821 gtk_tree_row_reference_free (row_reference);
1823 /* Mark header as read */
1824 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1825 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1827 /* Set new message */
1828 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1829 modest_msg_view_window_update_priority (self);
1830 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1831 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1833 /* Set the new message uid of the window */
1834 if (priv->msg_uid) {
1835 g_free (priv->msg_uid);
1836 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1839 /* Notify the observers */
1840 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1841 0, priv->header_model, priv->row_reference);
1843 /* Free new references */
1844 g_object_unref (self);
1848 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1850 ModestMsgViewWindowPrivate *priv;
1852 TnyFolderType folder_type;
1854 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1856 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1858 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1862 folder = tny_msg_get_folder (msg);
1864 folder_type = tny_folder_get_folder_type (folder);
1865 g_object_unref (folder);
1867 g_object_unref (msg);
1875 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1877 ModestMsgViewWindowPrivate *priv;
1878 TnyHeaderFlags flags = 0;
1880 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1882 if (priv->header_model) {
1885 GtkTreePath *path = NULL;
1887 path = gtk_tree_row_reference_get_path (priv->row_reference);
1888 g_return_if_fail (path != NULL);
1889 gtk_tree_model_get_iter (priv->header_model,
1891 gtk_tree_row_reference_get_path (priv->row_reference));
1893 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1896 flags = tny_header_get_flags (header);
1897 g_object_unref(G_OBJECT(header));
1899 gtk_tree_path_free (path);
1902 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1907 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1909 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1910 ModestWindowPrivate *parent_priv;
1911 ModestWindowMgr *mgr;
1912 gboolean is_fullscreen;
1913 GtkAction *fs_toggle_action;
1916 mgr = modest_runtime_get_window_mgr ();
1917 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1919 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1921 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1922 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1923 if (is_fullscreen != active) {
1924 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1933 set_homogeneous (GtkWidget *widget,
1936 if (GTK_IS_TOOL_ITEM (widget)) {
1937 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1938 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1943 modest_msg_view_window_show_toolbar (ModestWindow *self,
1944 gboolean show_toolbar)
1946 ModestMsgViewWindowPrivate *priv = NULL;
1947 ModestWindowPrivate *parent_priv;
1948 GtkWidget *reply_button = NULL, *menu = NULL;
1949 GtkWidget *placeholder = NULL;
1951 const gchar *action_name;
1954 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1955 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1957 /* Set optimized view status */
1958 priv->optimized_view = !show_toolbar;
1960 if (!parent_priv->toolbar) {
1961 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1963 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1965 /* Set homogeneous toolbar */
1966 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1967 set_homogeneous, NULL);
1969 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1970 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1971 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1972 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1973 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1974 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1975 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1976 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1978 /* Add ProgressBar (Transfer toolbar) */
1979 priv->progress_bar = modest_progress_bar_widget_new ();
1980 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1981 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1982 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1983 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1984 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1986 /* Connect cancel 'clicked' signal to abort progress mode */
1987 g_signal_connect(priv->cancel_toolitem, "clicked",
1988 G_CALLBACK(cancel_progressbar),
1991 /* Add it to the observers list */
1992 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1995 hildon_window_add_toolbar (HILDON_WINDOW (self),
1996 GTK_TOOLBAR (parent_priv->toolbar));
1998 /* Set reply button tap and hold menu */
1999 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2000 "/ToolBar/ToolbarMessageReply");
2001 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2002 "/ToolbarReplyCSM");
2003 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2007 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2008 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2009 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2011 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2012 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2013 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2015 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2018 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2019 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2022 /* Update also the actions (to update the toggles in the
2023 menus), we have to do it manually because some other window
2024 of the same time could have changed it (remember that the
2025 toolbar fullscreen mode is shared by all the windows of the
2027 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2028 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2030 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2032 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2033 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2038 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2040 ModestMsgViewWindow *window)
2042 if (!GTK_WIDGET_VISIBLE (window))
2045 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2049 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2051 ModestMsgViewWindowPrivate *priv;
2053 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2054 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2056 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2060 cancel_progressbar (GtkToolButton *toolbutton,
2061 ModestMsgViewWindow *self)
2064 ModestMsgViewWindowPrivate *priv;
2066 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2068 /* Get operation observers and cancel its current operation */
2069 tmp = priv->progress_widgets;
2071 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2072 tmp=g_slist_next(tmp);
2076 observers_empty (ModestMsgViewWindow *self)
2079 ModestMsgViewWindowPrivate *priv;
2080 gboolean is_empty = TRUE;
2081 guint pending_ops = 0;
2083 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2084 tmp = priv->progress_widgets;
2086 /* Check all observers */
2087 while (tmp && is_empty) {
2088 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2089 is_empty = pending_ops == 0;
2091 tmp = g_slist_next(tmp);
2098 on_account_removed (TnyAccountStore *account_store,
2099 TnyAccount *account,
2102 /* Do nothing if it's a transport account, because we only
2103 show the messages of a store account */
2104 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2105 const gchar *parent_acc = NULL;
2106 const gchar *our_acc = NULL;
2108 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2109 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2111 /* Close this window if I'm showing a message of the removed account */
2112 if (strcmp (parent_acc, our_acc) == 0)
2113 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2118 on_mail_operation_started (ModestMailOperation *mail_op,
2121 ModestMsgViewWindow *self;
2122 ModestMailOperationTypeOperation op_type;
2124 ModestMsgViewWindowPrivate *priv;
2126 self = MODEST_MSG_VIEW_WINDOW (user_data);
2127 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2128 op_type = modest_mail_operation_get_type_operation (mail_op);
2129 tmp = priv->progress_widgets;
2131 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2132 set_toolbar_transfer_mode(self);
2134 modest_progress_object_add_operation (
2135 MODEST_PROGRESS_OBJECT (tmp->data),
2137 tmp = g_slist_next (tmp);
2143 on_mail_operation_finished (ModestMailOperation *mail_op,
2146 ModestMsgViewWindow *self;
2147 ModestMailOperationTypeOperation op_type;
2149 ModestMsgViewWindowPrivate *priv;
2151 self = MODEST_MSG_VIEW_WINDOW (user_data);
2152 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2153 op_type = modest_mail_operation_get_type_operation (mail_op);
2154 tmp = priv->progress_widgets;
2156 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2158 modest_progress_object_remove_operation (
2159 MODEST_PROGRESS_OBJECT (tmp->data),
2161 tmp = g_slist_next (tmp);
2164 /* If no more operations are being observed, NORMAL mode is enabled again */
2165 if (observers_empty (self)) {
2166 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2172 on_queue_changed (ModestMailOperationQueue *queue,
2173 ModestMailOperation *mail_op,
2174 ModestMailOperationQueueNotification type,
2175 ModestMsgViewWindow *self)
2177 ModestMsgViewWindowPrivate *priv;
2179 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2181 /* If this operations was created by another window, do nothing */
2182 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2185 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2186 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2188 "operation-started",
2189 G_CALLBACK (on_mail_operation_started),
2191 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2193 "operation-finished",
2194 G_CALLBACK (on_mail_operation_finished),
2196 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2197 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2199 "operation-started");
2200 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2202 "operation-finished");
2207 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2209 ModestMsgViewWindowPrivate *priv;
2210 GList *selected_attachments = NULL;
2212 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2213 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2215 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2217 return selected_attachments;
2221 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2223 ModestMsgViewWindowPrivate *priv;
2224 const gchar *msg_uid;
2225 gchar *attachment_uid = NULL;
2226 gint attachment_index = 0;
2229 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2230 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2231 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2233 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2234 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2235 attachment_index = g_list_index (attachments, mime_part);
2236 g_list_free (attachments);
2238 if (msg_uid && attachment_index >= 0) {
2239 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2242 if (mime_part == NULL) {
2243 gboolean error = FALSE;
2244 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2245 if (selected_attachments == NULL) {
2247 } else if (g_list_length (selected_attachments) > 1) {
2248 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2251 mime_part = (TnyMimePart *) selected_attachments->data;
2252 g_object_ref (mime_part);
2254 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2255 g_list_free (selected_attachments);
2260 g_object_ref (mime_part);
2263 if (tny_mime_part_is_purged (mime_part)) {
2264 g_object_unref (mime_part);
2268 if (!TNY_IS_MSG (mime_part)) {
2269 gchar *filepath = NULL;
2270 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2271 const gchar *content_type;
2272 TnyFsStream *temp_stream = NULL;
2273 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid,
2276 if (temp_stream != NULL) {
2277 content_type = tny_mime_part_get_content_type (mime_part);
2278 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2280 /* make the file read-only */
2281 if (g_chmod(filepath, 0444) != 0)
2282 g_warning ("%s: failed to set file '%s' to read-only: %s",
2283 __FUNCTION__, filepath, strerror(errno));
2285 modest_platform_activate_file (filepath, content_type);
2286 g_object_unref (temp_stream);
2288 /* NOTE: files in the temporary area will be automatically
2289 * cleaned after some time if they are no longer in use */
2290 } else if (filepath != NULL) {
2291 /* the file may already exist but it isn't writable,
2292 * let's try to open it anyway */
2293 content_type = tny_mime_part_get_content_type (mime_part);
2294 modest_platform_activate_file (filepath, content_type);
2298 /* message attachment */
2299 TnyHeader *header = NULL;
2300 ModestWindowMgr *mgr;
2301 ModestWindow *msg_win = NULL;
2304 header = tny_msg_get_header (TNY_MSG (mime_part));
2305 mgr = modest_runtime_get_window_mgr ();
2306 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2309 if (msg_win) /* there is already a window for this uid; top it */
2310 gtk_window_present (GTK_WINDOW(msg_win));
2312 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2313 * thus, we don't do anything */
2314 g_warning ("window for is already being created");
2316 /* it's not found, so create a new window for it */
2317 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2318 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2320 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2321 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2322 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2323 modest_window_get_zoom (MODEST_WINDOW (window)));
2324 modest_window_mgr_register_window (mgr, msg_win);
2325 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2326 gtk_widget_show_all (GTK_WIDGET (msg_win));
2329 g_object_unref (mime_part);
2345 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2346 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2347 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2348 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2351 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2355 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2356 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2357 g_free (pair->filename);
2358 g_object_unref (pair->part);
2359 g_slice_free (SaveMimePartPair, pair);
2361 g_list_free (info->pairs);
2364 gtk_widget_destroy (info->banner);
2365 g_object_unref (info->banner);
2366 g_slice_free (SaveMimePartInfo, info);
2371 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2373 if (info->pairs != NULL) {
2374 save_mime_part_to_file (info);
2377 result = info->result;
2379 /* This is a GDK lock because we are an idle callback and
2380 * hildon_banner_show_information is or does Gtk+ code */
2382 gdk_threads_enter (); /* CHECKED */
2383 save_mime_part_info_free (info, TRUE);
2385 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2387 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2389 gdk_threads_leave (); /* CHECKED */
2396 save_mime_part_to_file (SaveMimePartInfo *info)
2398 GnomeVFSResult result;
2399 GnomeVFSHandle *handle;
2401 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2403 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2404 if (result == GNOME_VFS_OK) {
2405 stream = tny_vfs_stream_new (handle);
2406 tny_mime_part_decode_to_stream (pair->part, stream);
2407 g_object_unref (G_OBJECT (stream));
2408 g_object_unref (pair->part);
2409 g_slice_free (SaveMimePartPair, pair);
2410 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2411 info->result = TRUE;
2413 save_mime_part_info_free (info, FALSE);
2414 info->result = FALSE;
2417 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2422 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2424 gboolean is_ok = TRUE;
2425 gint replaced_files = 0;
2426 const GList *files = info->pairs;
2429 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2430 SaveMimePartPair *pair = iter->data;
2431 if (modest_maemo_utils_file_exists (pair->filename)) {
2435 if (replaced_files) {
2436 GtkWidget *confirm_overwrite_dialog;
2437 const gchar *message = (replaced_files == 1) ?
2438 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2439 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2440 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2443 gtk_widget_destroy (confirm_overwrite_dialog);
2447 save_mime_part_info_free (info, TRUE);
2449 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2450 _CS("sfil_ib_saving"));
2451 info->banner = g_object_ref (banner);
2452 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2453 g_object_unref (banner);
2460 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2462 gboolean clean_list = FALSE;
2463 ModestMsgViewWindowPrivate *priv;
2464 GList *files_to_save = NULL;
2465 GtkWidget *save_dialog = NULL;
2466 gchar *folder = NULL;
2467 gboolean canceled = FALSE;
2468 const gchar *filename = NULL;
2469 gchar *save_multiple_str = NULL;
2471 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2472 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2474 if (mime_parts == NULL) {
2475 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2476 if (mime_parts == NULL)
2481 /* prepare dialog */
2482 if (mime_parts->next == NULL) {
2483 /* only one attachment selected */
2484 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2485 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2486 filename = tny_mime_part_get_filename (mime_part);
2488 g_warning ("Tried to save a non-file attachment");
2492 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2493 g_list_length (mime_parts));
2496 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2497 GTK_FILE_CHOOSER_ACTION_SAVE);
2500 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2501 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2505 if (filename != NULL)
2506 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2509 /* if multiple, set multiple string */
2510 if (save_multiple_str) {
2511 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2515 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2516 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2518 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2519 hildon_banner_show_information
2520 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2524 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2525 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2527 if (tny_mime_part_is_attachment (mime_part)) {
2528 SaveMimePartPair *pair;
2530 if ((mime_parts->next != NULL) &&
2531 (tny_mime_part_get_filename (mime_part) == NULL))
2534 pair = g_slice_new0 (SaveMimePartPair);
2535 if (mime_parts->next == NULL) {
2536 pair->filename = g_strdup (chooser_uri);
2539 g_build_filename (chooser_uri,
2540 tny_mime_part_get_filename (mime_part), NULL);
2542 pair->part = g_object_ref (mime_part);
2543 files_to_save = g_list_prepend (files_to_save, pair);
2547 g_free (chooser_uri);
2550 gtk_widget_destroy (save_dialog);
2553 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2554 g_list_free (mime_parts);
2557 if (files_to_save != NULL) {
2558 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2559 info->pairs = files_to_save;
2560 info->result = TRUE;
2561 save_mime_parts_to_file_with_checks (info);
2566 show_remove_attachment_information (gpointer userdata)
2568 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2569 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2571 /* We're outside the main lock */
2572 gdk_threads_enter ();
2574 if (priv->remove_attachment_banner != NULL) {
2575 gtk_widget_destroy (priv->remove_attachment_banner);
2576 g_object_unref (priv->remove_attachment_banner);
2579 priv->remove_attachment_banner = g_object_ref (
2580 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2582 gdk_threads_leave ();
2588 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2590 ModestMsgViewWindowPrivate *priv;
2591 GList *mime_parts = NULL, *node;
2592 gchar *confirmation_message;
2596 /* TnyFolder *folder; */
2598 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2599 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2602 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2604 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2606 /* Remove already purged messages from mime parts list */
2608 while (node != NULL) {
2609 TnyMimePart *part = TNY_MIME_PART (node->data);
2610 if (tny_mime_part_is_purged (part)) {
2611 GList *deleted_node = node;
2612 node = g_list_next (node);
2613 g_object_unref (part);
2614 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2616 node = g_list_next (node);
2620 if (mime_parts == NULL)
2623 n_attachments = g_list_length (mime_parts);
2624 if (n_attachments == 1) {
2625 const gchar *filename;
2627 if (TNY_IS_MSG (mime_parts->data)) {
2629 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2630 filename = tny_header_get_subject (header);
2631 g_object_unref (header);
2632 if (filename == NULL)
2633 filename = _("mail_va_no_subject");
2635 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2637 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2639 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2640 "mcen_nc_purge_files_text",
2641 n_attachments), n_attachments);
2643 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2644 confirmation_message);
2645 g_free (confirmation_message);
2647 if (response != GTK_RESPONSE_OK)
2650 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2651 /* folder = tny_msg_get_folder (msg); */
2652 /* tny_msg_uncache_attachments (msg); */
2653 /* tny_folder_refresh (folder, NULL); */
2654 /* g_object_unref (folder); */
2656 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2657 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2658 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2661 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2662 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2663 tny_msg_rewrite_cache (msg);
2664 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2666 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2667 g_list_free (mime_parts);
2669 if (priv->purge_timeout > 0) {
2670 g_source_remove (priv->purge_timeout);
2671 priv->purge_timeout = 0;
2674 if (priv->remove_attachment_banner) {
2675 gtk_widget_destroy (priv->remove_attachment_banner);
2676 g_object_unref (priv->remove_attachment_banner);
2677 priv->remove_attachment_banner = NULL;
2685 update_window_title (ModestMsgViewWindow *window)
2687 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2689 TnyHeader *header = NULL;
2690 const gchar *subject = NULL;
2692 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2695 header = tny_msg_get_header (msg);
2696 subject = tny_header_get_subject (header);
2697 g_object_unref (msg);
2700 if ((subject == NULL)||(subject[0] == '\0'))
2701 subject = _("mail_va_no_subject");
2703 gtk_window_set_title (GTK_WINDOW (window), subject);
2707 static void on_move_focus (GtkWidget *widget,
2708 GtkDirectionType direction,
2711 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");