Bug 794693 - Crash when trying to view email message source
[evolution.git] / src / mail / e-mail-paned-view.c
blobbdd197cd71c574ebfe93398abc05d6dfebd25248
1 /*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU Lesser General Public License as published by
4 * the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful, but
7 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9 * for more details.
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 * Authors:
16 * Srinivasa Ragavan <sragavan@gnome.org>
18 * Copyright (C) 2010 Intel corporation. (www.intel.com)
22 #include "evolution-config.h"
24 #include <glib/gi18n.h>
26 #include <shell/e-shell-window-actions.h>
28 #include <libemail-engine/libemail-engine.h>
30 #include "em-utils.h"
31 #include "message-list.h"
32 #include "e-mail-reader-utils.h"
34 #include "e-mail-paned-view.h"
36 #define E_MAIL_PANED_VIEW_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), E_TYPE_MAIL_PANED_VIEW, EMailPanedViewPrivate))
40 #define E_SHELL_WINDOW_ACTION_GROUP_MAIL(window) \
41 E_SHELL_WINDOW_ACTION_GROUP ((window), "mail")
43 struct _EMailPanedViewPrivate {
44 GtkWidget *paned;
45 GtkWidget *scrolled_window;
46 GtkWidget *message_list;
47 GtkWidget *preview_pane;
48 GtkWidget *search_bar;
50 EMailDisplay *display;
51 GalViewInstance *view_instance;
53 /* ETable scrolling hack */
54 gdouble default_scrollbar_position;
56 guint paned_binding_id;
58 /* Signal handler IDs */
59 guint message_list_built_id;
62 enum {
63 PROP_0,
64 PROP_FORWARD_STYLE,
65 PROP_GROUP_BY_THREADS,
66 PROP_REPLY_STYLE,
67 PROP_MARK_SEEN_ALWAYS,
68 PROP_DELETE_SELECTS_PREVIOUS
71 #define STATE_KEY_GROUP_BY_THREADS "GroupByThreads"
72 #define STATE_KEY_SELECTED_MESSAGE "SelectedMessage"
73 #define STATE_KEY_PREVIEW_VISIBLE "PreviewVisible"
74 #define STATE_GROUP_GLOBAL_FOLDER "GlobalFolder"
76 /* Forward Declarations */
77 static void e_mail_paned_view_reader_init (EMailReaderInterface *iface);
79 G_DEFINE_TYPE_WITH_CODE (
80 EMailPanedView, e_mail_paned_view, E_TYPE_MAIL_VIEW,
81 G_IMPLEMENT_INTERFACE (
82 E_TYPE_MAIL_READER, e_mail_paned_view_reader_init)
83 G_IMPLEMENT_INTERFACE (
84 E_TYPE_EXTENSIBLE, NULL))
86 static void
87 mail_paned_view_save_boolean (EMailView *view,
88 const gchar *key,
89 gboolean value)
91 EMailReader *reader;
92 CamelFolder *folder;
94 reader = E_MAIL_READER (view);
95 folder = e_mail_reader_ref_folder (reader);
97 if (folder != NULL) {
98 EShellView *shell_view;
99 GKeyFile *key_file;
100 gchar *folder_uri;
101 gchar *group_name;
103 shell_view = e_mail_view_get_shell_view (view);
104 key_file = e_shell_view_get_state_key_file (shell_view);
106 folder_uri = e_mail_folder_uri_from_folder (folder);
107 group_name = g_strdup_printf ("Folder %s", folder_uri);
108 g_key_file_set_boolean (key_file, group_name, key, value);
109 g_free (group_name);
110 g_free (folder_uri);
112 g_key_file_set_boolean (
113 key_file, STATE_GROUP_GLOBAL_FOLDER, key, value);
115 e_shell_view_set_state_dirty (shell_view);
117 g_object_unref (folder);
121 static void
122 mail_paned_view_message_list_built_cb (EMailView *view,
123 MessageList *message_list)
125 EMailPanedViewPrivate *priv;
126 EShellView *shell_view;
127 EShellWindow *shell_window;
128 CamelFolder *folder;
129 GKeyFile *key_file;
131 priv = E_MAIL_PANED_VIEW_GET_PRIVATE (view);
133 folder = message_list_ref_folder (message_list);
135 g_signal_handler_disconnect (
136 message_list, priv->message_list_built_id);
137 priv->message_list_built_id = 0;
139 shell_view = e_mail_view_get_shell_view (view);
140 shell_window = e_shell_view_get_shell_window (shell_view);
142 key_file = e_shell_view_get_state_key_file (shell_view);
144 if (message_list->cursor_uid != NULL)
145 ; /* do nothing */
147 else if (folder == NULL)
148 ; /* do nothing */
150 else if (e_shell_window_get_safe_mode (shell_window))
151 e_shell_window_set_safe_mode (shell_window, FALSE);
153 else {
154 const gchar *key;
155 gchar *folder_uri;
156 gchar *group_name;
157 gchar *uid;
159 folder_uri = e_mail_folder_uri_from_folder (folder);
161 key = STATE_KEY_SELECTED_MESSAGE;
162 group_name = g_strdup_printf ("Folder %s", folder_uri);
163 uid = g_key_file_get_string (key_file, group_name, key, NULL);
164 g_free (group_name);
166 g_free (folder_uri);
168 if (!message_list_contains_uid (message_list, uid) &&
169 e_mail_reader_get_mark_seen_always (E_MAIL_READER (view)))
170 e_mail_reader_unset_folder_just_selected (E_MAIL_READER (view));
172 /* Use selection fallbacks if UID is not found. */
173 message_list_select_uid (message_list, uid, TRUE);
175 g_free (uid);
178 g_clear_object (&folder);
181 static void
182 mail_paned_view_message_selected_cb (EMailView *view,
183 const gchar *message_uid,
184 MessageList *message_list)
186 EShellView *shell_view;
187 CamelFolder *folder;
188 GKeyFile *key_file;
189 const gchar *key;
190 gchar *folder_uri;
191 gchar *group_name;
193 folder = message_list_ref_folder (message_list);
195 /* This also gets triggered when selecting a store name on
196 * the sidebar such as "On This Computer", in which case
197 * 'folder' will be NULL. */
198 if (folder == NULL)
199 return;
201 shell_view = e_mail_view_get_shell_view (view);
202 key_file = e_shell_view_get_state_key_file (shell_view);
204 folder_uri = e_mail_folder_uri_from_folder (folder);
206 key = STATE_KEY_SELECTED_MESSAGE;
207 group_name = g_strdup_printf ("Folder %s", folder_uri);
209 if (message_uid != NULL)
210 g_key_file_set_string (key_file, group_name, key, message_uid);
211 else
212 g_key_file_remove_key (key_file, group_name, key, NULL);
213 e_shell_view_set_state_dirty (shell_view);
215 g_free (group_name);
216 g_free (folder_uri);
218 g_object_unref (folder);
221 /* To recognize old values from new values */
222 #define PROPORTION_LOWER_LIMIT 1000000
224 static gboolean
225 mail_paned_view_map_setting_to_proportion_cb (GValue *value,
226 GVariant *variant,
227 gpointer user_data)
229 gint stored;
230 gdouble proportion = 0.5;
232 stored = g_variant_get_int32 (variant);
234 if (stored >= PROPORTION_LOWER_LIMIT)
235 proportion = (stored - PROPORTION_LOWER_LIMIT) / ((gdouble) PROPORTION_LOWER_LIMIT);
237 g_value_set_double (value, proportion);
239 return TRUE;
242 static GVariant *
243 mail_paned_view_map_proportion_to_setting_cb (const GValue *value,
244 const GVariantType *expected_type,
245 gpointer user_data)
247 gdouble proportion;
249 proportion = g_value_get_double (value);
251 return g_variant_new_int32 (PROPORTION_LOWER_LIMIT + (gint32) (proportion * PROPORTION_LOWER_LIMIT));
254 static void
255 mail_paned_view_notify_orientation_cb (GtkWidget *paned,
256 GParamSpec *param,
257 EShellWindow *shell_window)
259 GSettings *settings;
260 const gchar *settings_key;
261 guint32 add_flags = 0;
263 g_return_if_fail (E_IS_PANED (paned));
264 g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
266 g_settings_unbind (paned, "proportion");
268 if (e_shell_window_is_main_instance (shell_window)) {
269 if (gtk_orientable_get_orientation (GTK_ORIENTABLE (paned)) == GTK_ORIENTATION_HORIZONTAL)
270 settings_key = "hpaned-size";
271 else
272 settings_key = "paned-size";
273 } else {
274 if (gtk_orientable_get_orientation (GTK_ORIENTABLE (paned)) == GTK_ORIENTATION_HORIZONTAL)
275 settings_key = "hpaned-size-sub";
276 else
277 settings_key = "paned-size-sub";
279 add_flags = G_SETTINGS_BIND_GET_NO_CHANGES;
282 settings = e_util_ref_settings ("org.gnome.evolution.mail");
284 g_settings_bind_with_mapping (settings, settings_key,
285 paned, "proportion",
286 G_SETTINGS_BIND_DEFAULT | add_flags,
287 mail_paned_view_map_setting_to_proportion_cb,
288 mail_paned_view_map_proportion_to_setting_cb,
289 NULL, NULL);
291 g_object_unref (settings);
294 static void
295 mail_paned_view_restore_state_cb (EShellWindow *shell_window,
296 EShellView *shell_view,
297 EMailPanedView *view)
299 EMailPanedViewPrivate *priv;
301 priv = E_MAIL_PANED_VIEW (view)->priv;
303 g_signal_connect (priv->paned, "notify::orientation",
304 G_CALLBACK (mail_paned_view_notify_orientation_cb), shell_window);
306 mail_paned_view_notify_orientation_cb (priv->paned, NULL, shell_window);
309 static void
310 mail_paned_display_view_cb (GalViewInstance *view_instance,
311 GalView *gal_view,
312 EMailView *view)
314 EMailReader *reader;
315 EShellView *shell_view;
316 GtkWidget *message_list;
318 shell_view = e_mail_view_get_shell_view (view);
319 e_shell_view_set_view_instance (shell_view, view_instance);
321 reader = E_MAIL_READER (view);
322 message_list = e_mail_reader_get_message_list (reader);
324 if (GAL_IS_VIEW_ETABLE (gal_view))
325 gal_view_etable_attach_tree (
326 GAL_VIEW_ETABLE (gal_view),
327 E_TREE (message_list));
330 static void
331 mail_paned_view_notify_group_by_threads_cb (EMailReader *reader)
333 gboolean group_by_threads;
335 group_by_threads = e_mail_reader_get_group_by_threads (reader);
337 mail_paned_view_save_boolean (
338 E_MAIL_VIEW (reader),
339 STATE_KEY_GROUP_BY_THREADS, group_by_threads);
342 static void
343 mail_paned_view_set_property (GObject *object,
344 guint property_id,
345 const GValue *value,
346 GParamSpec *pspec)
348 switch (property_id) {
349 case PROP_FORWARD_STYLE:
350 e_mail_reader_set_forward_style (
351 E_MAIL_READER (object),
352 g_value_get_enum (value));
353 return;
355 case PROP_GROUP_BY_THREADS:
356 e_mail_reader_set_group_by_threads (
357 E_MAIL_READER (object),
358 g_value_get_boolean (value));
359 return;
361 case PROP_REPLY_STYLE:
362 e_mail_reader_set_reply_style (
363 E_MAIL_READER (object),
364 g_value_get_enum (value));
365 return;
367 case PROP_MARK_SEEN_ALWAYS:
368 e_mail_reader_set_mark_seen_always (
369 E_MAIL_READER (object),
370 g_value_get_boolean (value));
371 return;
373 case PROP_DELETE_SELECTS_PREVIOUS:
374 e_mail_reader_set_delete_selects_previous (
375 E_MAIL_READER (object),
376 g_value_get_boolean (value));
377 return;
380 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
383 static void
384 mail_paned_view_get_property (GObject *object,
385 guint property_id,
386 GValue *value,
387 GParamSpec *pspec)
389 switch (property_id) {
390 case PROP_FORWARD_STYLE:
391 g_value_set_enum (
392 value,
393 e_mail_reader_get_forward_style (
394 E_MAIL_READER (object)));
395 return;
397 case PROP_GROUP_BY_THREADS:
398 g_value_set_boolean (
399 value,
400 e_mail_reader_get_group_by_threads (
401 E_MAIL_READER (object)));
402 return;
404 case PROP_REPLY_STYLE:
405 g_value_set_enum (
406 value,
407 e_mail_reader_get_reply_style (
408 E_MAIL_READER (object)));
409 return;
411 case PROP_MARK_SEEN_ALWAYS:
412 g_value_set_boolean (
413 value,
414 e_mail_reader_get_mark_seen_always (
415 E_MAIL_READER (object)));
416 return;
418 case PROP_DELETE_SELECTS_PREVIOUS:
419 g_value_set_boolean (
420 value,
421 e_mail_reader_get_delete_selects_previous (
422 E_MAIL_READER (object)));
423 return;
426 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
429 static void
430 mail_paned_view_dispose (GObject *object)
432 EMailPanedViewPrivate *priv;
434 priv = E_MAIL_PANED_VIEW_GET_PRIVATE (object);
436 e_mail_reader_dispose (E_MAIL_READER (object));
438 if (priv->paned != NULL) {
439 g_object_unref (priv->paned);
440 priv->paned = NULL;
443 if (priv->scrolled_window != NULL) {
444 g_object_unref (priv->scrolled_window);
445 priv->scrolled_window = NULL;
448 if (priv->message_list != NULL) {
449 g_object_unref (priv->message_list);
450 priv->message_list = NULL;
453 if (priv->preview_pane != NULL) {
454 g_object_unref (priv->preview_pane);
455 priv->preview_pane = NULL;
458 if (priv->view_instance != NULL) {
459 g_object_unref (priv->view_instance);
460 priv->view_instance = NULL;
463 priv->display = NULL;
465 /* Chain up to parent's dispose() method. */
466 G_OBJECT_CLASS (e_mail_paned_view_parent_class)->dispose (object);
469 static GtkActionGroup *
470 mail_paned_view_get_action_group (EMailReader *reader,
471 EMailReaderActionGroup group)
473 EMailView *view;
474 EShellView *shell_view;
475 EShellWindow *shell_window;
476 const gchar *group_name;
478 view = E_MAIL_VIEW (reader);
479 shell_view = e_mail_view_get_shell_view (view);
480 shell_window = e_shell_view_get_shell_window (shell_view);
482 switch (group) {
483 case E_MAIL_READER_ACTION_GROUP_STANDARD:
484 group_name = "mail";
485 break;
486 case E_MAIL_READER_ACTION_GROUP_SEARCH_FOLDERS:
487 group_name = "search-folders";
488 break;
489 default:
490 g_return_val_if_reached (NULL);
493 return e_shell_window_get_action_group (shell_window, group_name);
496 static EAlertSink *
497 mail_paned_view_get_alert_sink (EMailReader *reader)
499 EMailView *view;
500 EShellView *shell_view;
501 EShellContent *shell_content;
503 view = E_MAIL_VIEW (reader);
504 shell_view = e_mail_view_get_shell_view (view);
505 shell_content = e_shell_view_get_shell_content (shell_view);
507 return E_ALERT_SINK (shell_content);
510 static EMailBackend *
511 mail_paned_view_get_backend (EMailReader *reader)
513 EMailView *view;
514 EShellView *shell_view;
515 EShellBackend *shell_backend;
517 view = E_MAIL_VIEW (reader);
518 shell_view = e_mail_view_get_shell_view (view);
519 shell_backend = e_shell_view_get_shell_backend (shell_view);
521 return E_MAIL_BACKEND (shell_backend);
524 static EMailDisplay *
525 mail_paned_view_get_mail_display (EMailReader *reader)
527 EMailPanedViewPrivate *priv;
529 priv = E_MAIL_PANED_VIEW (reader)->priv;
531 return priv->display;
534 static gboolean
535 mail_paned_view_get_hide_deleted (EMailReader *reader)
537 return !e_mail_view_get_show_deleted (E_MAIL_VIEW (reader));
540 static GtkWidget *
541 mail_paned_view_get_message_list (EMailReader *reader)
543 EMailPanedView *paned_view;
545 paned_view = E_MAIL_PANED_VIEW (reader);
547 return paned_view->priv->message_list;
550 static GtkMenu *
551 mail_paned_view_get_popup_menu (EMailReader *reader)
553 EMailView *view;
554 EShellView *shell_view;
555 EShellWindow *shell_window;
556 GtkUIManager *ui_manager;
557 GtkWidget *widget;
559 view = E_MAIL_VIEW (reader);
560 shell_view = e_mail_view_get_shell_view (view);
561 shell_window = e_shell_view_get_shell_window (shell_view);
563 ui_manager = e_shell_window_get_ui_manager (shell_window);
564 widget = gtk_ui_manager_get_widget (ui_manager, "/mail-preview-popup");
566 return GTK_MENU (widget);
569 static EPreviewPane *
570 mail_paned_view_get_preview_pane (EMailReader *reader)
572 EMailPanedView *paned_view;
574 paned_view = E_MAIL_PANED_VIEW (reader);
576 return E_PREVIEW_PANE (paned_view->priv->preview_pane);
579 static GtkWindow *
580 mail_paned_view_get_window (EMailReader *reader)
582 EMailView *view;
583 EShellView *shell_view;
584 EShellWindow *shell_window;
586 view = E_MAIL_VIEW (reader);
587 shell_view = e_mail_view_get_shell_view (view);
588 shell_window = e_shell_view_get_shell_window (shell_view);
590 return GTK_WINDOW (shell_window);
593 static void
594 mail_paned_view_set_folder (EMailReader *reader,
595 CamelFolder *folder)
597 EMailPanedViewPrivate *priv;
598 EMailView *view;
599 EShell *shell;
600 EShellView *shell_view;
601 EShellWindow *shell_window;
602 GSettings *settings;
603 EMailReaderInterface *default_interface;
604 GtkWidget *message_list;
605 GKeyFile *key_file;
606 CamelFolder *previous_folder;
607 gchar *folder_uri;
608 gchar *group_name;
609 const gchar *key;
610 gboolean value, global_view_setting;
611 GError *error = NULL;
613 priv = E_MAIL_PANED_VIEW_GET_PRIVATE (reader);
615 view = E_MAIL_VIEW (reader);
616 shell_view = e_mail_view_get_shell_view (view);
618 /* Can be NULL, if the shell window was closed meanwhile */
619 if (!shell_view)
620 return;
622 previous_folder = e_mail_reader_ref_folder (reader);
623 if (previous_folder == folder) {
624 g_clear_object (&previous_folder);
625 return;
628 g_clear_object (&previous_folder);
630 shell_window = e_shell_view_get_shell_window (shell_view);
632 shell = e_shell_window_get_shell (shell_window);
634 settings = e_util_ref_settings ("org.gnome.evolution.mail");
636 /* FIXME This should be an EMailReader property. */
637 global_view_setting = g_settings_get_boolean (
638 settings, "global-view-setting");
640 message_list = e_mail_reader_get_message_list (reader);
642 message_list_freeze (MESSAGE_LIST (message_list));
644 /* Chain up to interface's default set_folder() method. */
645 default_interface = g_type_default_interface_peek (E_TYPE_MAIL_READER);
646 default_interface->set_folder (reader, folder);
648 if (folder == NULL)
649 goto exit;
651 /* Only refresh the folder if we're online. */
652 if (e_shell_get_online (shell))
653 e_mail_reader_refresh_folder (reader, folder);
655 /* This is a one-time-only callback. */
656 if (MESSAGE_LIST (message_list)->cursor_uid == NULL &&
657 priv->message_list_built_id == 0)
658 priv->message_list_built_id = g_signal_connect_swapped (
659 message_list, "message-list-built",
660 G_CALLBACK (mail_paned_view_message_list_built_cb),
661 reader);
663 /* Restore the folder's preview and threaded state. */
665 folder_uri = e_mail_folder_uri_from_folder (folder);
666 key_file = e_shell_view_get_state_key_file (shell_view);
667 group_name = g_strdup_printf ("Folder %s", folder_uri);
668 g_free (folder_uri);
670 key = STATE_KEY_GROUP_BY_THREADS;
671 value = g_key_file_get_boolean (key_file, global_view_setting ? STATE_GROUP_GLOBAL_FOLDER : group_name, key, &error);
672 if (error != NULL) {
673 g_clear_error (&error);
675 value = !global_view_setting ||
676 g_key_file_get_boolean (key_file, STATE_GROUP_GLOBAL_FOLDER, key, &error);
677 if (error != NULL) {
678 g_clear_error (&error);
679 value = TRUE;
683 e_mail_reader_set_group_by_threads (reader, value);
685 key = STATE_KEY_PREVIEW_VISIBLE;
686 value = g_key_file_get_boolean (key_file, global_view_setting ? STATE_GROUP_GLOBAL_FOLDER : group_name, key, &error);
687 if (error != NULL) {
688 g_clear_error (&error);
690 value = !global_view_setting ||
691 g_key_file_get_boolean (key_file, STATE_GROUP_GLOBAL_FOLDER, key, &error);
692 if (error != NULL) {
693 g_clear_error (&error);
694 value = TRUE;
698 /* XXX This is a little confusing and needs rethought. The
699 * EShellWindow:safe-mode property blocks automatic message
700 * selection, but the "safe-list" setting blocks both the
701 * preview pane and automatic message selection. */
702 if (g_settings_get_boolean (settings, "safe-list")) {
703 g_settings_set_boolean (settings, "safe-list", FALSE);
704 e_shell_window_set_safe_mode (shell_window, TRUE);
705 value = FALSE;
708 e_mail_view_set_preview_visible (E_MAIL_VIEW (reader), value);
710 g_free (group_name);
712 exit:
713 message_list_thaw (MESSAGE_LIST (message_list));
715 g_object_unref (settings);
718 static guint
719 mail_paned_view_reader_open_selected_mail (EMailReader *reader)
721 EMailPanedView *paned_view;
722 EMailPanedViewClass *class;
724 paned_view = E_MAIL_PANED_VIEW (reader);
726 class = E_MAIL_PANED_VIEW_GET_CLASS (paned_view);
727 g_return_val_if_fail (class->open_selected_mail != NULL, 0);
729 return class->open_selected_mail (paned_view);
732 static void
733 mail_paned_view_constructed (GObject *object)
735 EMailPanedViewPrivate *priv;
736 EShellBackend *shell_backend;
737 EShellWindow *shell_window;
738 EShellView *shell_view;
739 GSettings *settings;
740 EMailReader *reader;
741 EMailBackend *backend;
742 EMailSession *session;
743 EMailView *view;
744 GtkWidget *message_list;
745 GtkWidget *container;
746 GtkWidget *widget, *vbox;
748 priv = E_MAIL_PANED_VIEW_GET_PRIVATE (object);
750 view = E_MAIL_VIEW (object);
751 shell_view = e_mail_view_get_shell_view (view);
752 shell_window = e_shell_view_get_shell_window (shell_view);
753 shell_backend = e_shell_view_get_shell_backend (shell_view);
755 backend = E_MAIL_BACKEND (shell_backend);
756 session = e_mail_backend_get_session (backend);
758 priv->display = g_object_new (E_TYPE_MAIL_DISPLAY,
759 "headers-collapsable", TRUE,
760 "remote-content", e_mail_backend_get_remote_content (backend),
761 NULL);
763 /* FIXME This should be an EMailPanedView property, so
764 * it can be configured from the settings module. */
766 settings = e_util_ref_settings ("org.gnome.evolution.mail");
768 g_settings_bind (
769 settings, "headers-collapsed",
770 priv->display, "headers-collapsed",
771 G_SETTINGS_BIND_DEFAULT);
773 g_object_unref (settings);
775 /* Build content widgets. */
777 container = GTK_WIDGET (object);
779 widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
780 e_paned_set_fixed_resize (E_PANED (widget), FALSE);
781 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
782 priv->paned = g_object_ref (widget);
783 gtk_widget_show (widget);
785 e_binding_bind_property (
786 object, "orientation",
787 widget, "orientation",
788 G_BINDING_SYNC_CREATE);
790 container = priv->paned;
792 widget = gtk_scrolled_window_new (NULL, NULL);
793 gtk_scrolled_window_set_policy (
794 GTK_SCROLLED_WINDOW (widget),
795 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
796 gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
797 priv->scrolled_window = g_object_ref (widget);
798 gtk_widget_show (widget);
800 container = widget;
802 widget = message_list_new (session);
803 gtk_container_add (GTK_CONTAINER (container), widget);
804 priv->message_list = g_object_ref (widget);
805 gtk_widget_show (widget);
807 container = priv->paned;
809 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
810 widget = e_preview_pane_new (E_WEB_VIEW (priv->display));
812 gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
813 gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (e_mail_display_get_attachment_view (priv->display)), FALSE, FALSE, 0);
815 gtk_paned_pack2 (GTK_PANED (container), vbox, FALSE, FALSE);
816 priv->preview_pane = g_object_ref (widget);
817 gtk_widget_show (GTK_WIDGET (priv->display));
818 gtk_widget_show (widget);
820 e_binding_bind_property (
821 object, "preview-visible",
822 widget, "visible",
823 G_BINDING_SYNC_CREATE);
825 e_binding_bind_property (
826 object, "preview-visible",
827 vbox, "visible",
828 G_BINDING_SYNC_CREATE);
830 /* Load the view instance. */
832 e_mail_view_update_view_instance (E_MAIL_VIEW (object));
834 /* Message list customizations. */
836 e_mail_reader_init (E_MAIL_READER (object), FALSE, TRUE);
838 reader = E_MAIL_READER (object);
839 message_list = e_mail_reader_get_message_list (reader);
841 g_signal_connect_swapped (
842 message_list, "message-selected",
843 G_CALLBACK (mail_paned_view_message_selected_cb),
844 object);
846 /* Restore pane positions from the last session once
847 * the shell view is fully initialized and visible. */
848 g_signal_connect (
849 shell_window, "shell-view-created::mail",
850 G_CALLBACK (mail_paned_view_restore_state_cb),
851 object);
853 /* Do this after creating the message list. Our
854 * set_preview_visible() method relies on it. */
855 e_mail_view_set_preview_visible (view, TRUE);
857 e_mail_reader_connect_remote_content (reader);
859 e_extensible_load_extensions (E_EXTENSIBLE (object));
861 /* Chain up to parent's constructed() method. */
862 G_OBJECT_CLASS (e_mail_paned_view_parent_class)->constructed (object);
865 static void
866 mail_paned_view_set_search_strings (EMailView *view,
867 GSList *search_strings)
869 EMailDisplay *display;
870 EWebView *web_view;
871 EMailReader *reader;
873 reader = E_MAIL_READER (view);
874 display = e_mail_reader_get_mail_display (reader);
875 if (!display)
876 return;
878 web_view = E_WEB_VIEW (display);
880 e_web_view_clear_highlights (web_view);
882 while (search_strings != NULL) {
883 e_web_view_add_highlight (web_view, search_strings->data);
884 search_strings = g_slist_next (search_strings);
888 static GalViewInstance *
889 mail_paned_view_get_view_instance (EMailView *view)
891 EMailPanedView *paned_view;
893 paned_view = E_MAIL_PANED_VIEW (view);
895 return paned_view->priv->view_instance;
898 static gchar *
899 empv_create_view_id (CamelFolder *folder)
901 GChecksum *checksum;
902 gchar *res, *folder_uri;
904 g_return_val_if_fail (folder != NULL, NULL);
906 folder_uri = e_mail_folder_uri_from_folder (folder);
907 g_return_val_if_fail (folder_uri != NULL, NULL);
909 /* to be able to migrate previously saved views */
910 e_filename_make_safe (folder_uri);
912 /* use MD5 checksum of the folder URI, to not depend on its length */
913 checksum = g_checksum_new (G_CHECKSUM_MD5);
914 g_checksum_update (checksum, (const guchar *) folder_uri, -1);
916 res = g_strdup (g_checksum_get_string (checksum));
918 g_checksum_free (checksum);
919 g_free (folder_uri);
921 return res;
924 static gboolean
925 empv_folder_or_parent_is_outgoing (MailFolderCache *folder_cache,
926 CamelStore *store,
927 const gchar *fullname)
929 CamelFolderInfoFlags info_flags;
930 gchar *path, *dash;
931 gboolean res = FALSE;
933 g_return_val_if_fail (MAIL_IS_FOLDER_CACHE (folder_cache), FALSE);
934 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
935 g_return_val_if_fail (fullname != NULL, FALSE);
937 if (!mail_folder_cache_get_folder_info_flags (folder_cache, store, fullname, &info_flags))
938 info_flags = 0;
940 if ((info_flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_OUTBOX ||
941 (info_flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_SENT)
942 return TRUE;
944 dash = strrchr (fullname, '/');
945 if (!dash)
946 return FALSE;
948 path = g_strdup (fullname);
950 while (path && *path) {
951 dash = strrchr (path, '/');
952 if (!dash)
953 break;
955 *dash = '\0';
957 if (!mail_folder_cache_get_folder_info_flags (folder_cache, store, path, &info_flags))
958 continue;
960 if ((info_flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_OUTBOX ||
961 (info_flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_SENT) {
962 res = TRUE;
963 break;
967 g_free (path);
969 return res;
972 static void
973 mail_paned_view_update_view_instance (EMailView *view)
975 EMailPanedViewPrivate *priv;
976 EMailReader *reader;
977 EShell *shell;
978 EShellView *shell_view;
979 EShellWindow *shell_window;
980 EShellViewClass *shell_view_class;
981 ESourceRegistry *registry;
982 GalViewCollection *view_collection;
983 GalViewInstance *view_instance;
984 MailFolderCache *folder_cache;
985 CamelFolder *folder;
986 GtkOrientable *orientable;
987 GtkOrientation orientation;
988 GSettings *settings;
989 gboolean outgoing_folder;
990 gboolean show_vertical_view;
991 gboolean global_view_setting;
992 gchar *view_id;
994 priv = E_MAIL_PANED_VIEW_GET_PRIVATE (view);
996 shell_view = e_mail_view_get_shell_view (view);
997 shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
998 view_collection = shell_view_class->view_collection;
1000 shell_window = e_shell_view_get_shell_window (shell_view);
1001 shell = e_shell_window_get_shell (shell_window);
1002 registry = e_shell_get_registry (shell);
1004 reader = E_MAIL_READER (view);
1005 folder = e_mail_reader_ref_folder (reader);
1007 /* If no folder is selected, return silently. */
1008 if (folder == NULL)
1009 return;
1011 if (priv->view_instance != NULL) {
1012 g_object_unref (priv->view_instance);
1013 priv->view_instance = NULL;
1016 view_id = empv_create_view_id (folder);
1017 e_filename_make_safe (view_id);
1019 folder_cache = e_mail_session_get_folder_cache (e_mail_backend_get_session (e_mail_reader_get_backend (reader)));
1021 outgoing_folder =
1022 empv_folder_or_parent_is_outgoing (folder_cache, camel_folder_get_parent_store (folder), camel_folder_get_full_name (folder)) ||
1023 em_utils_folder_is_drafts (registry, folder) ||
1024 em_utils_folder_is_outbox (registry, folder) ||
1025 em_utils_folder_is_sent (registry, folder);
1027 settings = e_util_ref_settings ("org.gnome.evolution.mail");
1028 global_view_setting = g_settings_get_boolean (
1029 settings, "global-view-setting");
1030 g_object_unref (settings);
1032 if (global_view_setting) {
1033 if (outgoing_folder) {
1034 view_instance = e_shell_view_new_view_instance (
1035 shell_view, "global_view_sent_setting");
1036 } else {
1037 view_instance = e_shell_view_new_view_instance (
1038 shell_view, "global_view_setting");
1040 } else {
1041 view_instance = e_shell_view_new_view_instance (
1042 shell_view, view_id);
1045 priv->view_instance = g_object_ref (view_instance);
1047 orientable = GTK_ORIENTABLE (view);
1048 orientation = gtk_orientable_get_orientation (orientable);
1049 show_vertical_view =
1050 !global_view_setting &&
1051 (orientation == GTK_ORIENTATION_HORIZONTAL);
1053 if (show_vertical_view) {
1054 const gchar *user_directory;
1055 gchar *filename;
1057 /* Force the view instance into vertical view. */
1059 g_free (view_instance->custom_filename);
1060 g_free (view_instance->current_view_filename);
1062 user_directory = gal_view_collection_get_user_directory (
1063 view_collection);
1065 filename = g_strdup_printf (
1066 "custom_wide_view-%s.xml", view_id);
1067 view_instance->custom_filename =
1068 g_build_filename (user_directory, filename, NULL);
1069 g_free (filename);
1071 filename = g_strdup_printf (
1072 "current_wide_view-%s.xml", view_id);
1073 view_instance->current_view_filename =
1074 g_build_filename (user_directory, filename, NULL);
1075 g_free (filename);
1078 g_free (view_id);
1080 if (outgoing_folder) {
1081 if (show_vertical_view)
1082 gal_view_instance_set_default_view (
1083 view_instance, "Wide_View_Sent");
1084 else
1085 gal_view_instance_set_default_view (
1086 view_instance, "As_Sent_Folder");
1087 } else if (show_vertical_view) {
1088 gal_view_instance_set_default_view (
1089 view_instance, "Wide_View_Normal");
1092 gal_view_instance_load (view_instance);
1094 if (!gal_view_instance_exists (view_instance)) {
1095 gchar *state_filename;
1097 state_filename = mail_config_folder_to_cachename (
1098 folder, "et-header-");
1100 if (g_file_test (state_filename, G_FILE_TEST_IS_REGULAR)) {
1101 GalView *view;
1103 view = gal_view_etable_new ("");
1105 /* XXX This only stashes the filename in the view.
1106 * The state file is not actually loaded until
1107 * the MessageList is attached to the view. */
1108 gal_view_load (view, state_filename);
1110 gal_view_instance_set_custom_view (
1111 view_instance, view);
1113 g_object_unref (view);
1116 g_free (state_filename);
1119 g_signal_connect (
1120 view_instance, "display-view",
1121 G_CALLBACK (mail_paned_display_view_cb), view);
1123 mail_paned_display_view_cb (
1124 view_instance,
1125 gal_view_instance_get_current_view (view_instance),
1126 view);
1128 view_id = gal_view_instance_get_current_view_id (view_instance);
1129 e_shell_view_set_view_id (shell_view, view_id);
1130 g_free (view_id);
1132 g_object_unref (view_instance);
1134 g_clear_object (&folder);
1137 static void
1138 mail_paned_view_set_preview_visible (EMailView *view,
1139 gboolean preview_visible)
1141 EMailViewClass *parent_class;
1143 /* If we're showing the preview, tell EMailReader to reload the
1144 * selected message. This should force it to download the full
1145 * message if necessary, so we don't get an empty preview. */
1146 if (preview_visible) {
1147 EMailReader *reader;
1148 GtkWidget *message_list;
1149 const gchar *cursor_uid;
1151 reader = E_MAIL_READER (view);
1152 message_list = e_mail_reader_get_message_list (reader);
1153 cursor_uid = MESSAGE_LIST (message_list)->cursor_uid;
1155 if (cursor_uid != NULL)
1156 e_mail_reader_set_message (reader, cursor_uid);
1159 mail_paned_view_save_boolean (
1160 E_MAIL_VIEW (view),
1161 STATE_KEY_PREVIEW_VISIBLE, preview_visible);
1163 /* Chain up to parent's set_preview_visible() method. */
1164 parent_class = E_MAIL_VIEW_CLASS (e_mail_paned_view_parent_class);
1165 parent_class->set_preview_visible (view, preview_visible);
1168 static guint
1169 mail_paned_view_open_selected_mail (EMailPanedView *view)
1171 return e_mail_reader_open_selected (E_MAIL_READER (view));
1174 static void
1175 e_mail_paned_view_class_init (EMailPanedViewClass *class)
1177 GObjectClass *object_class;
1178 EMailViewClass *mail_view_class;
1180 g_type_class_add_private (class, sizeof (EMailPanedViewPrivate));
1182 object_class = G_OBJECT_CLASS (class);
1183 object_class->dispose = mail_paned_view_dispose;
1184 object_class->constructed = mail_paned_view_constructed;
1185 object_class->set_property = mail_paned_view_set_property;
1186 object_class->get_property = mail_paned_view_get_property;
1188 mail_view_class = E_MAIL_VIEW_CLASS (class);
1189 mail_view_class->set_search_strings = mail_paned_view_set_search_strings;
1190 mail_view_class->get_view_instance = mail_paned_view_get_view_instance;
1191 mail_view_class->update_view_instance = mail_paned_view_update_view_instance;
1193 mail_view_class->set_preview_visible = mail_paned_view_set_preview_visible;
1195 class->open_selected_mail = mail_paned_view_open_selected_mail;
1197 /* Inherited from EMailReader */
1198 g_object_class_override_property (
1199 object_class,
1200 PROP_FORWARD_STYLE,
1201 "forward-style");
1203 /* Inherited from EMailReader */
1204 g_object_class_override_property (
1205 object_class,
1206 PROP_GROUP_BY_THREADS,
1207 "group-by-threads");
1209 /* Inherited from EMailReader */
1210 g_object_class_override_property (
1211 object_class,
1212 PROP_REPLY_STYLE,
1213 "reply-style");
1215 /* Inherited from EMailReader */
1216 g_object_class_override_property (
1217 object_class,
1218 PROP_MARK_SEEN_ALWAYS,
1219 "mark-seen-always");
1221 /* Inherited from EMailReader */
1222 g_object_class_override_property (
1223 object_class,
1224 PROP_DELETE_SELECTS_PREVIOUS,
1225 "delete-selects-previous");
1228 static void
1229 e_mail_paned_view_reader_init (EMailReaderInterface *iface)
1231 iface->get_action_group = mail_paned_view_get_action_group;
1232 iface->get_alert_sink = mail_paned_view_get_alert_sink;
1233 iface->get_backend = mail_paned_view_get_backend;
1234 iface->get_mail_display = mail_paned_view_get_mail_display;
1235 iface->get_hide_deleted = mail_paned_view_get_hide_deleted;
1236 iface->get_message_list = mail_paned_view_get_message_list;
1237 iface->get_popup_menu = mail_paned_view_get_popup_menu;
1238 iface->get_preview_pane = mail_paned_view_get_preview_pane;
1239 iface->get_window = mail_paned_view_get_window;
1240 iface->set_folder = mail_paned_view_set_folder;
1241 iface->open_selected_mail = mail_paned_view_reader_open_selected_mail;
1244 static void
1245 e_mail_paned_view_init (EMailPanedView *view)
1247 view->priv = E_MAIL_PANED_VIEW_GET_PRIVATE (view);
1249 e_signal_connect_notify (
1250 view, "notify::group-by-threads",
1251 G_CALLBACK (mail_paned_view_notify_group_by_threads_cb),
1252 NULL);
1255 GtkWidget *
1256 e_mail_paned_view_new (EShellView *shell_view)
1258 g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
1260 return g_object_new (
1261 E_TYPE_MAIL_PANED_VIEW,
1262 "shell-view", shell_view, NULL);
1265 void
1266 e_mail_paned_view_hide_message_list_pane (EMailPanedView *view,
1267 gboolean visible)
1269 g_return_if_fail (E_IS_MAIL_PANED_VIEW (view));
1271 if (visible)
1272 gtk_widget_show (view->priv->scrolled_window);
1273 else
1274 gtk_widget_hide (view->priv->scrolled_window);
1277 GtkWidget *
1278 e_mail_paned_view_get_preview (EMailPanedView *view)
1280 g_return_val_if_fail (E_IS_MAIL_PANED_VIEW (view), NULL);
1282 return GTK_WIDGET (mail_paned_view_get_mail_display (E_MAIL_READER (view)));