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;
250 GtkWidget *bcc_field;
251 GtkWidget *subject_field;
252 GtkWidget *attachments_view;
253 GtkWidget *priority_icon;
254 GtkWidget *subject_box;
255 GtkWidget *add_attachment_button;
257 GtkWidget *cc_caption;
258 GtkWidget *bcc_caption;
259 gboolean update_caption_visibility;
260 GtkWidget *attachments_caption;
262 GtkTextBuffer *text_buffer;
264 GtkWidget *font_size_toolitem;
265 GtkWidget *font_face_toolitem;
266 GtkWidget *font_color_button;
267 GtkWidget *font_color_toolitem;
268 GSList *font_items_group;
269 GtkTreeModel *faces_model;
270 gint current_face_index;
271 GtkWidget *font_tool_button_label;
272 GtkTreeModel *sizes_model;
273 gint current_size_index;
274 GtkWidget *size_tool_button_label;
276 GtkWidget *find_toolbar;
279 GtkWidget *font_dialog;
282 guint correct_scroll_idle;
283 guint scroll_drag_timeout_id;
287 TnyList *attachments;
292 TnyHeaderFlags priority_flags;
294 gboolean can_undo, can_redo;
295 gulong clipboard_change_handler_id;
296 gulong default_clipboard_change_handler_id;
297 gulong account_removed_handler_id;
298 guint clipboard_owner_idle;
299 gchar *clipboard_text;
308 GtkWidget *cc_button;
309 GtkWidget *bcc_button;
312 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
313 MODEST_TYPE_MSG_EDIT_WINDOW, \
314 ModestMsgEditWindowPrivate))
316 static GtkWindowClass *parent_class = NULL;
318 /* uncomment the following if you have defined any signals */
319 /* static guint signals[LAST_SIGNAL] = {0}; */
322 modest_msg_edit_window_get_type (void)
324 static GType my_type = 0;
326 static const GTypeInfo my_info = {
327 sizeof(ModestMsgEditWindowClass),
328 NULL, /* base init */
329 NULL, /* base finalize */
330 (GClassInitFunc) modest_msg_edit_window_class_init,
331 NULL, /* class finalize */
332 NULL, /* class data */
333 sizeof(ModestMsgEditWindow),
335 (GInstanceInitFunc) modest_msg_edit_window_init,
338 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
339 "ModestMsgEditWindow",
347 save_state (ModestWindow *self)
349 modest_widget_memory_save (modest_runtime_get_conf(),
350 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
355 restore_settings (ModestMsgEditWindow *self)
357 ModestConf *conf = NULL;
359 conf = modest_runtime_get_conf ();
361 /* Dim at start clipboard actions */
362 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
367 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
369 GObjectClass *gobject_class;
370 ModestWindowClass *modest_window_class;
371 gobject_class = (GObjectClass*) klass;
372 modest_window_class = (ModestWindowClass*) klass;
374 parent_class = g_type_class_peek_parent (klass);
375 gobject_class->finalize = modest_msg_edit_window_finalize;
377 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
378 modest_window_class->save_state_func = save_state;
379 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
381 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
385 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
387 ModestMsgEditWindowPrivate *priv;
388 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
390 priv->msg_body = NULL;
391 priv->from_field = NULL;
392 priv->to_field = NULL;
393 priv->cc_field = NULL;
394 priv->bcc_field = NULL;
395 priv->subject_field = NULL;
396 priv->attachments = TNY_LIST (tny_simple_list_new ());
397 priv->images = TNY_LIST (tny_simple_list_new ());
398 priv->images_size = 0;
399 priv->images_count = 0;
402 priv->cc_caption = NULL;
403 priv->bcc_caption = NULL;
404 priv->update_caption_visibility = FALSE;
406 priv->priority_flags = 0;
408 priv->find_toolbar = NULL;
409 priv->last_search = NULL;
411 priv->draft_msg = NULL;
412 priv->outbox_msg = NULL;
413 priv->msg_uid = NULL;
415 priv->can_undo = FALSE;
416 priv->can_redo = FALSE;
417 priv->clipboard_change_handler_id = 0;
418 priv->default_clipboard_change_handler_id = 0;
419 priv->account_removed_handler_id = 0;
420 priv->clipboard_owner_idle = 0;
421 priv->clipboard_text = NULL;
424 priv->scroll_drag_timeout_id = 0;
425 priv->correct_scroll_idle = 0;
426 priv->last_upper = 0.0;
428 priv->font_dialog = NULL;
429 priv->app_menu = NULL;
431 priv->references = NULL;
432 priv->in_reply_to = NULL;
434 if (!is_wp_text_buffer_started) {
435 is_wp_text_buffer_started = TRUE;
436 wp_text_buffer_library_init ();
441 hildon_program_add_window (hildon_program_get_instance(),
447 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
449 static ModestPairList*
450 get_transports (void)
452 GSList *transports = NULL;
454 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
455 GSList *accounts = modest_account_mgr_account_names (account_mgr,
456 TRUE /* only enabled accounts. */);
458 GSList *cursor = accounts;
460 gchar *account_name = cursor->data;
461 gchar *from_string = NULL;
463 from_string = modest_account_mgr_get_from_string (account_mgr,
467 if (from_string && account_name) {
468 gchar *name = account_name;
469 ModestPair *pair = modest_pair_new ((gpointer) name,
470 (gpointer) from_string , TRUE);
471 transports = g_slist_prepend (transports, pair);
474 cursor = cursor->next;
476 g_slist_free (accounts); /* only free the accounts, not the elements,
477 * because they are used in the pairlist */
481 static void window_focus (GtkWindow *window,
485 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
489 scroll_drag_timeout (gpointer userdata)
491 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
492 ModestMsgEditWindowPrivate *priv;
494 /* It could happen that the window was already closed */
495 if (!GTK_WIDGET_VISIBLE (win))
498 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
500 correct_scroll_without_drag_check (win, TRUE);
502 priv->scroll_drag_timeout_id = 0;
508 correct_scroll_without_drag_check_idle (gpointer userdata)
510 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
511 ModestMsgEditWindowPrivate *priv;
513 GdkRectangle rectangle;
514 gint offset_min, offset_max;
518 /* It could happen that the window was already closed */
519 if (!GTK_WIDGET_VISIBLE (w))
522 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
524 insert = gtk_text_buffer_get_insert (priv->text_buffer);
525 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
527 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
528 offset_min = priv->msg_body->allocation.y + rectangle.y;
529 offset_max = offset_min + rectangle.height;
531 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
532 offset_min = MAX (offset_min - 48, 0);
533 offset_max = MIN (offset_max + 48, vadj->upper);
535 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
537 priv->correct_scroll_idle = 0;
542 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
544 ModestMsgEditWindowPrivate *priv;
546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
548 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
551 if (priv->correct_scroll_idle > 0) {
555 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
556 (GSourceFunc) correct_scroll_without_drag_check_idle,
562 correct_scroll (ModestMsgEditWindow *w)
564 ModestMsgEditWindowPrivate *priv;
566 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
567 if (gtk_grab_get_current () == priv->msg_body) {
568 if (priv->scroll_drag_timeout_id == 0) {
569 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
571 (GSourceFunc) scroll_drag_timeout,
578 correct_scroll_without_drag_check (w, TRUE);
582 text_buffer_end_user_action (GtkTextBuffer *buffer,
583 ModestMsgEditWindow *userdata)
586 correct_scroll (userdata);
590 text_buffer_mark_set (GtkTextBuffer *buffer,
593 ModestMsgEditWindow *userdata)
595 gtk_text_buffer_begin_user_action (buffer);
596 gtk_text_buffer_end_user_action (buffer);
600 cut_clipboard_check (GtkTextView *text_view,
603 GtkTextBuffer *buffer;
605 buffer = gtk_text_view_get_buffer (text_view);
606 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
607 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
612 copy_clipboard_check (GtkTextView *text_view,
615 GtkTextBuffer *buffer;
617 buffer = gtk_text_view_get_buffer (text_view);
618 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
619 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
624 attachment_deleted (ModestAttachmentsView *attachments_view,
627 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
632 connect_signals (ModestMsgEditWindow *obj)
634 ModestMsgEditWindowPrivate *priv;
636 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
638 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
639 G_CALLBACK (text_buffer_refresh_attributes), obj);
640 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
641 G_CALLBACK (text_buffer_can_undo), obj);
642 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
643 G_CALLBACK (text_buffer_can_redo), obj);
644 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
645 G_CALLBACK (body_changed), obj);
646 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
647 G_CALLBACK (body_changed), obj);
648 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
649 G_CALLBACK (text_buffer_end_user_action), obj);
650 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
651 G_CALLBACK (text_buffer_mark_set), obj);
652 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
653 G_CALLBACK (text_buffer_apply_tag), obj);
654 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
655 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
656 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
657 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
658 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
659 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
661 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
662 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
663 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
664 G_CALLBACK (from_field_changed), obj);
666 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
667 G_CALLBACK (msg_body_focus), obj);
668 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
669 G_CALLBACK (msg_body_focus), obj);
670 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
671 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
672 "changed", G_CALLBACK (recpt_field_changed), obj);
673 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
674 "changed", G_CALLBACK (recpt_field_changed), obj);
675 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
676 "changed", G_CALLBACK (recpt_field_changed), obj);
677 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
678 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
679 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
681 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
682 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
684 priv->clipboard_change_handler_id =
685 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
686 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
687 priv->default_clipboard_change_handler_id =
688 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
689 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
691 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
692 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
693 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
697 init_wp_text_view_style ()
699 static gboolean initialized = FALSE;
702 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
708 init_window (ModestMsgEditWindow *obj)
710 GtkWidget *to_caption, *subject_caption;
711 GtkWidget *main_vbox;
712 GtkWidget *add_attachment_align;
713 ModestMsgEditWindowPrivate *priv;
714 GtkActionGroup *action_group;
715 ModestWindowPrivate *parent_priv;
716 GdkPixbuf *window_icon = NULL;
717 GError *error = NULL;
719 GtkSizeGroup *title_size_group;
720 GtkSizeGroup *value_size_group;
721 GtkWidget *attachment_icon;
722 GtkWidget *window_box;
723 GtkWidget *window_align;
724 #if (GTK_MINOR_VERSION >= 10)
725 GdkAtom deserialize_type;
728 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
729 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
731 parent_priv->ui_manager = gtk_ui_manager_new();
732 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
733 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
735 /* Add common actions */
736 gtk_action_group_add_actions (action_group,
737 modest_msg_edit_action_entries,
738 G_N_ELEMENTS (modest_msg_edit_action_entries),
740 gtk_action_group_add_actions (action_group,
741 hildon2_msg_edit_action_entries,
742 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
744 gtk_action_group_add_toggle_actions (action_group,
745 modest_msg_edit_toggle_action_entries,
746 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
748 gtk_action_group_add_radio_actions (action_group,
749 modest_msg_edit_alignment_radio_action_entries,
750 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
752 G_CALLBACK (modest_ui_actions_on_change_justify),
754 gtk_action_group_add_radio_actions (action_group,
755 modest_msg_edit_priority_action_entries,
756 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
758 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
760 gtk_action_group_add_radio_actions (action_group,
761 modest_msg_edit_file_format_action_entries,
762 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
763 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
764 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
766 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
767 g_object_unref (action_group);
769 /* Load the UI definition */
770 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
773 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
774 g_clear_error (&error);
777 /* Add accelerators */
778 gtk_window_add_accel_group (GTK_WINDOW (obj),
779 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
781 parent_priv->menubar = NULL;
783 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
784 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
786 /* Note: This ModestPairList* must exist for as long as the picker
787 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
788 * so it can't know how to manage its memory. */
789 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
790 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
792 modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group,
793 _("mail_va_from"), priv->from_field);
795 priv->to_field = modest_recpt_editor_new ();
796 priv->cc_field = modest_recpt_editor_new ();
797 priv->bcc_field = modest_recpt_editor_new ();
798 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
799 priv->priority_icon = gtk_image_new ();
800 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
801 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
802 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
803 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
804 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
805 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
806 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
807 priv->add_attachment_button = hildon_button_new (MODEST_EDITABLE_SIZE, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
808 gtk_widget_set_size_request (priv->add_attachment_button, ATTACHMENT_BUTTON_WIDTH, -1);
809 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
810 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
811 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
812 hildon_button_set_image (HILDON_BUTTON (priv->add_attachment_button), attachment_icon);
813 add_attachment_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
814 gtk_alignment_set_padding (GTK_ALIGNMENT (add_attachment_align), 0, 0, MODEST_MARGIN_DEFAULT, 0);
815 gtk_container_add (GTK_CONTAINER (add_attachment_align), priv->add_attachment_button);
816 gtk_box_pack_start (GTK_BOX (priv->subject_box), add_attachment_align, FALSE, FALSE, 0);
817 priv->attachments_view = modest_attachments_view_new (NULL);
818 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
819 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
821 priv->header_box = gtk_vbox_new (FALSE, 0);
823 to_caption = modest_maemo_utils_create_captioned_with_size_type
824 (title_size_group, value_size_group,
825 _("mail_va_to"), FALSE, priv->to_field,
826 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
827 priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type
828 (title_size_group, value_size_group,
829 _("mail_va_cc"), FALSE, priv->cc_field,
830 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
831 priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
832 (title_size_group, value_size_group,
833 _("mail_va_hotfix1"), FALSE, priv->bcc_field,
834 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
835 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
836 _("mail_va_subject"), FALSE, priv->subject_box);
837 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
838 _("mail_va_attachment"),
840 priv->attachments_view,
841 HILDON_SIZE_AUTO_WIDTH |
842 HILDON_SIZE_AUTO_HEIGHT);
843 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
844 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
845 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
846 g_object_unref (title_size_group);
847 g_object_unref (value_size_group);
849 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
850 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
851 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
852 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
853 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
854 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
855 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
857 init_wp_text_view_style ();
859 priv->msg_body = modest_wp_text_view_new ();
862 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
863 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
864 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
865 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
866 #if (GTK_MINOR_VERSION >= 10)
867 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
868 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
870 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
871 deserialize_type, TRUE);
873 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
875 priv->find_toolbar = hildon_find_toolbar_new (NULL);
876 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
878 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
880 priv->pannable = hildon_pannable_area_new ();
882 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
883 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
884 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
886 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
887 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
888 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
890 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
891 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
893 window_box = gtk_vbox_new (FALSE, 0);
894 gtk_container_add (GTK_CONTAINER(obj), window_box);
896 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
898 /* Set window icon */
899 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
901 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
902 g_object_unref (window_icon);
907 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
909 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
911 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
912 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
913 priv->clipboard_change_handler_id))
914 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
915 priv->clipboard_change_handler_id);
916 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
917 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
918 priv->default_clipboard_change_handler_id))
919 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
920 priv->default_clipboard_change_handler_id);
922 if (priv->account_removed_handler_id &&
923 g_signal_handler_is_connected (modest_runtime_get_account_store (),
924 priv->account_removed_handler_id))
925 g_signal_handler_disconnect(modest_runtime_get_account_store (),
926 priv->account_removed_handler_id);
930 modest_msg_edit_window_finalize (GObject *obj)
932 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
934 /* Sanity check: shouldn't be needed, the window mgr should
935 call this function before */
936 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
938 if (priv->font_dialog != NULL) {
939 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
942 if (priv->clipboard_text != NULL) {
943 g_free (priv->clipboard_text);
944 priv->clipboard_text = NULL;
947 if (priv->draft_msg != NULL) {
948 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
949 if (TNY_IS_HEADER (header)) {
950 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
951 modest_window_mgr_unregister_header (mgr, header);
953 g_object_unref (priv->draft_msg);
954 priv->draft_msg = NULL;
956 if (priv->outbox_msg != NULL) {
957 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
958 if (TNY_IS_HEADER (header)) {
959 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
960 modest_window_mgr_unregister_header (mgr, header);
962 g_object_unref (priv->outbox_msg);
963 priv->outbox_msg = NULL;
965 if (priv->correct_scroll_idle > 0) {
966 g_source_remove (priv->correct_scroll_idle);
967 priv->correct_scroll_idle = 0;
969 if (priv->scroll_drag_timeout_id > 0) {
970 g_source_remove (priv->scroll_drag_timeout_id);
971 priv->scroll_drag_timeout_id = 0;
973 if (priv->clipboard_owner_idle > 0) {
974 g_source_remove (priv->clipboard_owner_idle);
975 priv->clipboard_owner_idle = 0;
977 if (priv->original_account_name)
978 g_free (priv->original_account_name);
979 g_free (priv->msg_uid);
980 g_free (priv->last_search);
981 g_free (priv->references);
982 g_free (priv->in_reply_to);
983 g_object_unref (priv->faces_model);
984 g_object_unref (priv->sizes_model);
985 g_object_unref (priv->attachments);
986 g_object_unref (priv->images);
988 /* This had to stay alive for as long as the picker that used it: */
989 modest_pair_list_free (priv->from_field_protos);
991 G_OBJECT_CLASS(parent_class)->finalize (obj);
995 pixbuf_size_prepared (GdkPixbufLoader *loader,
998 ModestMsgEditWindow *self)
1000 gint new_height, new_width;
1003 new_height = height;
1007 if (width > IMAGE_MAX_WIDTH) {
1008 new_height = height * IMAGE_MAX_WIDTH / width;
1009 new_width = IMAGE_MAX_WIDTH;
1012 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1016 pixbuf_from_stream (TnyStream *stream,
1017 const gchar *mime_type,
1018 guint64 *stream_size,
1019 ModestMsgEditWindow *self)
1021 GdkPixbufLoader *loader;
1024 GError *error = NULL;
1028 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1030 if (loader == NULL) {
1035 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1037 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1039 tny_stream_reset (TNY_STREAM (stream));
1040 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1041 unsigned char read_buffer[128];
1043 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1045 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1048 /* Allow some UI responsiveness */
1049 while (gtk_events_pending ())
1050 gtk_main_iteration ();
1052 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1054 gdk_pixbuf_loader_close (loader, &error);
1057 g_error_free (error);
1058 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1060 g_object_ref (pixbuf);
1061 g_object_unref (loader);
1066 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1067 GdkPixbuf *new_pixbuf;
1069 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1070 gdk_pixbuf_get_width (pixbuf);
1071 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1072 g_object_unref (pixbuf);
1073 pixbuf = new_pixbuf;
1077 *stream_size = size;
1083 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1085 ModestMsgEditWindowPrivate *priv;
1088 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1090 g_object_ref (self);
1091 for (iter = tny_list_create_iterator (attachments);
1092 !tny_iterator_is_done (iter);
1093 tny_iterator_next (iter)) {
1094 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1095 const gchar *cid = tny_mime_part_get_content_id (part);
1096 const gchar *mime_type = tny_mime_part_get_content_type (part);
1097 if ((cid != NULL)&&(mime_type != NULL)) {
1098 guint64 stream_size;
1099 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1100 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1103 g_object_unref (stream);
1105 if (pixbuf != NULL) {
1106 priv->images_count ++;
1107 priv->images_size += stream_size;
1108 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1109 g_object_unref (pixbuf);
1112 g_object_unref (part);
1114 g_object_unref (iter);
1115 g_object_unref (self);
1119 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1121 TnyMimePart *parent = NULL;
1122 const gchar *content_type = NULL;
1123 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1125 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1127 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1128 parent = g_object_ref (msg);
1129 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1130 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1133 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1134 iter = tny_list_create_iterator (parts);
1135 while (!tny_iterator_is_done (iter)) {
1137 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1138 content_type = tny_mime_part_get_content_type (part);
1139 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1143 g_object_unref (part);
1145 tny_iterator_next (iter);
1147 g_object_unref (iter);
1148 g_object_unref (parts);
1151 if (parent != NULL) {
1152 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1155 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1156 iter = tny_list_create_iterator (parts);
1157 while (!tny_iterator_is_done (iter)) {
1159 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1160 content_type = tny_mime_part_get_content_type (part);
1161 if (content_type && g_str_has_prefix (content_type, "image/")) {
1162 tny_list_prepend (priv->images, (GObject *) part);
1164 g_object_unref (part);
1165 tny_iterator_next (iter);
1167 g_object_unref (iter);
1168 g_object_unref (parts);
1169 g_object_unref (parent);
1174 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1177 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1179 for (iter = tny_list_create_iterator (attachments) ;
1180 !tny_iterator_is_done (iter);
1181 tny_iterator_next (iter)) {
1182 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1183 const gchar *cid = tny_mime_part_get_content_id (part);
1185 char *invalid = NULL;
1186 gint int_cid = strtol (cid, &invalid, 10);
1187 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1188 priv->next_cid = int_cid + 1;
1191 g_object_unref (part);
1193 g_object_unref (iter);
1197 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1200 gchar *to, *cc, *bcc, *subject;
1202 ModestMsgEditWindowPrivate *priv;
1203 ModestWindowPrivate *parent_priv;
1205 TnyHeaderFlags priority_flags;
1206 TnyFolder *msg_folder;
1207 gboolean is_html = FALSE;
1208 gboolean field_view_set;
1210 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1211 g_return_if_fail (TNY_IS_MSG (msg));
1213 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1214 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1216 header = tny_msg_get_header (msg);
1217 to = tny_header_dup_to (header);
1218 cc = tny_header_dup_cc (header);
1219 bcc = tny_header_dup_bcc (header);
1220 subject = tny_header_dup_subject (header);
1222 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1223 priority_flags = tny_header_get_priority (header);
1226 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1228 field_view_set = TRUE;
1230 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1231 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1232 gtk_widget_show (priv->cc_caption);
1233 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1234 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1235 gtk_widget_hide (priv->cc_caption);
1236 field_view_set = FALSE;
1238 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1240 field_view_set = TRUE;
1242 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1243 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1244 gtk_widget_show (priv->bcc_caption);
1245 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1246 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1247 gtk_widget_hide (priv->bcc_caption);
1248 field_view_set = FALSE;
1250 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1254 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1255 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1258 update_window_title (self);
1260 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1261 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1263 if ((body == NULL)||(body[0] == '\0')) {
1265 body = modest_text_utils_convert_to_html ("");
1268 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1269 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1272 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1275 /* Add attachments to the view */
1276 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1277 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1278 if (tny_list_get_length (priv->attachments) == 0) {
1279 gtk_widget_hide (priv->attachments_caption);
1281 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1282 gtk_widget_show_all (priv->attachments_caption);
1284 get_related_images (self, msg);
1285 update_next_cid (self, priv->attachments);
1286 update_next_cid (self, priv->images);
1287 replace_with_images (self, priv->images);
1289 if (preserve_is_rich && !is_html) {
1290 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1291 /* Get the default format required from configuration */
1292 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1293 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1296 /* Set the default focus depending on having already a To: field or not */
1297 if ((!to)||(*to == '\0')) {
1298 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1300 gtk_widget_grab_focus (priv->msg_body);
1303 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1305 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1306 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1308 modest_msg_edit_window_set_modified (self, FALSE);
1310 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1311 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1312 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1313 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1315 if (priv->msg_uid) {
1316 g_free (priv->msg_uid);
1317 priv->msg_uid = NULL;
1320 /* we should set a reference to the incoming message if it is a draft */
1321 msg_folder = tny_msg_get_folder (msg);
1323 if (modest_tny_folder_is_local_folder (msg_folder)) {
1324 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1325 if (type == TNY_FOLDER_TYPE_INVALID)
1326 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1328 if (type == TNY_FOLDER_TYPE_DRAFTS)
1329 priv->draft_msg = g_object_ref(msg);
1330 if (type == TNY_FOLDER_TYPE_OUTBOX)
1331 priv->outbox_msg = g_object_ref(msg);
1332 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1334 g_object_unref (msg_folder);
1345 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1347 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1348 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1349 GtkWidget *placeholder;
1350 GtkWidget *tool_item;
1355 GtkWidget *sizes_menu;
1356 GtkWidget *fonts_menu;
1362 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1363 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1364 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1365 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1367 /* Font color placeholder */
1368 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1369 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1372 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1373 priv->font_color_button = hildon_color_button_new ();
1374 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1375 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1376 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1377 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1378 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1379 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1380 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1381 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1383 G_CALLBACK (modest_msg_edit_window_color_button_change),
1386 /* Font size and face placeholder */
1387 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1388 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1390 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1391 priv->size_tool_button_label = gtk_label_new (NULL);
1392 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1393 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1394 size_text, "</span>", NULL);
1395 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1396 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1398 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1399 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1400 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1401 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1402 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1403 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1404 gtk_widget_set_sensitive (arrow, FALSE);
1405 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1406 sizes_menu = gtk_menu_new ();
1407 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1408 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1411 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1412 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1414 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1418 if (wp_font_size[size_index] == 12)
1419 priv->current_size_index = size_index;
1423 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1424 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1425 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1426 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1427 priv->font_size_toolitem = tool_item;
1430 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1431 priv->font_tool_button_label = gtk_label_new (NULL);
1432 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1433 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1434 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1436 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1437 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1438 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1439 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1440 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1441 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1442 gtk_widget_set_sensitive (arrow, FALSE);
1443 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1444 fonts_menu = gtk_menu_new ();
1445 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1446 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1449 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1451 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1452 0, wp_get_font_name (font_index),
1455 if (font_index == DEFAULT_FONT)
1456 priv->current_face_index = font_index;
1458 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1459 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1460 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1461 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1462 priv->font_face_toolitem = tool_item;
1464 /* Set expand and homogeneous for remaining items */
1465 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1466 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1467 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1468 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1469 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1470 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1471 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1472 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1473 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1475 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1476 will not show the tool items added to the placeholders) */
1477 gtk_widget_show_all (parent_priv->toolbar);
1479 /* Set the no show all *after* showing all items. We do not
1480 want the toolbar to be shown with a show all because it
1481 could go agains the gconf setting regarding showing or not
1482 the toolbar of the editor window */
1483 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1489 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1492 ModestWindowPrivate *parent_priv;
1493 ModestMsgEditWindowPrivate *priv;
1494 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1495 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1496 ModestWindowMgr *mgr = NULL;
1498 g_return_val_if_fail (msg, NULL);
1499 g_return_val_if_fail (account_name, NULL);
1501 mgr = modest_runtime_get_window_mgr ();
1503 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1505 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1506 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1508 /* Menubar. Update the state of some toggles */
1509 priv->from_field_protos = get_transports ();
1510 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1511 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1512 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1513 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1515 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1516 hildon_touch_selector_get_current_text
1517 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1518 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1519 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1522 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1524 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1526 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1528 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1530 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1531 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1532 /* Add common dimming rules */
1533 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1534 modest_msg_edit_window_toolbar_dimming_entries,
1535 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1536 MODEST_WINDOW (obj));
1537 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1538 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1539 MODEST_WINDOW (obj));
1540 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1541 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1542 MODEST_WINDOW (obj));
1543 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1544 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1545 MODEST_WINDOW (obj));
1546 /* Insert dimming rules group for this window */
1547 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1548 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1550 /* Setup app menu */
1551 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1553 /* Checks the dimming rules */
1554 g_object_unref (toolbar_rules_group);
1555 g_object_unref (clipboard_rules_group);
1556 gtk_widget_hide (priv->priority_icon);
1557 gtk_widget_queue_resize (priv->subject_box);
1558 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1560 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1562 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1563 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1564 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1565 priv->update_caption_visibility = TRUE;
1567 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1569 /* Track account-removed signal, this window should be closed
1570 in the case we're creating a mail associated to the account
1572 priv->account_removed_handler_id =
1573 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1575 G_CALLBACK(on_account_removed),
1578 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1580 return (ModestWindow*) obj;
1584 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1586 GString **string_buffer = (GString **) user_data;
1588 *string_buffer = g_string_append (*string_buffer, buffer);
1594 * @result: A new string which should be freed with g_free().
1597 get_formatted_data (ModestMsgEditWindow *edit_window)
1599 ModestMsgEditWindowPrivate *priv;
1600 GString *string_buffer = g_string_new ("");
1602 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1604 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1606 modest_text_utils_hyperlinkify (string_buffer);
1608 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1610 return g_string_free (string_buffer, FALSE);
1615 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1618 const gchar *account_name;
1619 ModestMsgEditWindowPrivate *priv;
1620 TnyIterator *att_iter;
1622 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1624 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1626 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1627 g_return_val_if_fail (account_name, NULL);
1630 /* don't free these (except from) */
1631 data = g_slice_new0 (MsgData);
1632 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1634 data->account_name = g_strdup (account_name);
1635 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1636 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1637 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1638 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1639 data->references = g_strdup (priv->references);
1640 data->in_reply_to = g_strdup (priv->in_reply_to);
1641 if (priv->draft_msg) {
1642 data->draft_msg = g_object_ref (priv->draft_msg);
1643 } else if (priv->outbox_msg) {
1644 data->draft_msg = g_object_ref (priv->outbox_msg);
1646 data->draft_msg = NULL;
1649 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1651 gtk_text_buffer_get_bounds (buf, &b, &e);
1652 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1654 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1655 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1657 data->html_body = NULL;
1659 /* deep-copy the data */
1660 att_iter = tny_list_create_iterator (priv->attachments);
1661 data->attachments = NULL;
1662 while (!tny_iterator_is_done (att_iter)) {
1663 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1664 if (!(TNY_IS_MIME_PART(part))) {
1665 g_warning ("strange data in attachment list");
1666 g_object_unref (part);
1667 tny_iterator_next (att_iter);
1670 data->attachments = g_list_append (data->attachments,
1672 tny_iterator_next (att_iter);
1674 g_object_unref (att_iter);
1676 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1677 att_iter = tny_list_create_iterator (priv->images);
1678 data->images = NULL;
1679 while (!tny_iterator_is_done (att_iter)) {
1680 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1682 if (!(TNY_IS_MIME_PART(part))) {
1683 g_warning ("strange data in attachment list");
1684 g_object_unref (part);
1685 tny_iterator_next (att_iter);
1688 cid = tny_mime_part_get_content_id (part);
1690 gchar *image_tag_id;
1691 GtkTextTag *image_tag;
1693 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1694 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1695 g_free (image_tag_id);
1697 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1699 ((gtk_text_iter_has_tag (&iter, image_tag))||
1700 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1701 data->images = g_list_append (data->images,
1702 g_object_ref (part));
1704 g_object_unref (part);
1705 tny_iterator_next (att_iter);
1707 g_object_unref (att_iter);
1709 data->priority_flags = priv->priority_flags;
1716 unref_gobject (GObject *obj, gpointer data)
1718 if (!G_IS_OBJECT(obj))
1720 g_object_unref (obj);
1724 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1727 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1735 g_free (data->from);
1736 g_free (data->subject);
1737 g_free (data->plain_body);
1738 g_free (data->html_body);
1739 g_free (data->account_name);
1740 g_free (data->references);
1741 g_free (data->in_reply_to);
1743 if (data->draft_msg != NULL) {
1744 g_object_unref (data->draft_msg);
1745 data->draft_msg = NULL;
1748 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1749 g_list_free (data->attachments);
1750 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1751 g_list_free (data->images);
1753 g_slice_free (MsgData, data);
1757 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1759 guint64 *parts_size)
1761 ModestMsgEditWindowPrivate *priv;
1763 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1765 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1767 /* TODO: add images */
1768 *parts_size += priv->images_size;
1769 *parts_count += priv->images_count;
1774 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1777 ModestMsgEditWindowPrivate *priv = NULL;
1778 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1780 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1782 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1784 return MODEST_MSG_EDIT_FORMAT_HTML;
1786 return MODEST_MSG_EDIT_FORMAT_TEXT;
1790 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1791 ModestMsgEditFormat format)
1793 ModestMsgEditWindowPrivate *priv;
1795 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1796 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1799 case MODEST_MSG_EDIT_FORMAT_HTML:
1800 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1802 case MODEST_MSG_EDIT_FORMAT_TEXT:
1803 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1806 g_return_if_reached ();
1810 ModestMsgEditFormatState *
1811 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1813 ModestMsgEditFormatState *format_state = NULL;
1814 ModestMsgEditWindowPrivate *priv;
1815 WPTextBufferFormat *buffer_format;
1817 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1819 buffer_format = g_new0 (WPTextBufferFormat, 1);
1820 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1822 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1824 format_state = g_new0 (ModestMsgEditFormatState, 1);
1825 format_state->bold = buffer_format->bold&0x1;
1826 format_state->italics = buffer_format->italic&0x1;
1827 format_state->bullet = buffer_format->bullet&0x1;
1828 format_state->color = buffer_format->color;
1829 format_state->font_size = buffer_format->font_size;
1830 format_state->font_family = wp_get_font_name (buffer_format->font);
1831 format_state->justification = buffer_format->justification;
1832 g_free (buffer_format);
1834 return format_state;
1839 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1840 const ModestMsgEditFormatState *format_state)
1842 ModestMsgEditWindowPrivate *priv;
1843 WPTextBufferFormat *buffer_format;
1844 WPTextBufferFormat *current_format;
1846 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1847 g_return_if_fail (format_state != NULL);
1849 buffer_format = g_new0 (WPTextBufferFormat, 1);
1850 current_format = g_new0 (WPTextBufferFormat, 1);
1852 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1853 gtk_widget_grab_focus (priv->msg_body);
1854 buffer_format->bold = (format_state->bold != FALSE);
1855 buffer_format->italic = (format_state->italics != FALSE);
1856 buffer_format->color = format_state->color;
1857 buffer_format->font_size = format_state->font_size;
1858 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1859 buffer_format->justification = format_state->justification;
1860 buffer_format->bullet = format_state->bullet;
1862 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1864 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1865 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1866 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1867 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1868 buffer_format->cs.font = (buffer_format->font != current_format->font);
1869 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1870 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1872 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1873 if (buffer_format->cs.bold) {
1874 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1875 GINT_TO_POINTER (buffer_format->bold&0x1));
1877 if (buffer_format->cs.italic) {
1878 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1879 GINT_TO_POINTER (buffer_format->italic&0x1));
1881 if (buffer_format->cs.color) {
1882 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1883 GINT_TO_POINTER (&(buffer_format->color)));
1885 if (buffer_format->cs.font_size) {
1886 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1887 GINT_TO_POINTER (buffer_format->font_size));
1889 if (buffer_format->cs.justification) {
1890 switch (buffer_format->justification) {
1891 case GTK_JUSTIFY_LEFT:
1892 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1893 GINT_TO_POINTER(TRUE));
1895 case GTK_JUSTIFY_CENTER:
1896 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1897 GINT_TO_POINTER(TRUE));
1899 case GTK_JUSTIFY_RIGHT:
1900 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1901 GINT_TO_POINTER(TRUE));
1908 if (buffer_format->cs.font) {
1909 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1910 GINT_TO_POINTER (buffer_format->font));
1912 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1913 if (buffer_format->cs.bullet) {
1914 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1915 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1917 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1919 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1921 g_free (buffer_format);
1922 g_free (current_format);
1924 /* Check dimming rules */
1925 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1926 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1930 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1932 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1934 ModestWindowPrivate *parent_priv;
1935 ModestMsgEditWindowPrivate *priv;
1937 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1938 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1940 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1941 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1942 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1943 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1945 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1946 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1947 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1950 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1952 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1953 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1955 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1956 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1958 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1959 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1962 switch (buffer_format->justification)
1964 case GTK_JUSTIFY_LEFT:
1965 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1967 case GTK_JUSTIFY_CENTER:
1968 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1970 case GTK_JUSTIFY_RIGHT:
1971 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1978 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1980 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1981 G_CALLBACK (modest_msg_edit_window_color_button_change),
1983 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1984 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1985 G_CALLBACK (modest_msg_edit_window_color_button_change),
1988 if (priv->current_size_index != buffer_format->font_size) {
1992 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1993 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1997 priv->current_size_index = buffer_format->font_size;
1999 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2000 markup = g_strconcat ("<span font_family='Sans'>",
2001 size_text, "</span>", NULL);
2003 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2007 gtk_tree_path_free (path);
2010 if (priv->current_face_index != buffer_format->font) {
2014 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2015 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2019 priv->current_face_index = buffer_format->font;
2020 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2021 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2022 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2029 g_free (buffer_format);
2033 #ifdef MODEST_HILDON_VERSION_0
2035 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2038 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2039 ModestMsgEditWindowPrivate *priv;
2040 GtkWidget *dialog = NULL;
2042 GdkColor *new_color = NULL;
2044 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2045 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2047 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2048 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2049 g_free (buffer_format);
2051 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2052 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2053 if (new_color != NULL) {
2054 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2055 (gpointer) new_color);
2058 gtk_widget_destroy (dialog);
2063 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2066 ModestMsgEditWindowPrivate *priv;
2067 GtkWidget *dialog = NULL;
2069 GdkColor *old_color = NULL;
2070 const GdkColor *new_color = NULL;
2072 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2073 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2075 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2076 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2078 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2079 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2080 if (new_color != NULL)
2081 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2083 gtk_widget_destroy (dialog);
2089 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2092 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2093 ModestMsgEditWindowPrivate *priv;
2094 GtkWidget *dialog = NULL;
2096 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2097 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2099 dialog = hildon_color_chooser_new ();
2100 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2101 g_free (buffer_format);
2103 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2105 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2106 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2109 gtk_widget_destroy (dialog);
2114 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2117 ModestMsgEditWindowPrivate *priv;
2118 GtkWidget *dialog = NULL;
2119 GdkColor *old_color = NULL;
2121 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2122 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2124 dialog = hildon_color_chooser_new ();
2125 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2127 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2129 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2130 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2132 gtk_widget_destroy (dialog);
2135 #endif /*!MODEST_HILDON_VERSION_0*/
2140 create_stream_for_uri (const gchar* uri)
2145 TnyStream *result = NULL;
2147 GnomeVFSHandle *handle = NULL;
2148 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2149 if (test == GNOME_VFS_OK) {
2150 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2151 /* Streams over OBEX (Bluetooth) are not seekable but
2152 * we expect them to be (we might need to read them
2153 * several times). So if this is a Bluetooth URI just
2154 * read the whole file into memory (this is not a fast
2155 * protocol so we can assume that these files are not
2156 * going to be very big) */
2157 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2158 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2159 TnyStream *memstream = tny_camel_mem_stream_new ();
2160 tny_stream_write_to_stream (vfssstream, memstream);
2161 g_object_unref (vfssstream);
2164 result = vfssstream;
2172 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2175 ModestMsgEditWindowPrivate *priv;
2176 GtkWidget *dialog = NULL;
2178 GSList *uris = NULL;
2179 GSList *uri_node = NULL;
2181 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2183 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2184 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2185 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2187 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2189 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2190 GTK_WINDOW (dialog), GTK_WINDOW (window));
2192 response = gtk_dialog_run (GTK_DIALOG (dialog));
2194 case GTK_RESPONSE_OK:
2196 gchar *current_folder;
2197 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2198 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2199 if (current_folder && current_folder != '\0') {
2201 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2202 current_folder, &err);
2204 g_debug ("Error storing latest used folder: %s", err->message);
2208 g_free (current_folder);
2214 gtk_widget_destroy (dialog);
2216 g_object_ref (window);
2217 /* The operation could take some time so allow the dialog to be closed */
2218 while (gtk_events_pending ())
2219 gtk_main_iteration ();
2221 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2223 GnomeVFSHandle *handle = NULL;
2224 GnomeVFSResult result;
2225 GtkTextIter position;
2226 GtkTextMark *insert_mark;
2228 uri = (const gchar *) uri_node->data;
2229 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2230 if (result == GNOME_VFS_OK) {
2232 GnomeVFSFileInfo *info;
2233 gchar *filename, *basename, *escaped_filename;
2234 TnyMimePart *mime_part;
2236 const gchar *mime_type = NULL;
2237 GnomeVFSURI *vfs_uri;
2238 guint64 stream_size;
2240 gnome_vfs_close (handle);
2241 vfs_uri = gnome_vfs_uri_new (uri);
2243 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2244 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2245 g_free (escaped_filename);
2246 gnome_vfs_uri_unref (vfs_uri);
2247 info = gnome_vfs_file_info_new ();
2249 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2250 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2252 mime_type = gnome_vfs_file_info_get_mime_type (info);
2254 mime_part = tny_platform_factory_new_mime_part
2255 (modest_runtime_get_platform_factory ());
2257 TnyStream *stream = create_stream_for_uri (uri);
2259 if (stream == NULL) {
2261 modest_platform_information_banner (NULL, NULL,
2262 _FM("sfil_ib_opening_not_allowed"));
2264 g_object_unref (mime_part);
2265 gnome_vfs_file_info_unref (info);
2269 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2271 content_id = g_strdup_printf ("%d", priv->next_cid);
2272 tny_mime_part_set_content_id (mime_part, content_id);
2273 g_free (content_id);
2276 basename = g_path_get_basename (filename);
2277 tny_mime_part_set_filename (mime_part, basename);
2280 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2282 if (pixbuf != NULL) {
2283 priv->images_size += stream_size;
2284 priv->images_count ++;
2285 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2286 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2287 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2288 tny_mime_part_get_content_id (mime_part), pixbuf);
2289 g_object_unref (pixbuf);
2291 tny_list_prepend (priv->images, (GObject *) mime_part);
2292 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2294 modest_platform_information_banner (NULL, NULL,
2295 _("mail_ib_file_operation_failed"));
2299 g_object_unref (mime_part);
2300 gnome_vfs_file_info_unref (info);
2304 g_object_unref (window);
2308 on_attach_file_response (GtkDialog *dialog,
2312 GSList *uris = NULL;
2314 GnomeVFSFileSize total_size, allowed_size;
2315 ModestMsgEditWindow *window;
2316 ModestMsgEditWindowPrivate *priv;
2321 case GTK_RESPONSE_OK:
2323 gchar *current_folder;
2325 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2326 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2327 if (current_folder && current_folder != '\0') {
2329 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2330 current_folder, &err);
2332 g_debug ("Error storing latest used folder: %s", err->message);
2336 g_free (current_folder);
2343 window = MODEST_MSG_EDIT_WINDOW (user_data);
2344 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2346 /* allowed size is the maximum size - what's already there */
2347 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2348 &att_num, &att_size);
2349 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2352 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2354 const gchar *uri = (const gchar *) uri_node->data;
2357 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2359 if (total_size > allowed_size) {
2360 g_warning ("%s: total size: %u",
2361 __FUNCTION__, (unsigned int)total_size);
2364 allowed_size -= total_size;
2366 g_slist_foreach (uris, (GFunc) g_free, NULL);
2367 g_slist_free (uris);
2369 gtk_widget_destroy (GTK_WIDGET (dialog));
2373 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2375 GtkWidget *dialog = NULL;
2376 ModestMsgEditWindowPrivate *priv;
2379 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2381 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2383 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2386 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2387 GTK_FILE_CHOOSER_ACTION_OPEN);
2388 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2389 conf_folder = modest_conf_get_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2390 if (conf_folder && conf_folder[0] != '\0') {
2391 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2394 /* Set the default folder to images folder */
2395 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2396 ".documents", NULL);
2397 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2398 g_free (docs_folder);
2400 g_free (conf_folder);
2401 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2402 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2403 GTK_WINDOW (dialog), GTK_WINDOW (window));
2405 /* Connect to response & show */
2406 g_signal_connect (dialog, "response",
2407 G_CALLBACK (on_attach_file_response), window);
2408 gtk_widget_show (dialog);
2413 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2415 GnomeVFSFileSize allowed_size)
2418 GnomeVFSHandle *handle = NULL;
2419 ModestMsgEditWindowPrivate *priv;
2420 GnomeVFSResult result;
2421 GnomeVFSFileSize size = 0;
2422 g_return_val_if_fail (window, 0);
2423 g_return_val_if_fail (uri, 0);
2425 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2427 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2428 if (result == GNOME_VFS_OK) {
2429 TnyMimePart *mime_part;
2431 const gchar *mime_type = NULL;
2433 gchar *escaped_filename;
2436 GnomeVFSFileInfo *info;
2437 GnomeVFSURI *vfs_uri;
2439 gnome_vfs_close (handle);
2440 vfs_uri = gnome_vfs_uri_new (uri);
2443 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2444 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2445 g_free (escaped_filename);
2446 gnome_vfs_uri_unref (vfs_uri);
2448 info = gnome_vfs_file_info_new ();
2450 if (gnome_vfs_get_file_info (uri,
2452 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2454 mime_type = gnome_vfs_file_info_get_mime_type (info);
2455 mime_part = tny_platform_factory_new_mime_part
2456 (modest_runtime_get_platform_factory ());
2458 /* try to get the attachment's size; this may fail for weird
2459 * file systems, like obex, upnp... */
2460 if (allowed_size != 0 &&
2461 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2463 if (size > allowed_size) {
2464 modest_platform_information_banner (NULL, NULL,
2465 _FM("sfil_ib_opening_not_allowed"));
2470 g_warning ("%s: could not get attachment size", __FUNCTION__);
2472 stream = create_stream_for_uri (uri);
2474 if (stream == NULL) {
2476 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2478 g_object_unref (mime_part);
2480 gnome_vfs_file_info_unref (info);
2484 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2485 g_object_unref (stream);
2487 content_id = g_strdup_printf ("%d", priv->next_cid);
2488 tny_mime_part_set_content_id (mime_part, content_id);
2489 g_free (content_id);
2492 basename = g_path_get_basename (filename);
2493 tny_mime_part_set_filename (mime_part, basename);
2496 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2497 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2499 info->size == 0, info->size);
2500 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2501 gtk_widget_show_all (priv->attachments_caption);
2502 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2504 g_object_unref (mime_part);
2505 gnome_vfs_file_info_unref (info);
2512 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2515 ModestMsgEditWindowPrivate *priv;
2518 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2519 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2521 if (att_list == NULL) {
2522 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2523 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2524 g_object_unref (att_list);
2529 g_object_ref (att_list);
2532 if (tny_list_get_length (att_list) == 0) {
2533 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2535 gboolean dialog_response;
2536 gchar *message = NULL;
2537 gchar *filename = NULL;
2539 if (tny_list_get_length (att_list) == 1) {
2541 iter = tny_list_create_iterator (att_list);
2542 part = (TnyMimePart *) tny_iterator_get_current (iter);
2543 g_object_unref (iter);
2544 if (TNY_IS_MSG (part)) {
2545 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2547 filename = tny_header_dup_subject (header);
2548 g_object_unref (header);
2550 if (filename == NULL) {
2551 filename = g_strdup (_("mail_va_no_subject"));
2554 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2556 g_object_unref (part);
2558 filename = g_strdup ("");
2560 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2561 "emev_nc_delete_attachments",
2562 tny_list_get_length (att_list)), filename);
2565 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2569 if (dialog_response != GTK_RESPONSE_OK) {
2570 g_object_unref (att_list);
2574 for (iter = tny_list_create_iterator (att_list);
2575 !tny_iterator_is_done (iter);
2576 tny_iterator_next (iter)) {
2577 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2578 const gchar *att_id;
2579 tny_list_remove (priv->attachments, (GObject *) mime_part);
2581 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2583 if (tny_list_get_length (priv->attachments) == 0)
2584 gtk_widget_hide (priv->attachments_caption);
2585 att_id = tny_mime_part_get_content_id (mime_part);
2587 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2589 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2590 g_object_unref (mime_part);
2592 g_object_unref (iter);
2595 g_object_unref (att_list);
2597 /* if the last attachment has been removed, focus the Subject: field */
2598 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2599 gtk_widget_grab_focus (priv->subject_field);
2603 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2606 ModestMsgEditWindowPrivate *priv;
2607 GdkColor *new_color;
2608 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2610 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2611 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2614 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2616 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2618 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2620 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2625 font_size_clicked (GtkToolButton *button,
2626 ModestMsgEditWindow *window)
2628 ModestMsgEditWindowPrivate *priv;
2629 GtkWidget *selector, *dialog;
2631 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2633 selector = hildon_touch_selector_new ();
2634 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2635 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2637 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2638 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2639 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2641 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2645 WPTextBufferFormat format;
2647 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2649 memset (&format, 0, sizeof (format));
2650 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2652 format.cs.font_size = TRUE;
2653 format.cs.text_position = TRUE;
2654 format.cs.font = TRUE;
2655 format.font_size = new_index;
2656 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2658 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2659 GINT_TO_POINTER (new_index)))
2660 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2662 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2663 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2664 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2665 size_text, "</span>", NULL);
2667 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2671 gtk_widget_destroy (dialog);
2673 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2678 font_face_clicked (GtkToolButton *button,
2679 ModestMsgEditWindow *window)
2681 ModestMsgEditWindowPrivate *priv;
2682 GtkWidget *selector, *dialog;
2683 GtkCellRenderer *renderer;
2685 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2687 selector = hildon_touch_selector_new ();
2688 renderer = gtk_cell_renderer_text_new ();
2689 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2690 renderer, "family", 0, "text", 0, NULL);
2691 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2693 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2694 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2695 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2697 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2698 gint new_font_index;
2702 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2703 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2704 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2708 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2710 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2711 GINT_TO_POINTER(new_font_index)))
2712 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2714 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2715 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2717 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2721 gtk_tree_path_free (path);
2724 gtk_widget_destroy (dialog);
2726 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2731 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2734 ModestMsgEditWindowPrivate *priv = NULL;
2735 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2737 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2738 if (!priv->update_caption_visibility)
2741 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2743 gtk_widget_show (priv->cc_caption);
2745 gtk_widget_hide (priv->cc_caption);
2747 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2751 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2754 ModestMsgEditWindowPrivate *priv = NULL;
2755 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2757 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2758 if (!priv->update_caption_visibility)
2761 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2763 gtk_widget_show (priv->bcc_caption);
2765 gtk_widget_hide (priv->bcc_caption);
2767 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2771 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2772 ModestRecptEditor *editor)
2774 ModestMsgEditWindowPrivate *priv;
2776 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2777 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2779 /* we check for low-mem; in that case, show a warning, and don't allow
2780 * for the addressbook
2782 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2785 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2787 if (editor == NULL) {
2788 GtkWidget *view_focus;
2789 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2791 /* This code should be kept in sync with ModestRecptEditor. The
2792 textview inside the recpt editor is the one that really gets the
2793 focus. As it's inside a scrolled window, and this one inside the
2794 hbox recpt editor inherits from, we'll need to go up in the
2795 hierarchy to know if the text view is part of the recpt editor
2796 or if it's a different text entry */
2798 if (gtk_widget_get_parent (view_focus)) {
2799 GtkWidget *first_parent;
2801 first_parent = gtk_widget_get_parent (view_focus);
2802 if (gtk_widget_get_parent (first_parent) &&
2803 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2804 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2809 editor = MODEST_RECPT_EDITOR (priv->to_field);
2813 modest_address_book_select_addresses (editor);
2818 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2820 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2822 modest_msg_edit_window_open_addressbook (window, NULL);
2826 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2827 gboolean show_toolbar)
2829 ModestWindowPrivate *parent_priv;
2831 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2832 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2834 /* We can not just use the code of
2835 modest_msg_edit_window_setup_toolbar because it has a
2836 mixture of both initialization and creation code. */
2838 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2840 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2844 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2845 TnyHeaderFlags priority_flags)
2847 ModestMsgEditWindowPrivate *priv;
2848 ModestWindowPrivate *parent_priv;
2850 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2852 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2853 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2855 if (priv->priority_flags != priority_flags) {
2856 GtkAction *priority_action = NULL;
2858 priv->priority_flags = priority_flags;
2860 switch (priority_flags) {
2861 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2862 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2863 MODEST_HEADER_ICON_HIGH,
2864 HILDON_ICON_SIZE_SMALL);
2865 gtk_widget_show (priv->priority_icon);
2866 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2867 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2869 case TNY_HEADER_FLAG_LOW_PRIORITY:
2870 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2871 MODEST_HEADER_ICON_LOW,
2872 HILDON_ICON_SIZE_SMALL);
2873 gtk_widget_show (priv->priority_icon);
2874 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2875 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2878 gtk_widget_hide (priv->priority_icon);
2879 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2880 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2883 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2884 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2886 gtk_widget_queue_resize (priv->subject_box);
2890 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2893 ModestMsgEditWindowPrivate *priv;
2894 ModestWindowPrivate *parent_priv;
2895 gint current_format;
2897 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2899 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2900 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2902 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2903 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2905 if (current_format != file_format) {
2906 switch (file_format) {
2907 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2908 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2909 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2911 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2915 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2916 response = gtk_dialog_run (GTK_DIALOG (dialog));
2917 gtk_widget_destroy (dialog);
2918 if (response == GTK_RESPONSE_OK) {
2919 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2921 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2922 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2927 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2928 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2929 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2934 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2937 ModestMsgEditWindowPrivate *priv;
2938 WPTextBufferFormat oldfmt, fmt;
2939 gint old_position = 0;
2943 GdkColor *color = NULL;
2944 gboolean bold, bold_set, italic, italic_set;
2945 gboolean underline, underline_set;
2946 gboolean strikethrough, strikethrough_set;
2947 gboolean position_set;
2948 gboolean font_size_set, font_set, color_set;
2951 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2952 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2954 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2955 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2956 GTK_WINDOW(dialog), GTK_WINDOW (window));
2958 /* First we get the currently selected font information */
2959 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2961 switch (oldfmt.text_position) {
2962 case TEXT_POSITION_NORMAL:
2965 case TEXT_POSITION_SUPERSCRIPT:
2973 g_object_set (G_OBJECT (dialog),
2974 "bold", oldfmt.bold != FALSE,
2975 "bold-set", !oldfmt.cs.bold,
2976 "underline", oldfmt.underline != FALSE,
2977 "underline-set", !oldfmt.cs.underline,
2978 "italic", oldfmt.italic != FALSE,
2979 "italic-set", !oldfmt.cs.italic,
2980 "strikethrough", oldfmt.strikethrough != FALSE,
2981 "strikethrough-set", !oldfmt.cs.strikethrough,
2982 "color", &oldfmt.color,
2983 "color-set", !oldfmt.cs.color,
2984 "size", wp_font_size[oldfmt.font_size],
2985 "size-set", !oldfmt.cs.font_size,
2986 "position", old_position,
2987 "position-set", !oldfmt.cs.text_position,
2988 "family", wp_get_font_name (oldfmt.font),
2989 "family-set", !oldfmt.cs.font,
2992 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2993 GTK_WINDOW (dialog), GTK_WINDOW (window));
2994 gtk_widget_show_all (dialog);
2995 priv->font_dialog = dialog;
2996 response = gtk_dialog_run (GTK_DIALOG (dialog));
2997 priv->font_dialog = NULL;
2998 if (response == GTK_RESPONSE_OK) {
3000 g_object_get( dialog,
3002 "bold-set", &bold_set,
3003 "underline", &underline,
3004 "underline-set", &underline_set,
3006 "italic-set", &italic_set,
3007 "strikethrough", &strikethrough,
3008 "strikethrough-set", &strikethrough_set,
3010 "color-set", &color_set,
3012 "size-set", &font_size_set,
3013 "family", &font_name,
3014 "family-set", &font_set,
3015 "position", &position,
3016 "position-set", &position_set,
3021 if (response == GTK_RESPONSE_OK) {
3022 memset(&fmt, 0, sizeof(fmt));
3028 fmt.italic = italic;
3029 fmt.cs.italic = TRUE;
3031 if (underline_set) {
3032 fmt.underline = underline;
3033 fmt.cs.underline = TRUE;
3035 if (strikethrough_set) {
3036 fmt.strikethrough = strikethrough;
3037 fmt.cs.strikethrough = TRUE;
3042 ? TEXT_POSITION_NORMAL
3043 : ( ( position == 1 )
3044 ? TEXT_POSITION_SUPERSCRIPT
3045 : TEXT_POSITION_SUBSCRIPT );
3046 fmt.cs.text_position = TRUE;
3047 fmt.font_size = oldfmt.font_size;
3051 fmt.cs.color = TRUE;
3054 fmt.font = wp_get_font_index(font_name,
3059 if (font_size_set) {
3060 fmt.cs.font_size = TRUE;
3061 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3063 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3064 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3066 gtk_widget_destroy (dialog);
3068 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3072 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3074 ModestMsgEditWindowPrivate *priv;
3076 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3077 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3079 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3081 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3082 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3086 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3088 ModestMsgEditWindowPrivate *priv;
3090 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3091 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3093 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3095 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3096 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3101 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3103 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3105 priv->can_undo = can_undo;
3109 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3111 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3113 priv->can_redo = can_redo;
3117 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3119 ModestMsgEditWindowPrivate *priv;
3120 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3121 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3123 return priv->can_undo;
3127 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3129 ModestMsgEditWindowPrivate *priv;
3130 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3131 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3133 return priv->can_redo;
3138 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3141 GtkTextIter match_start, match_end;
3143 if (image_id == NULL)
3146 gtk_text_buffer_get_start_iter (buffer, &iter);
3148 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3149 GSList *tags = gtk_text_iter_get_tags (&match_start);
3151 for (node = tags; node != NULL; node = g_slist_next (node)) {
3152 GtkTextTag *tag = (GtkTextTag *) node->data;
3153 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3154 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3155 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3157 offset = gtk_text_iter_get_offset (&match_start);
3158 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3159 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3163 gtk_text_iter_forward_char (&iter);
3168 message_is_empty (ModestMsgEditWindow *window)
3170 ModestMsgEditWindowPrivate *priv = NULL;
3172 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3173 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3175 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3176 * so we can ignore markup.
3178 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3181 count = gtk_text_buffer_get_char_count (buf);
3187 msg_body_focus (GtkWidget *focus,
3188 GdkEventFocus *event,
3192 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3193 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3194 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3199 recpt_field_changed (GtkTextBuffer *buffer,
3200 ModestMsgEditWindow *editor)
3202 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3203 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3207 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3209 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3210 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3214 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3217 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3218 GtkTextBuffer *buffer;
3220 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3221 gtk_text_buffer_set_modified (buffer, modified);
3222 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3223 gtk_text_buffer_set_modified (buffer, modified);
3224 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3225 gtk_text_buffer_set_modified (buffer, modified);
3226 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3230 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3232 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3233 const char *account_name;
3234 GtkTextBuffer *buffer;
3236 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3237 if (gtk_text_buffer_get_modified (buffer))
3239 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3240 if (gtk_text_buffer_get_modified (buffer))
3242 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3243 if (gtk_text_buffer_get_modified (buffer))
3245 if (gtk_text_buffer_get_modified (priv->text_buffer))
3247 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3248 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3259 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3261 ModestMsgEditWindowPrivate *priv = NULL;
3263 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3264 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3266 /* check if there's no recipient added */
3267 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3268 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3269 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3270 /* no recipient contents, then select contacts */
3271 modest_msg_edit_window_open_addressbook (window, NULL);
3275 g_object_ref (window);
3276 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3277 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3278 g_object_unref (window);
3281 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3282 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3283 g_object_unref (window);
3286 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3287 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3288 g_object_unref (window);
3292 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3293 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3294 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3295 g_object_unref (window);
3302 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3303 ModestMsgEditWindow *window)
3305 modest_msg_edit_window_offer_attach_file (window);
3309 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3311 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3313 return priv->clipboard_text;
3317 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3319 ModestMsgEditWindow *window)
3321 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3322 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3325 /* It could happen that the window was already closed */
3326 if (!GTK_WIDGET_VISIBLE (window))
3329 g_object_ref (window);
3330 text = gtk_clipboard_wait_for_text (selection_clipboard);
3332 if (priv->clipboard_text != NULL) {
3333 g_free (priv->clipboard_text);
3335 priv->clipboard_text = text;
3337 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3339 g_object_unref (window);
3342 static gboolean clipboard_owner_change_idle (gpointer userdata)
3344 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3345 ModestMsgEditWindowPrivate *priv;
3347 gdk_threads_enter ();
3348 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3349 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3351 priv->clipboard_owner_idle = 0;
3352 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3353 gdk_threads_leave ();
3359 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3361 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3362 if (priv->clipboard_owner_idle == 0) {
3363 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3364 clipboard_owner_change_idle,
3365 g_object_ref (window),
3371 subject_field_move_cursor (GtkEntry *entry,
3372 GtkMovementStep step,
3377 /* It could happen that the window was already closed */
3378 if (!GTK_WIDGET_VISIBLE (window))
3381 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3385 update_window_title (ModestMsgEditWindow *window)
3387 ModestMsgEditWindowPrivate *priv = NULL;
3388 const gchar *subject;
3390 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3391 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3392 if (subject == NULL || subject[0] == '\0')
3393 subject = _("mail_va_new_email");
3395 gtk_window_set_title (GTK_WINDOW (window), subject);
3400 subject_field_changed (GtkEditable *editable,
3401 ModestMsgEditWindow *window)
3403 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3404 update_window_title (window);
3405 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3406 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3407 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3411 subject_field_insert_text (GtkEditable *editable,
3413 gint new_text_length,
3415 ModestMsgEditWindow *window)
3417 GString *result = g_string_new ("");
3419 gint result_len = 0;
3420 const gchar *entry_text = NULL;
3423 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3424 old_length = g_utf8_strlen (entry_text, -1);
3426 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3427 gunichar c = g_utf8_get_char_validated (current, 8);
3428 /* Invalid unichar, stop */
3434 result = g_string_append_unichar (result, c);
3438 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3439 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3442 /* Prevent endless recursion */
3443 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3444 g_signal_emit_by_name (editable, "insert-text",
3445 (gpointer) result->str, (gpointer) result->len,
3446 (gpointer) position, (gpointer) window);
3447 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3451 if (result_len + old_length > 1000) {
3452 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3453 _CS("ckdg_ib_maximum_characters_reached"));
3455 g_string_free (result, TRUE);
3459 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3462 ModestMsgEditWindowPrivate *priv = NULL;
3464 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3465 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3467 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3470 gtk_widget_show_all (priv->find_toolbar);
3471 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3473 gtk_widget_hide_all (priv->find_toolbar);
3474 gtk_widget_grab_focus (priv->msg_body);
3479 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3481 GtkTextIter *match_start,
3482 GtkTextIter *match_end)
3484 GtkTextIter end_iter;
3485 gchar *str_casefold;
3488 gchar *range_casefold;
3491 gboolean result = FALSE;
3498 gtk_text_iter_forward_to_end (&end_iter);
3500 str_casefold = g_utf8_casefold (str, -1);
3501 str_chars_n = strlen (str);
3503 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3504 range_casefold = g_utf8_casefold (range_text, -1);
3505 range_chars_n = strlen (range_casefold);
3507 if (range_chars_n < str_chars_n) {
3508 g_free (str_casefold);
3509 g_free (range_text);
3510 g_free (range_casefold);
3514 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3515 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3516 if (!g_utf8_collate (range_subtext, str_casefold)) {
3517 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3519 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3520 match_start, match_end, NULL)) {
3521 g_warning ("Matched string with collate, but not matched in model");
3523 g_free (found_text);
3525 g_free (range_subtext);
3529 g_free (str_casefold);
3530 g_free (range_text);
3531 g_free (range_casefold);
3538 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3539 ModestMsgEditWindow *window)
3541 gchar *current_search = NULL;
3542 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3544 GtkTextIter selection_start, selection_end;
3545 GtkTextIter match_start, match_end;
3546 gboolean continue_search = FALSE;
3548 if (message_is_empty (window)) {
3549 g_free (priv->last_search);
3550 priv->last_search = NULL;
3551 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3555 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3556 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3557 g_free (current_search);
3558 g_free (priv->last_search);
3559 priv->last_search = NULL;
3560 /* Information banner about empty search */
3561 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3565 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3566 continue_search = TRUE;
3568 g_free (priv->last_search);
3569 priv->last_search = g_strdup (current_search);
3572 if (continue_search) {
3573 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3574 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3575 &match_start, &match_end);
3577 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3579 GtkTextIter buffer_start;
3580 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3581 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3582 &match_start, &match_end);
3584 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3587 /* Mark as selected the string found in search */
3589 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3590 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3591 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3593 g_free (priv->last_search);
3594 priv->last_search = NULL;
3596 g_free (current_search);
3600 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3602 ModestMsgEditWindowPrivate *priv;
3604 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3609 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3612 ModestMsgEditWindowPrivate *priv;
3614 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3619 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3620 ModestMsgEditWindow *window)
3622 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3626 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3629 ModestMsgEditWindowPrivate *priv;
3630 TnyHeader *header = NULL;
3632 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3633 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3635 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3637 if (priv->draft_msg != NULL) {
3638 g_object_unref (priv->draft_msg);
3641 if (draft != NULL) {
3642 g_object_ref (draft);
3643 header = tny_msg_get_header (draft);
3644 if (priv->msg_uid) {
3645 g_free (priv->msg_uid);
3646 priv->msg_uid = NULL;
3648 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3651 priv->draft_msg = draft;
3655 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3656 GtkTextIter *start, GtkTextIter *end,
3659 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3660 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3663 if (tag == NULL) return;
3664 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3665 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3666 replace_with_images (window, priv->images);
3671 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3674 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3676 g_return_if_fail (TNY_IS_MIME_PART (part));
3677 tny_list_prepend (priv->attachments, (GObject *) part);
3678 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3679 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3680 gtk_widget_show_all (priv->attachments_caption);
3681 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3685 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3687 ModestMsgEditWindowPrivate *priv;
3689 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3690 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3692 return priv->msg_uid;
3696 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3697 ModestMsgEditWindowWidgetType widget_type)
3699 ModestMsgEditWindowPrivate *priv;
3701 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3702 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3704 switch (widget_type) {
3705 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3706 return priv->msg_body;
3708 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3709 return priv->to_field;
3711 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3712 return priv->cc_field;
3714 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3715 return priv->bcc_field;
3717 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3718 return priv->subject_field;
3720 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3721 return priv->attachments_view;
3729 remove_tags (WPTextBuffer *buffer)
3731 GtkTextIter start, end;
3733 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3734 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3736 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3740 on_account_removed (TnyAccountStore *account_store,
3741 TnyAccount *account,
3744 /* Do nothing if it's a store account, because we use the
3745 transport to send the messages */
3746 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3747 const gchar *parent_acc = NULL;
3748 const gchar *our_acc = NULL;
3750 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3751 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3752 /* Close this window if I'm showing a message of the removed account */
3753 if (strcmp (parent_acc, our_acc) == 0)
3754 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3759 from_field_changed (HildonPickerButton *button,
3760 ModestMsgEditWindow *self)
3762 ModestMsgEditWindowPrivate *priv;
3763 gboolean has_old_signature, has_new_signature;
3765 GtkTextIter match_start, match_end;
3766 ModestAccountMgr *mgr;
3768 gchar *full_signature;
3770 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3772 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3773 mgr = modest_runtime_get_account_mgr ();
3774 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3775 if (has_old_signature) {
3776 full_signature = g_strconcat ("\n--\n", signature, NULL);
3777 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3778 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3780 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3781 &match_start, &match_end, NULL)) {
3784 g_free (full_signature);
3788 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3789 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3790 if (has_new_signature) {
3791 full_signature = g_strconcat ("\n--\n", signature, NULL);
3792 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3793 g_free (full_signature);
3798 typedef struct _MessageSettingsHelper {
3799 ModestMsgEditWindow *window;
3800 GSList *priority_group;
3801 GSList *format_group;
3802 GtkToggleButton *current_priority;
3803 GtkToggleButton *current_format;
3804 } MessageSettingsHelper;
3807 on_priority_toggle (GtkToggleButton *button,
3808 MessageSettingsHelper *helper)
3811 ModestMsgEditWindowPrivate *priv;
3813 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3814 if (gtk_toggle_button_get_active (button)) {
3816 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3817 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3818 if ((node_button != button) &&
3819 gtk_toggle_button_get_active (node_button)) {
3820 gtk_toggle_button_set_active (node_button, FALSE);
3823 helper->current_priority = button;
3825 gboolean found = FALSE;
3826 /* If no one is active, activate it again */
3827 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3828 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3829 if (gtk_toggle_button_get_active (node_button)) {
3835 gtk_toggle_button_set_active (button, TRUE);
3841 on_format_toggle (GtkToggleButton *button,
3842 MessageSettingsHelper *helper)
3845 ModestMsgEditWindowPrivate *priv;
3847 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3848 if (gtk_toggle_button_get_active (button)) {
3850 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3851 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3852 if ((node_button != button) &&
3853 gtk_toggle_button_get_active (node_button)) {
3854 gtk_toggle_button_set_active (node_button, FALSE);
3857 helper->current_format = button;
3859 gboolean found = FALSE;
3860 /* If no one is active, activate it again */
3861 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3862 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3863 if (gtk_toggle_button_get_active (node_button)) {
3869 gtk_toggle_button_set_active (button, TRUE);
3876 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3881 GtkWidget *priority_hbox;
3882 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3883 GtkWidget *captioned;
3884 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3885 GtkWidget *format_hbox;
3886 GtkWidget *html_toggle, *text_toggle;
3887 ModestMsgEditWindowPrivate *priv;
3888 MessageSettingsHelper helper = {0,};
3890 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3891 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3892 helper.window = window;
3893 helper.priority_group = NULL;
3894 helper.format_group = NULL;
3896 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3897 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3899 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3900 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3901 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3902 vbox = gtk_vbox_new (FALSE, 0);
3903 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3904 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3905 gtk_container_add (GTK_CONTAINER (align), vbox);
3906 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3907 gtk_widget_show (align);
3908 gtk_widget_show (vbox);
3910 /* Priority toggles */
3911 priority_hbox = gtk_hbox_new (TRUE, 0);
3912 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3913 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3914 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3915 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3916 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3917 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3918 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3919 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3920 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3921 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3922 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3923 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3924 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3925 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3926 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3927 gtk_widget_show_all (priority_hbox);
3928 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3929 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3930 gtk_widget_show (captioned);
3931 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3933 /* format toggles */
3934 format_hbox = gtk_hbox_new (TRUE, 0);
3935 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3936 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3937 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3938 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3939 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3940 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3941 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3942 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3943 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3944 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3945 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3946 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3947 gtk_widget_show_all (format_hbox);
3948 gtk_widget_show (format_hbox);
3949 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3952 g_object_unref (title_sizegroup);
3953 g_object_unref (value_sizegroup);
3955 /* Set current values */
3956 switch (priv->priority_flags) {
3957 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3958 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3959 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3961 case TNY_HEADER_FLAG_LOW_PRIORITY:
3962 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3963 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3966 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3967 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3971 switch (modest_msg_edit_window_get_format (window)) {
3972 case MODEST_MSG_EDIT_FORMAT_TEXT:
3973 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3974 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3976 case MODEST_MSG_EDIT_FORMAT_HTML:
3978 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3979 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3983 /* Signal connects */
3984 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3985 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3986 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3987 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3988 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3990 /* Save settings if the user clicked on done */
3991 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3992 TnyHeaderFlags flags;
3993 ModestMsgEditFormat old_format, new_format;
3995 /* Set priority flags */
3996 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3997 if (priv->priority_flags != flags)
3998 modest_msg_edit_window_set_priority_flags (window, flags);
4000 /* Set edit format */
4001 old_format = modest_msg_edit_window_get_format (window);
4002 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4003 if (old_format != new_format) {
4004 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4005 modest_msg_edit_window_set_file_format (window, file_format);
4009 gtk_widget_destroy (dialog);
4010 g_slist_free (helper.priority_group);
4014 on_message_settings (GtkAction *action,
4015 ModestMsgEditWindow *window)
4017 modest_msg_edit_window_show_msg_settings_dialog (window);
4021 on_cc_button_toggled (HildonCheckButton *button,
4022 ModestMsgEditWindow *window)
4024 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4026 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4027 hildon_check_button_get_active (button));
4031 on_bcc_button_toggled (HildonCheckButton *button,
4032 ModestMsgEditWindow *window)
4034 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4036 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4037 hildon_check_button_get_active (button));
4041 setup_menu (ModestMsgEditWindow *self)
4043 ModestMsgEditWindowPrivate *priv = NULL;
4045 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4047 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4049 /* Settings menu buttons */
4050 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4051 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4053 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4054 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4055 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4057 priv->cc_button = hildon_check_button_new (0);
4058 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4059 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4061 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4063 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4064 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4065 priv->bcc_button = hildon_check_button_new (0);
4066 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4067 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4069 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4071 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4072 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4074 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4075 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4076 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4077 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4078 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4079 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4080 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4081 APP_MENU_CALLBACK (on_message_settings),
4083 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4084 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),