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.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38 #include <tny-camel-mem-stream.h>
42 #include <modest-account-mgr.h>
43 #include <modest-account-mgr-helpers.h>
45 #include <widgets/modest-msg-edit-window.h>
46 #include <modest-selector-picker.h>
47 #include <widgets/modest-recpt-editor.h>
48 #include <widgets/modest-attachments-view.h>
50 #include <modest-runtime.h>
52 #include "modest-platform.h"
53 #include "modest-icon-names.h"
54 #include "modest-widget-memory.h"
55 #include "modest-window-priv.h"
56 #include "modest-mail-operation.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-tny-folder.h"
60 #include "modest-tny-account.h"
61 #include "modest-address-book.h"
62 #include "modest-text-utils.h"
63 #include <tny-simple-list.h>
64 #include <modest-wp-text-view.h>
65 #include <wptextbuffer.h>
66 #include <hildon/hildon-pannable-area.h>
67 #include <hildon/hildon-touch-selector.h>
68 #include <hildon/hildon-picker-dialog.h>
69 #include "modest-msg-edit-window-ui-dimming.h"
71 #include "modest-hildon-includes.h"
72 #ifdef MODEST_HAVE_HILDON0_WIDGETS
73 #include <hildon-widgets/hildon-color-chooser.h>
75 #include "widgets/modest-msg-edit-window-ui.h"
76 #ifdef MODEST_HAVE_HILDON0_WIDGETS
77 #include <libgnomevfs/gnome-vfs-mime-utils.h>
79 #include <libgnomevfs/gnome-vfs-mime.h>
81 #include <modest-utils.h>
82 #include "modest-maemo-utils.h"
83 #include <modest-ui-constants.h>
86 #define DEFAULT_FONT_SIZE 3
87 #define DEFAULT_FONT 2
88 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
89 #define DEFAULT_MAIN_VBOX_SPACING 6
90 #define SUBJECT_MAX_LENGTH 1000
91 #define IMAGE_MAX_WIDTH 560
92 #define DEFAULT_FONT_SCALE 1.5
93 #define ATTACHMENT_BUTTON_WIDTH 118
95 static gboolean is_wp_text_buffer_started = FALSE;
97 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
98 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
99 static void modest_msg_edit_window_finalize (GObject *obj);
101 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
102 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
103 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
105 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
106 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
107 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
108 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
109 GtkTextIter *start, GtkTextIter *end,
111 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
112 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
113 static void subject_field_insert_text (GtkEditable *editable,
115 gint new_text_length,
117 ModestMsgEditWindow *window);
118 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
122 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
123 ModestRecptEditor *editor);
124 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
125 ModestMsgEditWindow *window);
127 /* ModestWindow methods implementation */
128 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
129 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
130 gboolean show_toolbar);
131 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
133 ModestMsgEditWindow *window);
134 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
135 static void subject_field_move_cursor (GtkEntry *entry,
136 GtkMovementStep step,
140 static void update_window_title (ModestMsgEditWindow *window);
143 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
144 ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
149 GtkTextIter *match_start,
150 GtkTextIter *match_end);
152 static void remove_tags (WPTextBuffer *buffer);
154 static void on_account_removed (TnyAccountStore *account_store,
158 static void init_window (ModestMsgEditWindow *obj);
160 gboolean scroll_drag_timeout (gpointer userdata);
161 static void correct_scroll (ModestMsgEditWindow *w);
162 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
163 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
164 ModestMsgEditWindow *userdata);
165 static void text_buffer_mark_set (GtkTextBuffer *buffer,
168 ModestMsgEditWindow *userdata);
169 static void on_message_settings (GtkAction *action,
170 ModestMsgEditWindow *window);
171 static void setup_menu (ModestMsgEditWindow *self);
173 static void from_field_changed (HildonPickerButton *button,
174 ModestMsgEditWindow *self);
175 static void font_size_clicked (GtkToolButton *button,
176 ModestMsgEditWindow *window);
177 static void font_face_clicked (GtkToolButton *button,
178 ModestMsgEditWindow *window);
179 static void DEBUG_BUFFER (WPTextBuffer *buffer)
183 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
185 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
186 while (!gtk_text_iter_is_end (&iter)) {
187 GString *output = g_string_new ("");
188 GSList *toggled_tags;
191 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
192 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
193 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
194 GtkTextTag *tag = (GtkTextTag *) node->data;
196 g_object_get (G_OBJECT (tag), "name", &name, NULL);
197 output = g_string_append (output, name);
198 g_string_append (output, " ");
200 output = g_string_append (output, "] OPENED [ ");
201 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
202 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
203 GtkTextTag *tag = (GtkTextTag *) node->data;
205 g_object_get (G_OBJECT (tag), "name", &name, NULL);
206 output = g_string_append (output, name);
207 g_string_append (output, " ");
209 output = g_string_append (output, "]\n");
210 g_message ("%s", output->str);
211 g_string_free (output, TRUE);
212 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
214 g_message ("END BUFFER");
218 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
219 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
223 /* static gboolean */
224 /* on_key_pressed (GtkWidget *self, */
225 /* GdkEventKey *event, */
226 /* gpointer user_data); */
228 /* list my signals */
235 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
236 struct _ModestMsgEditWindowPrivate {
238 GtkWidget *header_box;
240 ModestPairList *from_field_protos;
241 GtkWidget *from_field;
242 gchar *last_from_account;
243 gchar *original_account_name;
247 GtkWidget *bcc_field;
248 GtkWidget *subject_field;
249 GtkWidget *attachments_view;
250 GtkWidget *priority_icon;
251 GtkWidget *subject_box;
252 GtkWidget *add_attachment_button;
254 GtkWidget *cc_caption;
255 GtkWidget *bcc_caption;
256 gboolean update_caption_visibility;
257 GtkWidget *attachments_caption;
259 GtkTextBuffer *text_buffer;
261 GtkWidget *font_size_toolitem;
262 GtkWidget *font_face_toolitem;
263 GtkWidget *font_color_button;
264 GtkWidget *font_color_toolitem;
265 GSList *font_items_group;
266 GtkTreeModel *faces_model;
267 gint current_face_index;
268 GtkWidget *font_tool_button_label;
269 GtkTreeModel *sizes_model;
270 gint current_size_index;
271 GtkWidget *size_tool_button_label;
273 GtkWidget *find_toolbar;
276 GtkWidget *font_dialog;
279 guint correct_scroll_idle;
280 guint scroll_drag_timeout_id;
284 TnyList *attachments;
289 TnyHeaderFlags priority_flags;
291 gboolean can_undo, can_redo;
292 gulong clipboard_change_handler_id;
293 gulong default_clipboard_change_handler_id;
294 gulong account_removed_handler_id;
295 guint clipboard_owner_idle;
296 gchar *clipboard_text;
305 GtkWidget *cc_button;
306 GtkWidget *bcc_button;
309 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
310 MODEST_TYPE_MSG_EDIT_WINDOW, \
311 ModestMsgEditWindowPrivate))
313 static GtkWindowClass *parent_class = NULL;
315 /* uncomment the following if you have defined any signals */
316 /* static guint signals[LAST_SIGNAL] = {0}; */
319 modest_msg_edit_window_get_type (void)
321 static GType my_type = 0;
323 static const GTypeInfo my_info = {
324 sizeof(ModestMsgEditWindowClass),
325 NULL, /* base init */
326 NULL, /* base finalize */
327 (GClassInitFunc) modest_msg_edit_window_class_init,
328 NULL, /* class finalize */
329 NULL, /* class data */
330 sizeof(ModestMsgEditWindow),
332 (GInstanceInitFunc) modest_msg_edit_window_init,
335 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
336 "ModestMsgEditWindow",
344 save_state (ModestWindow *self)
346 modest_widget_memory_save (modest_runtime_get_conf(),
347 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
352 restore_settings (ModestMsgEditWindow *self)
354 ModestConf *conf = NULL;
356 conf = modest_runtime_get_conf ();
358 /* Dim at start clipboard actions */
359 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
364 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
366 GObjectClass *gobject_class;
367 ModestWindowClass *modest_window_class;
368 gobject_class = (GObjectClass*) klass;
369 modest_window_class = (ModestWindowClass*) klass;
371 parent_class = g_type_class_peek_parent (klass);
372 gobject_class->finalize = modest_msg_edit_window_finalize;
374 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
375 modest_window_class->save_state_func = save_state;
376 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
378 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
382 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
384 ModestMsgEditWindowPrivate *priv;
385 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
387 priv->msg_body = NULL;
388 priv->from_field = NULL;
389 priv->to_field = NULL;
390 priv->cc_field = NULL;
391 priv->bcc_field = NULL;
392 priv->subject_field = NULL;
393 priv->attachments = TNY_LIST (tny_simple_list_new ());
394 priv->images = TNY_LIST (tny_simple_list_new ());
395 priv->images_size = 0;
396 priv->images_count = 0;
399 priv->cc_caption = NULL;
400 priv->bcc_caption = NULL;
401 priv->update_caption_visibility = FALSE;
403 priv->priority_flags = 0;
405 priv->find_toolbar = NULL;
406 priv->last_search = NULL;
408 priv->draft_msg = NULL;
409 priv->outbox_msg = NULL;
410 priv->msg_uid = NULL;
412 priv->can_undo = FALSE;
413 priv->can_redo = FALSE;
414 priv->clipboard_change_handler_id = 0;
415 priv->default_clipboard_change_handler_id = 0;
416 priv->account_removed_handler_id = 0;
417 priv->clipboard_owner_idle = 0;
418 priv->clipboard_text = NULL;
421 priv->scroll_drag_timeout_id = 0;
422 priv->correct_scroll_idle = 0;
423 priv->last_upper = 0.0;
425 priv->font_dialog = NULL;
426 priv->app_menu = NULL;
428 if (!is_wp_text_buffer_started) {
429 is_wp_text_buffer_started = TRUE;
430 wp_text_buffer_library_init ();
435 hildon_program_add_window (hildon_program_get_instance(),
441 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
443 static ModestPairList*
444 get_transports (void)
446 GSList *transports = NULL;
448 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
449 GSList *accounts = modest_account_mgr_account_names (account_mgr,
450 TRUE /* only enabled accounts. */);
452 GSList *cursor = accounts;
454 gchar *account_name = cursor->data;
455 gchar *from_string = NULL;
457 from_string = modest_account_mgr_get_from_string (account_mgr,
461 if (from_string && account_name) {
462 gchar *name = account_name;
463 ModestPair *pair = modest_pair_new ((gpointer) name,
464 (gpointer) from_string , TRUE);
465 transports = g_slist_prepend (transports, pair);
468 cursor = cursor->next;
470 g_slist_free (accounts); /* only free the accounts, not the elements,
471 * because they are used in the pairlist */
475 static void window_focus (GtkWindow *window,
479 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
483 scroll_drag_timeout (gpointer userdata)
485 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
486 ModestMsgEditWindowPrivate *priv;
488 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
490 correct_scroll_without_drag_check (win, TRUE);
492 priv->scroll_drag_timeout_id = 0;
498 correct_scroll_without_drag_check_idle (gpointer userdata)
500 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
501 ModestMsgEditWindowPrivate *priv;
503 GdkRectangle rectangle;
504 gint offset_min, offset_max;
508 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
510 insert = gtk_text_buffer_get_insert (priv->text_buffer);
511 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
513 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
514 offset_min = priv->msg_body->allocation.y + rectangle.y;
515 offset_max = offset_min + rectangle.height;
517 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
518 offset_min = MAX (offset_min - 48, 0);
519 offset_max = MIN (offset_max + 48, vadj->upper);
521 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
523 priv->correct_scroll_idle = 0;
528 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
530 ModestMsgEditWindowPrivate *priv;
532 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
534 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
537 if (priv->correct_scroll_idle > 0) {
541 priv->correct_scroll_idle = g_idle_add ((GSourceFunc) correct_scroll_without_drag_check_idle,
546 correct_scroll (ModestMsgEditWindow *w)
548 ModestMsgEditWindowPrivate *priv;
550 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
551 if (gtk_grab_get_current () == priv->msg_body) {
552 if (priv->scroll_drag_timeout_id == 0) {
553 priv->scroll_drag_timeout_id = g_timeout_add (500, (GSourceFunc) scroll_drag_timeout,
559 correct_scroll_without_drag_check (w, TRUE);
563 text_buffer_end_user_action (GtkTextBuffer *buffer,
564 ModestMsgEditWindow *userdata)
567 correct_scroll (userdata);
571 text_buffer_mark_set (GtkTextBuffer *buffer,
574 ModestMsgEditWindow *userdata)
576 gtk_text_buffer_begin_user_action (buffer);
577 gtk_text_buffer_end_user_action (buffer);
581 cut_clipboard_check (GtkTextView *text_view,
584 GtkTextBuffer *buffer;
586 buffer = gtk_text_view_get_buffer (text_view);
587 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
588 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
593 copy_clipboard_check (GtkTextView *text_view,
596 GtkTextBuffer *buffer;
598 buffer = gtk_text_view_get_buffer (text_view);
599 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
600 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
605 attachment_deleted (ModestAttachmentsView *attachments_view,
608 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
613 connect_signals (ModestMsgEditWindow *obj)
615 ModestMsgEditWindowPrivate *priv;
617 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
619 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
620 G_CALLBACK (text_buffer_refresh_attributes), obj);
621 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
622 G_CALLBACK (text_buffer_can_undo), obj);
623 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
624 G_CALLBACK (text_buffer_can_redo), obj);
625 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
626 G_CALLBACK (body_changed), obj);
627 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
628 G_CALLBACK (body_changed), obj);
629 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
630 G_CALLBACK (text_buffer_end_user_action), obj);
631 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
632 G_CALLBACK (text_buffer_mark_set), obj);
633 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
634 G_CALLBACK (text_buffer_apply_tag), obj);
635 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
636 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
637 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
638 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
639 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
640 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
642 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
643 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
644 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
645 G_CALLBACK (from_field_changed), obj);
647 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
648 G_CALLBACK (msg_body_focus), obj);
649 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
650 G_CALLBACK (msg_body_focus), obj);
651 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
652 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
653 "changed", G_CALLBACK (recpt_field_changed), obj);
654 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
655 "changed", G_CALLBACK (recpt_field_changed), obj);
656 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
657 "changed", G_CALLBACK (recpt_field_changed), obj);
658 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
659 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
660 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
662 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
663 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
665 priv->clipboard_change_handler_id =
666 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
667 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
668 priv->default_clipboard_change_handler_id =
669 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
670 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
672 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
673 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
674 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
678 init_wp_text_view_style ()
680 static gboolean initialized = FALSE;
683 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
689 init_window (ModestMsgEditWindow *obj)
691 GtkWidget *to_caption, *subject_caption;
692 GtkWidget *main_vbox;
693 GtkWidget *add_attachment_align;
694 ModestMsgEditWindowPrivate *priv;
695 GtkActionGroup *action_group;
696 ModestWindowPrivate *parent_priv;
697 GdkPixbuf *window_icon = NULL;
698 GError *error = NULL;
700 GtkSizeGroup *title_size_group;
701 GtkSizeGroup *value_size_group;
702 GtkWidget *attachment_icon;
703 GtkWidget *window_box;
704 GtkWidget *window_align;
705 #if (GTK_MINOR_VERSION >= 10)
706 GdkAtom deserialize_type;
709 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
710 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
712 parent_priv->ui_manager = gtk_ui_manager_new();
713 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
714 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
716 /* Add common actions */
717 gtk_action_group_add_actions (action_group,
718 modest_msg_edit_action_entries,
719 G_N_ELEMENTS (modest_msg_edit_action_entries),
721 gtk_action_group_add_actions (action_group,
722 hildon2_msg_edit_action_entries,
723 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
725 gtk_action_group_add_toggle_actions (action_group,
726 modest_msg_edit_toggle_action_entries,
727 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
729 gtk_action_group_add_radio_actions (action_group,
730 modest_msg_edit_alignment_radio_action_entries,
731 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
733 G_CALLBACK (modest_ui_actions_on_change_justify),
735 gtk_action_group_add_radio_actions (action_group,
736 modest_msg_edit_priority_action_entries,
737 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
739 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
741 gtk_action_group_add_radio_actions (action_group,
742 modest_msg_edit_file_format_action_entries,
743 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
744 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
745 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
747 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
748 g_object_unref (action_group);
750 /* Load the UI definition */
751 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
754 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
755 g_clear_error (&error);
758 /* Add accelerators */
759 gtk_window_add_accel_group (GTK_WINDOW (obj),
760 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
762 parent_priv->menubar = NULL;
764 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
765 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
767 /* Note: This ModestPairList* must exist for as long as the picker
768 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
769 * so it can't know how to manage its memory. */
770 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
771 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
773 modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group,
774 _("mail_va_from"), priv->from_field);
776 priv->to_field = modest_recpt_editor_new ();
777 priv->cc_field = modest_recpt_editor_new ();
778 priv->bcc_field = modest_recpt_editor_new ();
779 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
780 priv->priority_icon = gtk_image_new ();
781 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
782 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
783 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
784 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
785 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
786 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
787 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
788 priv->add_attachment_button = hildon_button_new (MODEST_EDITABLE_SIZE, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
789 gtk_widget_set_size_request (priv->add_attachment_button, ATTACHMENT_BUTTON_WIDTH, -1);
790 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
791 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
792 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
793 hildon_button_set_image (HILDON_BUTTON (priv->add_attachment_button), attachment_icon);
794 add_attachment_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
795 gtk_alignment_set_padding (GTK_ALIGNMENT (add_attachment_align), 0, 0, MODEST_MARGIN_DEFAULT, 0);
796 gtk_container_add (GTK_CONTAINER (add_attachment_align), priv->add_attachment_button);
797 gtk_box_pack_start (GTK_BOX (priv->subject_box), add_attachment_align, FALSE, FALSE, 0);
798 priv->attachments_view = modest_attachments_view_new (NULL);
799 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
800 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
802 priv->header_box = gtk_vbox_new (FALSE, 0);
804 to_caption = modest_maemo_utils_create_captioned_with_size_type
805 (title_size_group, value_size_group,
806 _("mail_va_to"), FALSE, priv->to_field,
807 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
808 priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type
809 (title_size_group, value_size_group,
810 _("mail_va_cc"), FALSE, priv->cc_field,
811 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
812 priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
813 (title_size_group, value_size_group,
814 _("mail_va_hotfix1"), FALSE, priv->bcc_field,
815 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
816 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
817 _("mail_va_subject"), FALSE, priv->subject_box);
818 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
819 _("mail_va_attachment"),
821 priv->attachments_view,
822 HILDON_SIZE_AUTO_WIDTH |
823 HILDON_SIZE_AUTO_HEIGHT);
824 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
825 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
826 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
827 g_object_unref (title_size_group);
828 g_object_unref (value_size_group);
830 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
831 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
832 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
833 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
834 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
835 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
836 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
838 init_wp_text_view_style ();
840 priv->msg_body = modest_wp_text_view_new ();
843 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
844 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
845 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
846 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
847 #if (GTK_MINOR_VERSION >= 10)
848 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
849 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
851 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
852 deserialize_type, TRUE);
854 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
856 priv->find_toolbar = hildon_find_toolbar_new (NULL);
857 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
859 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
861 priv->pannable = hildon_pannable_area_new ();
863 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
864 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
865 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
867 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
868 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
869 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
871 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
872 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox),
873 hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable)));
874 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
876 window_box = gtk_vbox_new (FALSE, 0);
877 gtk_container_add (GTK_CONTAINER(obj), window_box);
879 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
881 /* Set window icon */
882 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
884 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
885 g_object_unref (window_icon);
890 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
892 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
894 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
895 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
896 priv->clipboard_change_handler_id))
897 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
898 priv->clipboard_change_handler_id);
899 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
900 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
901 priv->default_clipboard_change_handler_id))
902 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
903 priv->default_clipboard_change_handler_id);
905 if (priv->account_removed_handler_id &&
906 g_signal_handler_is_connected (modest_runtime_get_account_store (),
907 priv->account_removed_handler_id))
908 g_signal_handler_disconnect(modest_runtime_get_account_store (),
909 priv->account_removed_handler_id);
913 modest_msg_edit_window_finalize (GObject *obj)
915 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
917 /* Sanity check: shouldn't be needed, the window mgr should
918 call this function before */
919 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
921 if (priv->font_dialog != NULL) {
922 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
925 if (priv->clipboard_text != NULL) {
926 g_free (priv->clipboard_text);
927 priv->clipboard_text = NULL;
930 if (priv->draft_msg != NULL) {
931 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
932 if (TNY_IS_HEADER (header)) {
933 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
934 modest_window_mgr_unregister_header (mgr, header);
936 g_object_unref (priv->draft_msg);
937 priv->draft_msg = NULL;
939 if (priv->outbox_msg != NULL) {
940 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
941 if (TNY_IS_HEADER (header)) {
942 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
943 modest_window_mgr_unregister_header (mgr, header);
945 g_object_unref (priv->outbox_msg);
946 priv->outbox_msg = NULL;
948 if (priv->correct_scroll_idle > 0) {
949 g_source_remove (priv->correct_scroll_idle);
950 priv->correct_scroll_idle = 0;
952 if (priv->scroll_drag_timeout_id > 0) {
953 g_source_remove (priv->scroll_drag_timeout_id);
954 priv->scroll_drag_timeout_id = 0;
956 if (priv->clipboard_owner_idle > 0) {
957 g_source_remove (priv->clipboard_owner_idle);
958 priv->clipboard_owner_idle = 0;
960 if (priv->original_account_name)
961 g_free (priv->original_account_name);
962 g_free (priv->msg_uid);
963 g_free (priv->last_search);
964 g_object_unref (priv->faces_model);
965 g_object_unref (priv->sizes_model);
966 g_object_unref (priv->attachments);
967 g_object_unref (priv->images);
969 /* This had to stay alive for as long as the picker that used it: */
970 modest_pair_list_free (priv->from_field_protos);
972 G_OBJECT_CLASS(parent_class)->finalize (obj);
976 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type, guint64 *stream_size)
978 GdkPixbufLoader *loader;
981 GError *error = NULL;
985 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
987 if (loader == NULL) {
993 tny_stream_reset (TNY_STREAM (stream));
994 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
995 unsigned char read_buffer[128];
997 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
999 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1004 gdk_pixbuf_loader_close (loader, &error);
1007 g_error_free (error);
1008 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1010 g_object_ref (pixbuf);
1011 g_object_unref (loader);
1016 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1017 GdkPixbuf *new_pixbuf;
1019 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1020 gdk_pixbuf_get_width (pixbuf);
1021 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1022 g_object_unref (pixbuf);
1023 pixbuf = new_pixbuf;
1027 *stream_size = size;
1033 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1035 ModestMsgEditWindowPrivate *priv;
1038 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1040 for (iter = tny_list_create_iterator (attachments);
1041 !tny_iterator_is_done (iter);
1042 tny_iterator_next (iter)) {
1043 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1044 const gchar *cid = tny_mime_part_get_content_id (part);
1045 const gchar *mime_type = tny_mime_part_get_content_type (part);
1046 if ((cid != NULL)&&(mime_type != NULL)) {
1047 guint64 stream_size;
1048 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1049 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
1052 g_object_unref (stream);
1054 if (pixbuf != NULL) {
1055 priv->images_count ++;
1056 priv->images_size += stream_size;
1057 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1058 g_object_unref (pixbuf);
1061 g_object_unref (part);
1063 g_object_unref (iter);
1067 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1069 TnyMimePart *parent = NULL;
1070 const gchar *content_type = NULL;
1071 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1073 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1075 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1076 parent = g_object_ref (msg);
1077 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1078 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1081 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1082 iter = tny_list_create_iterator (parts);
1083 while (!tny_iterator_is_done (iter)) {
1085 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1086 content_type = tny_mime_part_get_content_type (part);
1087 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1091 g_object_unref (part);
1093 tny_iterator_next (iter);
1095 g_object_unref (iter);
1096 g_object_unref (parts);
1099 if (parent != NULL) {
1100 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1103 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1104 iter = tny_list_create_iterator (parts);
1105 while (!tny_iterator_is_done (iter)) {
1107 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1108 content_type = tny_mime_part_get_content_type (part);
1109 if (content_type && g_str_has_prefix (content_type, "image/")) {
1110 tny_list_prepend (priv->images, (GObject *) part);
1112 g_object_unref (part);
1113 tny_iterator_next (iter);
1115 g_object_unref (iter);
1116 g_object_unref (parts);
1117 g_object_unref (parent);
1122 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1125 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1127 for (iter = tny_list_create_iterator (attachments) ;
1128 !tny_iterator_is_done (iter);
1129 tny_iterator_next (iter)) {
1130 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1131 const gchar *cid = tny_mime_part_get_content_id (part);
1133 char *invalid = NULL;
1134 gint int_cid = strtol (cid, &invalid, 10);
1135 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1136 priv->next_cid = int_cid + 1;
1139 g_object_unref (part);
1141 g_object_unref (iter);
1145 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1148 gchar *to, *cc, *bcc, *subject;
1150 ModestMsgEditWindowPrivate *priv;
1151 ModestWindowPrivate *parent_priv;
1153 TnyHeaderFlags priority_flags;
1154 TnyFolder *msg_folder;
1155 gboolean is_html = FALSE;
1156 gboolean field_view_set;
1158 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1159 g_return_if_fail (TNY_IS_MSG (msg));
1161 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1162 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1164 header = tny_msg_get_header (msg);
1165 to = tny_header_dup_to (header);
1166 cc = tny_header_dup_cc (header);
1167 bcc = tny_header_dup_bcc (header);
1168 subject = tny_header_dup_subject (header);
1169 priority_flags = tny_header_get_priority (header);
1172 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1174 field_view_set = TRUE;
1176 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1177 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1178 gtk_widget_show (priv->cc_caption);
1179 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1180 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1181 gtk_widget_hide (priv->cc_caption);
1182 field_view_set = FALSE;
1184 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1186 field_view_set = TRUE;
1188 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1189 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1190 gtk_widget_show (priv->bcc_caption);
1191 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1192 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1193 gtk_widget_hide (priv->bcc_caption);
1194 field_view_set = FALSE;
1196 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1200 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1201 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1204 update_window_title (self);
1206 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1207 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1209 if ((body == NULL)||(body[0] == '\0')) {
1211 body = modest_text_utils_convert_to_html ("");
1214 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1215 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1218 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1221 /* Add attachments to the view */
1222 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1223 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1224 if (tny_list_get_length (priv->attachments) == 0) {
1225 gtk_widget_hide (priv->attachments_caption);
1227 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1228 gtk_widget_show_all (priv->attachments_caption);
1230 get_related_images (self, msg);
1231 update_next_cid (self, priv->attachments);
1232 update_next_cid (self, priv->images);
1233 replace_with_images (self, priv->images);
1235 if (preserve_is_rich && !is_html) {
1236 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1237 /* Get the default format required from configuration */
1238 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1239 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1242 /* Set the default focus depending on having already a To: field or not */
1243 if ((!to)||(*to == '\0')) {
1244 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1246 gtk_widget_grab_focus (priv->msg_body);
1249 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1251 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1252 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1254 modest_msg_edit_window_set_modified (self, FALSE);
1256 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1257 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1258 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1259 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1261 if (priv->msg_uid) {
1262 g_free (priv->msg_uid);
1263 priv->msg_uid = NULL;
1266 /* we should set a reference to the incoming message if it is a draft */
1267 msg_folder = tny_msg_get_folder (msg);
1269 if (modest_tny_folder_is_local_folder (msg_folder)) {
1270 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1271 if (type == TNY_FOLDER_TYPE_INVALID)
1272 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1274 if (type == TNY_FOLDER_TYPE_DRAFTS)
1275 priv->draft_msg = g_object_ref(msg);
1276 if (type == TNY_FOLDER_TYPE_OUTBOX)
1277 priv->outbox_msg = g_object_ref(msg);
1278 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1280 g_object_unref (msg_folder);
1291 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1293 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1294 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1295 GtkWidget *placeholder;
1296 GtkWidget *tool_item;
1301 GtkWidget *sizes_menu;
1302 GtkWidget *fonts_menu;
1306 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1307 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1308 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1309 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1311 /* Font color placeholder */
1312 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1313 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1316 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1317 priv->font_color_button = hildon_color_button_new ();
1318 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1319 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1320 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1321 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1322 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1323 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1324 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1325 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1327 G_CALLBACK (modest_msg_edit_window_color_button_change),
1330 /* Font size and face placeholder */
1331 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1332 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1334 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1335 priv->size_tool_button_label = gtk_label_new (NULL);
1336 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1337 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1338 size_text, "</span>", NULL);
1339 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1341 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1342 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1343 sizes_menu = gtk_menu_new ();
1344 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1345 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1348 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1349 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1351 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1355 if (wp_font_size[size_index] == 12)
1356 priv->current_size_index = size_index;
1360 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1361 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1362 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1363 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1364 priv->font_size_toolitem = tool_item;
1367 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1368 priv->font_tool_button_label = gtk_label_new (NULL);
1369 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1370 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1372 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1373 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1374 fonts_menu = gtk_menu_new ();
1375 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1376 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1379 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1381 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1382 0, wp_get_font_name (font_index),
1385 if (font_index == DEFAULT_FONT)
1386 priv->current_face_index = font_index;
1388 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1389 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1390 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1391 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1392 priv->font_face_toolitem = tool_item;
1394 /* Set expand and homogeneous for remaining items */
1395 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1396 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1397 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1398 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1399 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1400 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1401 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1402 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1403 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1405 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1406 will not show the tool items added to the placeholders) */
1407 gtk_widget_show_all (parent_priv->toolbar);
1409 /* Set the no show all *after* showing all items. We do not
1410 want the toolbar to be shown with a show all because it
1411 could go agains the gconf setting regarding showing or not
1412 the toolbar of the editor window */
1413 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1419 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1422 ModestWindowPrivate *parent_priv;
1423 ModestMsgEditWindowPrivate *priv;
1424 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1425 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1426 ModestWindowMgr *mgr = NULL;
1428 g_return_val_if_fail (msg, NULL);
1429 g_return_val_if_fail (account_name, NULL);
1431 mgr = modest_runtime_get_window_mgr ();
1433 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1435 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1436 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1438 /* Menubar. Update the state of some toggles */
1439 priv->from_field_protos = get_transports ();
1440 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1441 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1442 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1443 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1445 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1446 hildon_touch_selector_get_current_text
1447 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1448 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1449 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1452 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1454 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1456 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1458 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1460 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1461 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1462 /* Add common dimming rules */
1463 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1464 modest_msg_edit_window_toolbar_dimming_entries,
1465 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1466 MODEST_WINDOW (obj));
1467 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1468 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1469 MODEST_WINDOW (obj));
1470 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1471 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1472 MODEST_WINDOW (obj));
1473 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1474 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1475 MODEST_WINDOW (obj));
1476 /* Insert dimming rules group for this window */
1477 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1478 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1480 /* Setup app menu */
1481 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1483 /* Checks the dimming rules */
1484 g_object_unref (toolbar_rules_group);
1485 g_object_unref (clipboard_rules_group);
1486 gtk_widget_hide (priv->priority_icon);
1487 gtk_widget_queue_resize (priv->subject_box);
1488 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1490 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1492 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1493 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1494 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1495 priv->update_caption_visibility = TRUE;
1497 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1499 /* Track account-removed signal, this window should be closed
1500 in the case we're creating a mail associated to the account
1502 priv->account_removed_handler_id =
1503 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1505 G_CALLBACK(on_account_removed),
1508 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1510 return (ModestWindow*) obj;
1514 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1516 GString **string_buffer = (GString **) user_data;
1518 *string_buffer = g_string_append (*string_buffer, buffer);
1524 * @result: A new string which should be freed with g_free().
1527 get_formatted_data (ModestMsgEditWindow *edit_window)
1529 ModestMsgEditWindowPrivate *priv;
1530 GString *string_buffer = g_string_new ("");
1532 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1534 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1536 modest_text_utils_hyperlinkify (string_buffer);
1538 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1540 return g_string_free (string_buffer, FALSE);
1545 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1548 const gchar *account_name;
1549 ModestMsgEditWindowPrivate *priv;
1550 TnyIterator *att_iter;
1552 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1554 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1556 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1557 g_return_val_if_fail (account_name, NULL);
1560 /* don't free these (except from) */
1561 data = g_slice_new0 (MsgData);
1562 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1564 data->account_name = g_strdup (account_name);
1565 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1566 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1567 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1568 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1569 if (priv->draft_msg) {
1570 data->draft_msg = g_object_ref (priv->draft_msg);
1571 } else if (priv->outbox_msg) {
1572 data->draft_msg = g_object_ref (priv->outbox_msg);
1574 data->draft_msg = NULL;
1577 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1579 gtk_text_buffer_get_bounds (buf, &b, &e);
1580 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1582 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1583 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1585 data->html_body = NULL;
1587 /* deep-copy the data */
1588 att_iter = tny_list_create_iterator (priv->attachments);
1589 data->attachments = NULL;
1590 while (!tny_iterator_is_done (att_iter)) {
1591 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1592 if (!(TNY_IS_MIME_PART(part))) {
1593 g_warning ("strange data in attachment list");
1594 g_object_unref (part);
1595 tny_iterator_next (att_iter);
1598 data->attachments = g_list_append (data->attachments,
1600 tny_iterator_next (att_iter);
1602 g_object_unref (att_iter);
1604 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1605 att_iter = tny_list_create_iterator (priv->images);
1606 data->images = NULL;
1607 while (!tny_iterator_is_done (att_iter)) {
1608 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1610 if (!(TNY_IS_MIME_PART(part))) {
1611 g_warning ("strange data in attachment list");
1612 g_object_unref (part);
1613 tny_iterator_next (att_iter);
1616 cid = tny_mime_part_get_content_id (part);
1618 gchar *image_tag_id;
1619 GtkTextTag *image_tag;
1621 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1622 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1623 g_free (image_tag_id);
1625 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1627 ((gtk_text_iter_has_tag (&iter, image_tag))||
1628 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1629 data->images = g_list_append (data->images,
1630 g_object_ref (part));
1632 g_object_unref (part);
1633 tny_iterator_next (att_iter);
1635 g_object_unref (att_iter);
1637 data->priority_flags = priv->priority_flags;
1644 unref_gobject (GObject *obj, gpointer data)
1646 if (!G_IS_OBJECT(obj))
1648 g_object_unref (obj);
1652 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1655 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1663 g_free (data->from);
1664 g_free (data->subject);
1665 g_free (data->plain_body);
1666 g_free (data->html_body);
1667 g_free (data->account_name);
1669 if (data->draft_msg != NULL) {
1670 g_object_unref (data->draft_msg);
1671 data->draft_msg = NULL;
1674 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1675 g_list_free (data->attachments);
1676 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1677 g_list_free (data->images);
1679 g_slice_free (MsgData, data);
1683 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1685 guint64 *parts_size)
1687 ModestMsgEditWindowPrivate *priv;
1689 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1691 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1693 /* TODO: add images */
1694 *parts_size += priv->images_size;
1695 *parts_count += priv->images_count;
1700 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1703 ModestMsgEditWindowPrivate *priv = NULL;
1704 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1706 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1708 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1710 return MODEST_MSG_EDIT_FORMAT_HTML;
1712 return MODEST_MSG_EDIT_FORMAT_TEXT;
1716 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1717 ModestMsgEditFormat format)
1719 ModestMsgEditWindowPrivate *priv;
1721 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1722 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1725 case MODEST_MSG_EDIT_FORMAT_HTML:
1726 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1728 case MODEST_MSG_EDIT_FORMAT_TEXT:
1729 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1732 g_return_if_reached ();
1736 ModestMsgEditFormatState *
1737 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1739 ModestMsgEditFormatState *format_state = NULL;
1740 ModestMsgEditWindowPrivate *priv;
1741 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1743 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1744 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1746 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1748 format_state = g_new0 (ModestMsgEditFormatState, 1);
1749 format_state->bold = buffer_format->bold&0x1;
1750 format_state->italics = buffer_format->italic&0x1;
1751 format_state->bullet = buffer_format->bullet&0x1;
1752 format_state->color = buffer_format->color;
1753 format_state->font_size = buffer_format->font_size;
1754 format_state->font_family = wp_get_font_name (buffer_format->font);
1755 format_state->justification = buffer_format->justification;
1756 g_free (buffer_format);
1758 return format_state;
1763 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1764 const ModestMsgEditFormatState *format_state)
1766 ModestMsgEditWindowPrivate *priv;
1767 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1768 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1769 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1770 g_return_if_fail (format_state != NULL);
1772 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1773 gtk_widget_grab_focus (priv->msg_body);
1774 buffer_format->bold = (format_state->bold != FALSE);
1775 buffer_format->italic = (format_state->italics != FALSE);
1776 buffer_format->color = format_state->color;
1777 buffer_format->font_size = format_state->font_size;
1778 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1779 buffer_format->justification = format_state->justification;
1780 buffer_format->bullet = format_state->bullet;
1782 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1784 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1785 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1786 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1787 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1788 buffer_format->cs.font = (buffer_format->font != current_format->font);
1789 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1790 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1792 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1793 if (buffer_format->cs.bold) {
1794 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1795 GINT_TO_POINTER (buffer_format->bold&0x1));
1797 if (buffer_format->cs.italic) {
1798 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1799 GINT_TO_POINTER (buffer_format->italic&0x1));
1801 if (buffer_format->cs.color) {
1802 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1803 GINT_TO_POINTER (&(buffer_format->color)));
1805 if (buffer_format->cs.font_size) {
1806 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1807 GINT_TO_POINTER (buffer_format->font_size));
1809 if (buffer_format->cs.justification) {
1810 switch (buffer_format->justification) {
1811 case GTK_JUSTIFY_LEFT:
1812 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1813 GINT_TO_POINTER(TRUE));
1815 case GTK_JUSTIFY_CENTER:
1816 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1817 GINT_TO_POINTER(TRUE));
1819 case GTK_JUSTIFY_RIGHT:
1820 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1821 GINT_TO_POINTER(TRUE));
1828 if (buffer_format->cs.font) {
1829 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1830 GINT_TO_POINTER (buffer_format->font));
1832 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1833 if (buffer_format->cs.bullet) {
1834 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1835 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1837 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1839 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1841 g_free (buffer_format);
1842 g_free (current_format);
1844 /* Check dimming rules */
1845 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1846 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1850 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1852 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1854 ModestWindowPrivate *parent_priv;
1855 ModestMsgEditWindowPrivate *priv;
1857 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1858 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1860 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1861 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1862 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1863 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1865 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1866 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1867 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1870 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1872 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1873 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1875 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1876 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1878 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1879 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1882 switch (buffer_format->justification)
1884 case GTK_JUSTIFY_LEFT:
1885 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1887 case GTK_JUSTIFY_CENTER:
1888 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1890 case GTK_JUSTIFY_RIGHT:
1891 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1898 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1900 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1901 G_CALLBACK (modest_msg_edit_window_color_button_change),
1903 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1904 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1905 G_CALLBACK (modest_msg_edit_window_color_button_change),
1908 if (priv->current_size_index != buffer_format->font_size) {
1912 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1913 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1917 priv->current_size_index = buffer_format->font_size;
1919 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
1920 markup = g_strconcat ("<span font_family='Sans'>",
1921 size_text, "</span>", NULL);
1923 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1927 gtk_tree_path_free (path);
1930 if (priv->current_face_index != buffer_format->font) {
1934 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
1935 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
1939 priv->current_face_index = buffer_format->font;
1940 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
1941 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
1942 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1949 g_free (buffer_format);
1953 #ifdef MODEST_HILDON_VERSION_0
1955 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1958 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1959 ModestMsgEditWindowPrivate *priv;
1960 GtkWidget *dialog = NULL;
1962 GdkColor *new_color = NULL;
1964 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1965 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1967 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1968 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1969 g_free (buffer_format);
1971 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1972 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1973 if (new_color != NULL) {
1974 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1975 (gpointer) new_color);
1978 gtk_widget_destroy (dialog);
1983 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1986 ModestMsgEditWindowPrivate *priv;
1987 GtkWidget *dialog = NULL;
1989 GdkColor *old_color = NULL;
1990 const GdkColor *new_color = NULL;
1992 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1993 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1995 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1996 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1998 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1999 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2000 if (new_color != NULL)
2001 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2003 gtk_widget_destroy (dialog);
2009 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2012 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2013 ModestMsgEditWindowPrivate *priv;
2014 GtkWidget *dialog = NULL;
2016 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2017 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2019 dialog = hildon_color_chooser_new ();
2020 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2021 g_free (buffer_format);
2023 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2025 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2026 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2029 gtk_widget_destroy (dialog);
2034 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2037 ModestMsgEditWindowPrivate *priv;
2038 GtkWidget *dialog = NULL;
2039 GdkColor *old_color = NULL;
2041 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2042 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2044 dialog = hildon_color_chooser_new ();
2045 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2047 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2049 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2050 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2052 gtk_widget_destroy (dialog);
2055 #endif /*!MODEST_HILDON_VERSION_0*/
2060 create_stream_for_uri (const gchar* uri)
2065 TnyStream *result = NULL;
2067 GnomeVFSHandle *handle = NULL;
2068 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2069 if (test == GNOME_VFS_OK) {
2070 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2071 /* Streams over OBEX (Bluetooth) are not seekable but
2072 * we expect them to be (we might need to read them
2073 * several times). So if this is a Bluetooth URI just
2074 * read the whole file into memory (this is not a fast
2075 * protocol so we can assume that these files are not
2076 * going to be very big) */
2077 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2078 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2079 TnyStream *memstream = tny_camel_mem_stream_new ();
2080 tny_stream_write_to_stream (vfssstream, memstream);
2081 g_object_unref (vfssstream);
2084 result = vfssstream;
2092 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2095 ModestMsgEditWindowPrivate *priv;
2096 GtkWidget *dialog = NULL;
2098 GSList *uris = NULL;
2099 GSList *uri_node = NULL;
2101 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2103 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2104 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2105 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2107 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2109 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2110 GTK_WINDOW (dialog), GTK_WINDOW (window));
2112 response = gtk_dialog_run (GTK_DIALOG (dialog));
2114 case GTK_RESPONSE_OK:
2115 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2120 gtk_widget_destroy (dialog);
2122 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2124 GnomeVFSHandle *handle = NULL;
2125 GnomeVFSResult result;
2126 GtkTextIter position;
2127 GtkTextMark *insert_mark;
2129 uri = (const gchar *) uri_node->data;
2130 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2131 if (result == GNOME_VFS_OK) {
2133 GnomeVFSFileInfo *info;
2134 gchar *filename, *basename, *escaped_filename;
2135 TnyMimePart *mime_part;
2137 const gchar *mime_type = NULL;
2138 GnomeVFSURI *vfs_uri;
2139 guint64 stream_size;
2141 gnome_vfs_close (handle);
2142 vfs_uri = gnome_vfs_uri_new (uri);
2144 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2145 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2146 g_free (escaped_filename);
2147 gnome_vfs_uri_unref (vfs_uri);
2148 info = gnome_vfs_file_info_new ();
2150 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2151 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2153 mime_type = gnome_vfs_file_info_get_mime_type (info);
2155 mime_part = tny_platform_factory_new_mime_part
2156 (modest_runtime_get_platform_factory ());
2158 TnyStream *stream = create_stream_for_uri (uri);
2160 if (stream == NULL) {
2162 modest_platform_information_banner (NULL, NULL,
2163 _FM("sfil_ib_opening_not_allowed"));
2165 g_object_unref (mime_part);
2166 gnome_vfs_file_info_unref (info);
2170 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2172 content_id = g_strdup_printf ("%d", priv->next_cid);
2173 tny_mime_part_set_content_id (mime_part, content_id);
2174 g_free (content_id);
2177 basename = g_path_get_basename (filename);
2178 tny_mime_part_set_filename (mime_part, basename);
2181 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2183 if (pixbuf != NULL) {
2184 priv->images_size += stream_size;
2185 priv->images_count ++;
2186 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2187 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2188 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2189 g_object_unref (pixbuf);
2191 tny_list_prepend (priv->images, (GObject *) mime_part);
2192 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2194 modest_platform_information_banner (NULL, NULL,
2195 _("mail_ib_file_operation_failed"));
2199 g_object_unref (mime_part);
2200 gnome_vfs_file_info_unref (info);
2209 on_attach_file_response (GtkDialog *dialog,
2213 GSList *uris = NULL;
2215 GnomeVFSFileSize total_size, allowed_size;
2216 ModestMsgEditWindow *window;
2217 ModestMsgEditWindowPrivate *priv;
2222 case GTK_RESPONSE_OK:
2223 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2229 window = MODEST_MSG_EDIT_WINDOW (user_data);
2230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2232 /* allowed size is the maximum size - what's already there */
2233 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2234 &att_num, &att_size);
2235 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2238 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2240 const gchar *uri = (const gchar *) uri_node->data;
2243 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2245 if (total_size > allowed_size) {
2246 g_warning ("%s: total size: %u",
2247 __FUNCTION__, (unsigned int)total_size);
2250 allowed_size -= total_size;
2252 g_slist_foreach (uris, (GFunc) g_free, NULL);
2253 g_slist_free (uris);
2255 gtk_widget_destroy (GTK_WIDGET (dialog));
2259 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2261 GtkWidget *dialog = NULL;
2262 ModestMsgEditWindowPrivate *priv;
2264 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2266 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2268 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2271 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2272 GTK_FILE_CHOOSER_ACTION_OPEN);
2273 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2274 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2275 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2276 GTK_WINDOW (dialog), GTK_WINDOW (window));
2278 /* Connect to response & show */
2279 g_signal_connect (dialog, "response",
2280 G_CALLBACK (on_attach_file_response), window);
2281 gtk_widget_show (dialog);
2286 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2288 GnomeVFSFileSize allowed_size)
2291 GnomeVFSHandle *handle = NULL;
2292 ModestMsgEditWindowPrivate *priv;
2293 GnomeVFSResult result;
2294 GnomeVFSFileSize size = 0;
2295 g_return_val_if_fail (window, 0);
2296 g_return_val_if_fail (uri, 0);
2298 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2300 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2301 if (result == GNOME_VFS_OK) {
2302 TnyMimePart *mime_part;
2304 const gchar *mime_type = NULL;
2306 gchar *escaped_filename;
2309 GnomeVFSFileInfo *info;
2310 GnomeVFSURI *vfs_uri;
2312 gnome_vfs_close (handle);
2313 vfs_uri = gnome_vfs_uri_new (uri);
2316 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2317 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2318 g_free (escaped_filename);
2319 gnome_vfs_uri_unref (vfs_uri);
2321 info = gnome_vfs_file_info_new ();
2323 if (gnome_vfs_get_file_info (uri,
2325 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2327 mime_type = gnome_vfs_file_info_get_mime_type (info);
2328 mime_part = tny_platform_factory_new_mime_part
2329 (modest_runtime_get_platform_factory ());
2331 /* try to get the attachment's size; this may fail for weird
2332 * file systems, like obex, upnp... */
2333 if (allowed_size != 0 &&
2334 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2336 if (size > allowed_size) {
2337 modest_platform_information_banner (NULL, NULL,
2338 _FM("sfil_ib_opening_not_allowed"));
2342 g_warning ("%s: could not get attachment size", __FUNCTION__);
2344 stream = create_stream_for_uri (uri);
2346 if (stream == NULL) {
2348 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2350 g_object_unref (mime_part);
2351 gnome_vfs_file_info_unref (info);
2355 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2356 g_object_unref (stream);
2358 content_id = g_strdup_printf ("%d", priv->next_cid);
2359 tny_mime_part_set_content_id (mime_part, content_id);
2360 g_free (content_id);
2363 basename = g_path_get_basename (filename);
2364 tny_mime_part_set_filename (mime_part, basename);
2367 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2368 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2370 info->size == 0, info->size);
2371 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2372 gtk_widget_show_all (priv->attachments_caption);
2373 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2375 g_object_unref (mime_part);
2376 gnome_vfs_file_info_unref (info);
2383 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2386 ModestMsgEditWindowPrivate *priv;
2389 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2390 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2392 if (att_list == NULL) {
2393 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2394 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2395 g_object_unref (att_list);
2400 g_object_ref (att_list);
2403 if (tny_list_get_length (att_list) == 0) {
2404 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2406 gboolean dialog_response;
2407 gchar *message = NULL;
2408 gchar *filename = NULL;
2410 if (tny_list_get_length (att_list) == 1) {
2412 iter = tny_list_create_iterator (att_list);
2413 part = (TnyMimePart *) tny_iterator_get_current (iter);
2414 g_object_unref (iter);
2415 if (TNY_IS_MSG (part)) {
2416 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2418 filename = tny_header_dup_subject (header);
2419 g_object_unref (header);
2421 if (filename == NULL) {
2422 filename = g_strdup (_("mail_va_no_subject"));
2425 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2427 g_object_unref (part);
2429 filename = g_strdup ("");
2431 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2432 "emev_nc_delete_attachments",
2433 tny_list_get_length (att_list)), filename);
2436 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2440 if (dialog_response != GTK_RESPONSE_OK) {
2441 g_object_unref (att_list);
2445 for (iter = tny_list_create_iterator (att_list);
2446 !tny_iterator_is_done (iter);
2447 tny_iterator_next (iter)) {
2448 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2449 const gchar *att_id;
2450 tny_list_remove (priv->attachments, (GObject *) mime_part);
2452 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2454 if (tny_list_get_length (priv->attachments) == 0)
2455 gtk_widget_hide (priv->attachments_caption);
2456 att_id = tny_mime_part_get_content_id (mime_part);
2458 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2460 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2461 g_object_unref (mime_part);
2463 g_object_unref (iter);
2466 g_object_unref (att_list);
2468 /* if the last attachment has been removed, focus the Subject: field */
2469 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2470 gtk_widget_grab_focus (priv->subject_field);
2474 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2477 ModestMsgEditWindowPrivate *priv;
2478 GdkColor *new_color;
2479 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2481 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2482 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2485 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2487 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2489 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2491 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2496 font_size_clicked (GtkToolButton *button,
2497 ModestMsgEditWindow *window)
2499 ModestMsgEditWindowPrivate *priv;
2500 GtkWidget *selector, *dialog;
2502 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2504 selector = hildon_touch_selector_new ();
2505 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2506 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2508 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2509 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2511 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2515 WPTextBufferFormat format;
2517 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2519 memset (&format, 0, sizeof (format));
2520 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2522 format.cs.font_size = TRUE;
2523 format.cs.text_position = TRUE;
2524 format.cs.font = TRUE;
2525 format.font_size = new_index;
2526 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2528 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2529 GINT_TO_POINTER (new_index)))
2530 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2532 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2533 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2534 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2535 size_text, "</span>", NULL);
2537 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2541 gtk_widget_destroy (dialog);
2543 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2548 font_face_clicked (GtkToolButton *button,
2549 ModestMsgEditWindow *window)
2551 ModestMsgEditWindowPrivate *priv;
2552 GtkWidget *selector, *dialog;
2553 GtkCellRenderer *renderer;
2555 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2557 selector = hildon_touch_selector_new ();
2558 renderer = gtk_cell_renderer_text_new ();
2559 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2560 renderer, "family", 0, "text", 0, NULL);
2561 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2563 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2564 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2566 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2567 gint new_font_index;
2571 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2572 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2573 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2577 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2579 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2580 GINT_TO_POINTER(new_font_index)))
2581 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2583 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2584 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2586 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2590 gtk_tree_path_free (path);
2593 gtk_widget_destroy (dialog);
2595 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2600 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2603 ModestMsgEditWindowPrivate *priv = NULL;
2604 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2606 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2607 if (!priv->update_caption_visibility)
2610 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2612 gtk_widget_show (priv->cc_caption);
2614 gtk_widget_hide (priv->cc_caption);
2616 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2620 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2623 ModestMsgEditWindowPrivate *priv = NULL;
2624 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2626 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2627 if (!priv->update_caption_visibility)
2630 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2632 gtk_widget_show (priv->bcc_caption);
2634 gtk_widget_hide (priv->bcc_caption);
2636 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2640 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2641 ModestRecptEditor *editor)
2643 ModestMsgEditWindowPrivate *priv;
2645 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2646 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2648 /* we check for low-mem; in that case, show a warning, and don't allow
2649 * for the addressbook
2651 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2654 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2656 if (editor == NULL) {
2657 GtkWidget *view_focus;
2658 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2660 /* This code should be kept in sync with ModestRecptEditor. The
2661 textview inside the recpt editor is the one that really gets the
2662 focus. As it's inside a scrolled window, and this one inside the
2663 hbox recpt editor inherits from, we'll need to go up in the
2664 hierarchy to know if the text view is part of the recpt editor
2665 or if it's a different text entry */
2667 if (gtk_widget_get_parent (view_focus)) {
2668 GtkWidget *first_parent;
2670 first_parent = gtk_widget_get_parent (view_focus);
2671 if (gtk_widget_get_parent (first_parent) &&
2672 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2673 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2678 editor = MODEST_RECPT_EDITOR (priv->to_field);
2682 modest_address_book_select_addresses (editor);
2687 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2689 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2691 modest_msg_edit_window_open_addressbook (window, NULL);
2695 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2696 gboolean show_toolbar)
2698 ModestWindowPrivate *parent_priv;
2700 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2701 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2703 /* We can not just use the code of
2704 modest_msg_edit_window_setup_toolbar because it has a
2705 mixture of both initialization and creation code. */
2707 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2709 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2713 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2714 TnyHeaderFlags priority_flags)
2716 ModestMsgEditWindowPrivate *priv;
2717 ModestWindowPrivate *parent_priv;
2719 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2721 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2722 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2724 if (priv->priority_flags != priority_flags) {
2725 GtkAction *priority_action = NULL;
2727 priv->priority_flags = priority_flags;
2729 switch (priority_flags) {
2730 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2731 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2732 MODEST_HEADER_ICON_HIGH,
2733 HILDON_ICON_SIZE_SMALL);
2734 gtk_widget_show (priv->priority_icon);
2735 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2736 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2738 case TNY_HEADER_FLAG_LOW_PRIORITY:
2739 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2740 MODEST_HEADER_ICON_LOW,
2741 HILDON_ICON_SIZE_SMALL);
2742 gtk_widget_show (priv->priority_icon);
2743 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2744 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2747 gtk_widget_hide (priv->priority_icon);
2748 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2749 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2752 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2753 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2755 gtk_widget_queue_resize (priv->subject_box);
2759 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2762 ModestMsgEditWindowPrivate *priv;
2763 ModestWindowPrivate *parent_priv;
2764 gint current_format;
2766 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2768 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2769 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2771 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2772 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2774 if (current_format != file_format) {
2775 switch (file_format) {
2776 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2777 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2778 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2780 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2784 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2785 response = gtk_dialog_run (GTK_DIALOG (dialog));
2786 gtk_widget_destroy (dialog);
2787 if (response == GTK_RESPONSE_OK) {
2788 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2790 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2791 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2796 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2797 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2798 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2803 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2806 ModestMsgEditWindowPrivate *priv;
2807 WPTextBufferFormat oldfmt, fmt;
2808 gint old_position = 0;
2812 GdkColor *color = NULL;
2813 gboolean bold, bold_set, italic, italic_set;
2814 gboolean underline, underline_set;
2815 gboolean strikethrough, strikethrough_set;
2816 gboolean position_set;
2817 gboolean font_size_set, font_set, color_set;
2820 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2821 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2823 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2824 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2825 GTK_WINDOW(dialog), GTK_WINDOW (window));
2827 /* First we get the currently selected font information */
2828 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2830 switch (oldfmt.text_position) {
2831 case TEXT_POSITION_NORMAL:
2834 case TEXT_POSITION_SUPERSCRIPT:
2842 g_object_set (G_OBJECT (dialog),
2843 "bold", oldfmt.bold != FALSE,
2844 "bold-set", !oldfmt.cs.bold,
2845 "underline", oldfmt.underline != FALSE,
2846 "underline-set", !oldfmt.cs.underline,
2847 "italic", oldfmt.italic != FALSE,
2848 "italic-set", !oldfmt.cs.italic,
2849 "strikethrough", oldfmt.strikethrough != FALSE,
2850 "strikethrough-set", !oldfmt.cs.strikethrough,
2851 "color", &oldfmt.color,
2852 "color-set", !oldfmt.cs.color,
2853 "size", wp_font_size[oldfmt.font_size],
2854 "size-set", !oldfmt.cs.font_size,
2855 "position", old_position,
2856 "position-set", !oldfmt.cs.text_position,
2857 "family", wp_get_font_name (oldfmt.font),
2858 "family-set", !oldfmt.cs.font,
2861 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2862 GTK_WINDOW (dialog), GTK_WINDOW (window));
2863 gtk_widget_show_all (dialog);
2864 priv->font_dialog = dialog;
2865 response = gtk_dialog_run (GTK_DIALOG (dialog));
2866 priv->font_dialog = NULL;
2867 if (response == GTK_RESPONSE_OK) {
2869 g_object_get( dialog,
2871 "bold-set", &bold_set,
2872 "underline", &underline,
2873 "underline-set", &underline_set,
2875 "italic-set", &italic_set,
2876 "strikethrough", &strikethrough,
2877 "strikethrough-set", &strikethrough_set,
2879 "color-set", &color_set,
2881 "size-set", &font_size_set,
2882 "family", &font_name,
2883 "family-set", &font_set,
2884 "position", &position,
2885 "position-set", &position_set,
2890 if (response == GTK_RESPONSE_OK) {
2891 memset(&fmt, 0, sizeof(fmt));
2897 fmt.italic = italic;
2898 fmt.cs.italic = TRUE;
2900 if (underline_set) {
2901 fmt.underline = underline;
2902 fmt.cs.underline = TRUE;
2904 if (strikethrough_set) {
2905 fmt.strikethrough = strikethrough;
2906 fmt.cs.strikethrough = TRUE;
2911 ? TEXT_POSITION_NORMAL
2912 : ( ( position == 1 )
2913 ? TEXT_POSITION_SUPERSCRIPT
2914 : TEXT_POSITION_SUBSCRIPT );
2915 fmt.cs.text_position = TRUE;
2916 fmt.font_size = oldfmt.font_size;
2920 fmt.cs.color = TRUE;
2923 fmt.font = wp_get_font_index(font_name,
2928 if (font_size_set) {
2929 fmt.cs.font_size = TRUE;
2930 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2932 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2933 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2935 gtk_widget_destroy (dialog);
2937 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2941 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2943 ModestMsgEditWindowPrivate *priv;
2945 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2946 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2948 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2950 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2951 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2955 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2957 ModestMsgEditWindowPrivate *priv;
2959 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2960 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2962 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2964 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2965 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2970 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2972 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2974 priv->can_undo = can_undo;
2978 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2980 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2982 priv->can_redo = can_redo;
2986 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2988 ModestMsgEditWindowPrivate *priv;
2989 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2990 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2992 return priv->can_undo;
2996 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2998 ModestMsgEditWindowPrivate *priv;
2999 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3000 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3002 return priv->can_redo;
3007 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3010 GtkTextIter match_start, match_end;
3012 if (image_id == NULL)
3015 gtk_text_buffer_get_start_iter (buffer, &iter);
3017 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3018 GSList *tags = gtk_text_iter_get_tags (&match_start);
3020 for (node = tags; node != NULL; node = g_slist_next (node)) {
3021 GtkTextTag *tag = (GtkTextTag *) node->data;
3022 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3023 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3024 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3026 offset = gtk_text_iter_get_offset (&match_start);
3027 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3028 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3032 gtk_text_iter_forward_char (&iter);
3037 message_is_empty (ModestMsgEditWindow *window)
3039 ModestMsgEditWindowPrivate *priv = NULL;
3041 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3042 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3044 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3045 * so we can ignore markup.
3047 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3050 count = gtk_text_buffer_get_char_count (buf);
3056 msg_body_focus (GtkWidget *focus,
3057 GdkEventFocus *event,
3061 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3062 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3063 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3068 recpt_field_changed (GtkTextBuffer *buffer,
3069 ModestMsgEditWindow *editor)
3071 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3072 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3076 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3078 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3079 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3083 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3086 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3087 GtkTextBuffer *buffer;
3089 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3090 gtk_text_buffer_set_modified (buffer, modified);
3091 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3092 gtk_text_buffer_set_modified (buffer, modified);
3093 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3094 gtk_text_buffer_set_modified (buffer, modified);
3095 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3099 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3101 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3102 const char *account_name;
3103 GtkTextBuffer *buffer;
3105 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3106 if (gtk_text_buffer_get_modified (buffer))
3108 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3109 if (gtk_text_buffer_get_modified (buffer))
3111 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3112 if (gtk_text_buffer_get_modified (buffer))
3114 if (gtk_text_buffer_get_modified (priv->text_buffer))
3116 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3117 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3128 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3130 ModestMsgEditWindowPrivate *priv = NULL;
3132 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3133 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3135 /* check if there's no recipient added */
3136 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3137 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3138 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3139 /* no recipient contents, then select contacts */
3140 modest_msg_edit_window_open_addressbook (window, NULL);
3144 g_object_ref (window);
3145 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3146 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3147 g_object_unref (window);
3150 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3151 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3152 g_object_unref (window);
3155 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3156 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3157 g_object_unref (window);
3161 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3162 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3163 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3164 g_object_unref (window);
3171 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3172 ModestMsgEditWindow *window)
3174 modest_msg_edit_window_offer_attach_file (window);
3178 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3180 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3182 return priv->clipboard_text;
3186 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3188 ModestMsgEditWindow *window)
3190 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3191 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3193 if (!GTK_WIDGET_VISIBLE (window))
3196 g_object_ref (window);
3197 text = gtk_clipboard_wait_for_text (selection_clipboard);
3199 if (priv->clipboard_text != NULL) {
3200 g_free (priv->clipboard_text);
3202 priv->clipboard_text = text;
3204 if (GTK_WIDGET_VISIBLE (window)) {
3205 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3207 g_object_unref (window);
3210 static gboolean clipboard_owner_change_idle (gpointer userdata)
3212 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3213 ModestMsgEditWindowPrivate *priv;
3215 gdk_threads_enter ();
3216 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3217 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3219 priv->clipboard_owner_idle = 0;
3220 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3221 gdk_threads_leave ();
3227 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3229 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3230 if (priv->clipboard_owner_idle == 0) {
3231 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3236 subject_field_move_cursor (GtkEntry *entry,
3237 GtkMovementStep step,
3242 if (!GTK_WIDGET_VISIBLE (window))
3245 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3249 update_window_title (ModestMsgEditWindow *window)
3251 ModestMsgEditWindowPrivate *priv = NULL;
3252 const gchar *subject;
3254 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3255 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3256 if (subject == NULL || subject[0] == '\0')
3257 subject = _("mail_va_new_email");
3259 gtk_window_set_title (GTK_WINDOW (window), subject);
3264 subject_field_changed (GtkEditable *editable,
3265 ModestMsgEditWindow *window)
3267 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3268 update_window_title (window);
3269 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3270 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3271 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3275 subject_field_insert_text (GtkEditable *editable,
3277 gint new_text_length,
3279 ModestMsgEditWindow *window)
3281 GString *result = g_string_new ("");
3283 gint result_len = 0;
3284 const gchar *entry_text = NULL;
3287 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3288 old_length = g_utf8_strlen (entry_text, -1);
3290 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3291 gunichar c = g_utf8_get_char_validated (current, 8);
3292 /* Invalid unichar, stop */
3298 result = g_string_append_unichar (result, c);
3302 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3303 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3306 /* Prevent endless recursion */
3307 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3308 g_signal_emit_by_name (editable, "insert-text",
3309 (gpointer) result->str, (gpointer) result->len,
3310 (gpointer) position, (gpointer) window);
3311 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3315 if (result_len + old_length > 1000) {
3316 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3317 _CS("ckdg_ib_maximum_characters_reached"));
3319 g_string_free (result, TRUE);
3323 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3326 ModestMsgEditWindowPrivate *priv = NULL;
3328 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3329 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3331 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3334 gtk_widget_show_all (priv->find_toolbar);
3335 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3337 gtk_widget_hide_all (priv->find_toolbar);
3338 gtk_widget_grab_focus (priv->msg_body);
3343 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3345 GtkTextIter *match_start,
3346 GtkTextIter *match_end)
3348 GtkTextIter end_iter;
3349 gchar *str_casefold;
3352 gchar *range_casefold;
3355 gboolean result = FALSE;
3362 gtk_text_iter_forward_to_end (&end_iter);
3364 str_casefold = g_utf8_casefold (str, -1);
3365 str_chars_n = strlen (str);
3367 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3368 range_casefold = g_utf8_casefold (range_text, -1);
3369 range_chars_n = strlen (range_casefold);
3371 if (range_chars_n < str_chars_n) {
3372 g_free (str_casefold);
3373 g_free (range_text);
3374 g_free (range_casefold);
3378 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3379 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3380 if (!g_utf8_collate (range_subtext, str_casefold)) {
3381 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3383 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3384 match_start, match_end, NULL);
3385 g_free (found_text);
3387 g_free (range_subtext);
3391 g_free (str_casefold);
3392 g_free (range_text);
3393 g_free (range_casefold);
3400 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3401 ModestMsgEditWindow *window)
3403 gchar *current_search = NULL;
3404 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3406 GtkTextIter selection_start, selection_end;
3407 GtkTextIter match_start, match_end;
3408 gboolean continue_search = FALSE;
3410 if (message_is_empty (window)) {
3411 g_free (priv->last_search);
3412 priv->last_search = NULL;
3413 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3417 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3418 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3419 g_free (current_search);
3420 g_free (priv->last_search);
3421 priv->last_search = NULL;
3422 /* Information banner about empty search */
3423 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3427 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3428 continue_search = TRUE;
3430 g_free (priv->last_search);
3431 priv->last_search = g_strdup (current_search);
3434 if (continue_search) {
3435 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3436 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3437 &match_start, &match_end);
3439 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3441 GtkTextIter buffer_start;
3442 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3443 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3444 &match_start, &match_end);
3446 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3449 /* Mark as selected the string found in search */
3451 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3452 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3453 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3455 g_free (priv->last_search);
3456 priv->last_search = NULL;
3458 g_free (current_search);
3462 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3464 ModestMsgEditWindowPrivate *priv;
3466 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3471 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3474 ModestMsgEditWindowPrivate *priv;
3476 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3481 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3482 ModestMsgEditWindow *window)
3484 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3488 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3491 ModestMsgEditWindowPrivate *priv;
3492 TnyHeader *header = NULL;
3494 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3495 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3497 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3498 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3500 if (priv->draft_msg != NULL) {
3501 g_object_unref (priv->draft_msg);
3504 if (draft != NULL) {
3505 g_object_ref (draft);
3506 header = tny_msg_get_header (draft);
3507 if (priv->msg_uid) {
3508 g_free (priv->msg_uid);
3509 priv->msg_uid = NULL;
3511 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3512 if (GTK_WIDGET_REALIZED (window)) {
3513 if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3514 gtk_widget_destroy (GTK_WIDGET (window));
3520 priv->draft_msg = draft;
3524 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3525 GtkTextIter *start, GtkTextIter *end,
3528 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3529 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3532 if (tag == NULL) return;
3533 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3534 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3535 replace_with_images (window, priv->images);
3540 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3543 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3545 g_return_if_fail (TNY_IS_MIME_PART (part));
3546 tny_list_prepend (priv->attachments, (GObject *) part);
3547 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3548 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3549 gtk_widget_show_all (priv->attachments_caption);
3550 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3554 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3556 ModestMsgEditWindowPrivate *priv;
3558 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3559 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3561 return priv->msg_uid;
3565 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3566 ModestMsgEditWindowWidgetType widget_type)
3568 ModestMsgEditWindowPrivate *priv;
3570 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3571 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3573 switch (widget_type) {
3574 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3575 return priv->msg_body;
3577 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3578 return priv->to_field;
3580 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3581 return priv->cc_field;
3583 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3584 return priv->bcc_field;
3586 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3587 return priv->subject_field;
3589 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3590 return priv->attachments_view;
3598 remove_tags (WPTextBuffer *buffer)
3600 GtkTextIter start, end;
3602 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3603 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3605 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3609 on_account_removed (TnyAccountStore *account_store,
3610 TnyAccount *account,
3613 /* Do nothing if it's a store account, because we use the
3614 transport to send the messages */
3615 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3616 const gchar *parent_acc = NULL;
3617 const gchar *our_acc = NULL;
3619 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3620 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3621 /* Close this window if I'm showing a message of the removed account */
3622 if (strcmp (parent_acc, our_acc) == 0)
3623 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3628 from_field_changed (HildonPickerButton *button,
3629 ModestMsgEditWindow *self)
3631 ModestMsgEditWindowPrivate *priv;
3632 gboolean has_old_signature, has_new_signature;
3634 GtkTextIter match_start, match_end;
3635 ModestAccountMgr *mgr;
3637 gchar *full_signature;
3639 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3641 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3642 mgr = modest_runtime_get_account_mgr ();
3643 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3644 if (has_old_signature) {
3645 full_signature = g_strconcat ("\n--\n", signature, NULL);
3646 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3647 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3649 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3650 &match_start, &match_end, NULL)) {
3653 g_free (full_signature);
3657 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3658 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3659 if (has_new_signature) {
3660 full_signature = g_strconcat ("\n--\n", signature, NULL);
3661 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3662 g_free (full_signature);
3667 typedef struct _MessageSettingsHelper {
3668 ModestMsgEditWindow *window;
3669 GSList *priority_group;
3670 GSList *format_group;
3671 GtkToggleButton *current_priority;
3672 GtkToggleButton *current_format;
3673 } MessageSettingsHelper;
3676 on_priority_toggle (GtkToggleButton *button,
3677 MessageSettingsHelper *helper)
3680 ModestMsgEditWindowPrivate *priv;
3682 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3683 if (gtk_toggle_button_get_active (button)) {
3685 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3686 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3687 if ((node_button != button) &&
3688 gtk_toggle_button_get_active (node_button)) {
3689 gtk_toggle_button_set_active (node_button, FALSE);
3692 helper->current_priority = button;
3694 gboolean found = FALSE;
3695 /* If no one is active, activate it again */
3696 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3697 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3698 if (gtk_toggle_button_get_active (node_button)) {
3704 gtk_toggle_button_set_active (button, TRUE);
3710 on_format_toggle (GtkToggleButton *button,
3711 MessageSettingsHelper *helper)
3714 ModestMsgEditWindowPrivate *priv;
3716 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3717 if (gtk_toggle_button_get_active (button)) {
3719 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3720 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3721 if ((node_button != button) &&
3722 gtk_toggle_button_get_active (node_button)) {
3723 gtk_toggle_button_set_active (node_button, FALSE);
3726 helper->current_format = button;
3728 gboolean found = FALSE;
3729 /* If no one is active, activate it again */
3730 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3731 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3732 if (gtk_toggle_button_get_active (node_button)) {
3738 gtk_toggle_button_set_active (button, TRUE);
3745 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3750 GtkWidget *priority_hbox;
3751 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3752 GtkWidget *captioned;
3753 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3754 GtkWidget *format_hbox;
3755 GtkWidget *html_toggle, *text_toggle;
3756 ModestMsgEditWindowPrivate *priv;
3757 MessageSettingsHelper helper = {0,};
3759 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3760 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3761 helper.window = window;
3762 helper.priority_group = NULL;
3763 helper.format_group = NULL;
3765 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3766 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3768 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3769 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3770 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3771 vbox = gtk_vbox_new (FALSE, 0);
3772 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3773 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3774 gtk_container_add (GTK_CONTAINER (align), vbox);
3775 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3776 gtk_widget_show (align);
3777 gtk_widget_show (vbox);
3779 /* Priority toggles */
3780 priority_hbox = gtk_hbox_new (TRUE, 0);
3781 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3782 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3783 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3784 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3785 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3786 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3787 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3788 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3789 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3790 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3791 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3792 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3793 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3794 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3795 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3796 gtk_widget_show_all (priority_hbox);
3797 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3798 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3799 gtk_widget_show (captioned);
3800 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3802 /* format toggles */
3803 format_hbox = gtk_hbox_new (TRUE, 0);
3804 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3805 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3806 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3807 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3808 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3809 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3810 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3811 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3812 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3813 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3814 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3815 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3816 gtk_widget_show_all (format_hbox);
3817 gtk_widget_show (format_hbox);
3818 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3821 g_object_unref (title_sizegroup);
3822 g_object_unref (value_sizegroup);
3824 /* Set current values */
3825 switch (priv->priority_flags) {
3826 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3827 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3828 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3830 case TNY_HEADER_FLAG_LOW_PRIORITY:
3831 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3832 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3835 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3836 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3840 switch (modest_msg_edit_window_get_format (window)) {
3841 case MODEST_MSG_EDIT_FORMAT_TEXT:
3842 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3843 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3845 case MODEST_MSG_EDIT_FORMAT_HTML:
3847 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3848 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3852 /* Signal connects */
3853 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3854 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3855 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3856 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3857 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3859 /* Save settings if the user clicked on done */
3860 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3861 TnyHeaderFlags flags;
3862 ModestMsgEditFormat old_format, new_format;
3864 /* Set priority flags */
3865 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3866 if (priv->priority_flags != flags)
3867 modest_msg_edit_window_set_priority_flags (window, flags);
3869 /* Set edit format */
3870 old_format = modest_msg_edit_window_get_format (window);
3871 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3872 if (old_format != new_format) {
3873 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3874 modest_msg_edit_window_set_file_format (window, file_format);
3878 gtk_widget_destroy (dialog);
3879 g_slist_free (helper.priority_group);
3883 on_message_settings (GtkAction *action,
3884 ModestMsgEditWindow *window)
3886 modest_msg_edit_window_show_msg_settings_dialog (window);
3890 on_cc_button_toggled (HildonCheckButton *button,
3891 ModestMsgEditWindow *window)
3893 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3895 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3896 hildon_check_button_get_active (button));
3900 on_bcc_button_toggled (HildonCheckButton *button,
3901 ModestMsgEditWindow *window)
3903 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3905 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3906 hildon_check_button_get_active (button));
3910 setup_menu (ModestMsgEditWindow *self)
3912 ModestMsgEditWindowPrivate *priv = NULL;
3914 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3916 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3918 /* Settings menu buttons */
3919 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3920 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3922 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3923 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3924 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3926 priv->cc_button = hildon_check_button_new (0);
3927 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
3928 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
3930 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
3932 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
3933 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
3934 priv->bcc_button = hildon_check_button_new (0);
3935 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
3936 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
3938 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
3940 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
3941 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
3943 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
3944 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
3945 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
3946 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3947 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
3948 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
3949 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
3950 APP_MENU_CALLBACK (on_message_settings),
3952 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
3953 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),