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_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox),
892 hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable)));
893 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
895 window_box = gtk_vbox_new (FALSE, 0);
896 gtk_container_add (GTK_CONTAINER(obj), window_box);
898 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
900 /* Set window icon */
901 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
903 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
904 g_object_unref (window_icon);
909 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
911 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
913 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
914 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
915 priv->clipboard_change_handler_id))
916 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
917 priv->clipboard_change_handler_id);
918 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
919 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
920 priv->default_clipboard_change_handler_id))
921 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
922 priv->default_clipboard_change_handler_id);
924 if (priv->account_removed_handler_id &&
925 g_signal_handler_is_connected (modest_runtime_get_account_store (),
926 priv->account_removed_handler_id))
927 g_signal_handler_disconnect(modest_runtime_get_account_store (),
928 priv->account_removed_handler_id);
932 modest_msg_edit_window_finalize (GObject *obj)
934 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
936 /* Sanity check: shouldn't be needed, the window mgr should
937 call this function before */
938 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
940 if (priv->font_dialog != NULL) {
941 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
944 if (priv->clipboard_text != NULL) {
945 g_free (priv->clipboard_text);
946 priv->clipboard_text = NULL;
949 if (priv->draft_msg != NULL) {
950 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
951 if (TNY_IS_HEADER (header)) {
952 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
953 modest_window_mgr_unregister_header (mgr, header);
955 g_object_unref (priv->draft_msg);
956 priv->draft_msg = NULL;
958 if (priv->outbox_msg != NULL) {
959 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
960 if (TNY_IS_HEADER (header)) {
961 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
962 modest_window_mgr_unregister_header (mgr, header);
964 g_object_unref (priv->outbox_msg);
965 priv->outbox_msg = NULL;
967 if (priv->correct_scroll_idle > 0) {
968 g_source_remove (priv->correct_scroll_idle);
969 priv->correct_scroll_idle = 0;
971 if (priv->scroll_drag_timeout_id > 0) {
972 g_source_remove (priv->scroll_drag_timeout_id);
973 priv->scroll_drag_timeout_id = 0;
975 if (priv->clipboard_owner_idle > 0) {
976 g_source_remove (priv->clipboard_owner_idle);
977 priv->clipboard_owner_idle = 0;
979 if (priv->original_account_name)
980 g_free (priv->original_account_name);
981 g_free (priv->msg_uid);
982 g_free (priv->last_search);
983 g_free (priv->references);
984 g_free (priv->in_reply_to);
985 g_object_unref (priv->faces_model);
986 g_object_unref (priv->sizes_model);
987 g_object_unref (priv->attachments);
988 g_object_unref (priv->images);
990 /* This had to stay alive for as long as the picker that used it: */
991 modest_pair_list_free (priv->from_field_protos);
993 G_OBJECT_CLASS(parent_class)->finalize (obj);
997 pixbuf_size_prepared (GdkPixbufLoader *loader,
1000 ModestMsgEditWindow *self)
1002 gint new_height, new_width;
1005 new_height = height;
1009 if (width > IMAGE_MAX_WIDTH) {
1010 new_height = height * IMAGE_MAX_WIDTH / width;
1011 new_width = IMAGE_MAX_WIDTH;
1014 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1018 pixbuf_from_stream (TnyStream *stream,
1019 const gchar *mime_type,
1020 guint64 *stream_size,
1021 ModestMsgEditWindow *self)
1023 GdkPixbufLoader *loader;
1026 GError *error = NULL;
1030 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1032 if (loader == NULL) {
1037 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1039 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1041 tny_stream_reset (TNY_STREAM (stream));
1042 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1043 unsigned char read_buffer[128];
1045 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1047 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1050 /* Allow some UI responsiveness */
1051 while (gtk_events_pending ())
1052 gtk_main_iteration ();
1054 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1056 gdk_pixbuf_loader_close (loader, &error);
1059 g_error_free (error);
1060 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1062 g_object_ref (pixbuf);
1063 g_object_unref (loader);
1068 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1069 GdkPixbuf *new_pixbuf;
1071 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1072 gdk_pixbuf_get_width (pixbuf);
1073 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1074 g_object_unref (pixbuf);
1075 pixbuf = new_pixbuf;
1079 *stream_size = size;
1085 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1087 ModestMsgEditWindowPrivate *priv;
1090 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1092 g_object_ref (self);
1093 for (iter = tny_list_create_iterator (attachments);
1094 !tny_iterator_is_done (iter);
1095 tny_iterator_next (iter)) {
1096 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1097 const gchar *cid = tny_mime_part_get_content_id (part);
1098 const gchar *mime_type = tny_mime_part_get_content_type (part);
1099 if ((cid != NULL)&&(mime_type != NULL)) {
1100 guint64 stream_size;
1101 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1102 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1105 g_object_unref (stream);
1107 if (pixbuf != NULL) {
1108 priv->images_count ++;
1109 priv->images_size += stream_size;
1110 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1111 g_object_unref (pixbuf);
1114 g_object_unref (part);
1116 g_object_unref (iter);
1117 g_object_unref (self);
1121 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1123 TnyMimePart *parent = NULL;
1124 const gchar *content_type = NULL;
1125 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1127 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1129 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1130 parent = g_object_ref (msg);
1131 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1132 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1135 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1136 iter = tny_list_create_iterator (parts);
1137 while (!tny_iterator_is_done (iter)) {
1139 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1140 content_type = tny_mime_part_get_content_type (part);
1141 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1145 g_object_unref (part);
1147 tny_iterator_next (iter);
1149 g_object_unref (iter);
1150 g_object_unref (parts);
1153 if (parent != NULL) {
1154 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1157 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1158 iter = tny_list_create_iterator (parts);
1159 while (!tny_iterator_is_done (iter)) {
1161 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1162 content_type = tny_mime_part_get_content_type (part);
1163 if (content_type && g_str_has_prefix (content_type, "image/")) {
1164 tny_list_prepend (priv->images, (GObject *) part);
1166 g_object_unref (part);
1167 tny_iterator_next (iter);
1169 g_object_unref (iter);
1170 g_object_unref (parts);
1171 g_object_unref (parent);
1176 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1179 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1181 for (iter = tny_list_create_iterator (attachments) ;
1182 !tny_iterator_is_done (iter);
1183 tny_iterator_next (iter)) {
1184 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1185 const gchar *cid = tny_mime_part_get_content_id (part);
1187 char *invalid = NULL;
1188 gint int_cid = strtol (cid, &invalid, 10);
1189 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1190 priv->next_cid = int_cid + 1;
1193 g_object_unref (part);
1195 g_object_unref (iter);
1199 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1202 gchar *to, *cc, *bcc, *subject;
1204 ModestMsgEditWindowPrivate *priv;
1205 ModestWindowPrivate *parent_priv;
1207 TnyHeaderFlags priority_flags;
1208 TnyFolder *msg_folder;
1209 gboolean is_html = FALSE;
1210 gboolean field_view_set;
1212 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1213 g_return_if_fail (TNY_IS_MSG (msg));
1215 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1216 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1218 header = tny_msg_get_header (msg);
1219 to = tny_header_dup_to (header);
1220 cc = tny_header_dup_cc (header);
1221 bcc = tny_header_dup_bcc (header);
1222 subject = tny_header_dup_subject (header);
1224 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1225 priority_flags = tny_header_get_priority (header);
1228 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1230 field_view_set = TRUE;
1232 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1233 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1234 gtk_widget_show (priv->cc_caption);
1235 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1236 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1237 gtk_widget_hide (priv->cc_caption);
1238 field_view_set = FALSE;
1240 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1242 field_view_set = TRUE;
1244 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1245 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1246 gtk_widget_show (priv->bcc_caption);
1247 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1248 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1249 gtk_widget_hide (priv->bcc_caption);
1250 field_view_set = FALSE;
1252 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1256 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1257 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1260 update_window_title (self);
1262 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1263 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1265 if ((body == NULL)||(body[0] == '\0')) {
1267 body = modest_text_utils_convert_to_html ("");
1270 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1271 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1274 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1277 /* Add attachments to the view */
1278 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1279 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1280 if (tny_list_get_length (priv->attachments) == 0) {
1281 gtk_widget_hide (priv->attachments_caption);
1283 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1284 gtk_widget_show_all (priv->attachments_caption);
1286 get_related_images (self, msg);
1287 update_next_cid (self, priv->attachments);
1288 update_next_cid (self, priv->images);
1289 replace_with_images (self, priv->images);
1291 if (preserve_is_rich && !is_html) {
1292 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1293 /* Get the default format required from configuration */
1294 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1295 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1298 /* Set the default focus depending on having already a To: field or not */
1299 if ((!to)||(*to == '\0')) {
1300 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1302 gtk_widget_grab_focus (priv->msg_body);
1305 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1307 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1308 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1310 modest_msg_edit_window_set_modified (self, FALSE);
1312 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1313 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1314 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1315 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1317 if (priv->msg_uid) {
1318 g_free (priv->msg_uid);
1319 priv->msg_uid = NULL;
1322 /* we should set a reference to the incoming message if it is a draft */
1323 msg_folder = tny_msg_get_folder (msg);
1325 if (modest_tny_folder_is_local_folder (msg_folder)) {
1326 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1327 if (type == TNY_FOLDER_TYPE_INVALID)
1328 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1330 if (type == TNY_FOLDER_TYPE_DRAFTS)
1331 priv->draft_msg = g_object_ref(msg);
1332 if (type == TNY_FOLDER_TYPE_OUTBOX)
1333 priv->outbox_msg = g_object_ref(msg);
1334 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1336 g_object_unref (msg_folder);
1347 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1349 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1350 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1351 GtkWidget *placeholder;
1352 GtkWidget *tool_item;
1357 GtkWidget *sizes_menu;
1358 GtkWidget *fonts_menu;
1364 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1365 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1366 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1367 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1369 /* Font color placeholder */
1370 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1371 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1374 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1375 priv->font_color_button = hildon_color_button_new ();
1376 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1377 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1378 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1379 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1380 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1381 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1382 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1383 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1385 G_CALLBACK (modest_msg_edit_window_color_button_change),
1388 /* Font size and face placeholder */
1389 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1390 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1392 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1393 priv->size_tool_button_label = gtk_label_new (NULL);
1394 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1395 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1396 size_text, "</span>", NULL);
1397 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1398 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1400 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1401 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1402 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1403 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1404 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1405 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1406 gtk_widget_set_sensitive (arrow, FALSE);
1407 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1408 sizes_menu = gtk_menu_new ();
1409 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1410 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1413 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1414 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1416 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1420 if (wp_font_size[size_index] == 12)
1421 priv->current_size_index = size_index;
1425 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1426 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1427 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1428 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1429 priv->font_size_toolitem = tool_item;
1432 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1433 priv->font_tool_button_label = gtk_label_new (NULL);
1434 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1435 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1436 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1438 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1439 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1440 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1441 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1442 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1443 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1444 gtk_widget_set_sensitive (arrow, FALSE);
1445 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1446 fonts_menu = gtk_menu_new ();
1447 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1448 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1451 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1453 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1454 0, wp_get_font_name (font_index),
1457 if (font_index == DEFAULT_FONT)
1458 priv->current_face_index = font_index;
1460 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1461 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1462 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1463 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1464 priv->font_face_toolitem = tool_item;
1466 /* Set expand and homogeneous for remaining items */
1467 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1468 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1469 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1470 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1471 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1472 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1473 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1474 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1475 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1477 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1478 will not show the tool items added to the placeholders) */
1479 gtk_widget_show_all (parent_priv->toolbar);
1481 /* Set the no show all *after* showing all items. We do not
1482 want the toolbar to be shown with a show all because it
1483 could go agains the gconf setting regarding showing or not
1484 the toolbar of the editor window */
1485 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1491 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1494 ModestWindowPrivate *parent_priv;
1495 ModestMsgEditWindowPrivate *priv;
1496 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1497 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1498 ModestWindowMgr *mgr = NULL;
1500 g_return_val_if_fail (msg, NULL);
1501 g_return_val_if_fail (account_name, NULL);
1503 mgr = modest_runtime_get_window_mgr ();
1505 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1507 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1508 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1510 /* Menubar. Update the state of some toggles */
1511 priv->from_field_protos = get_transports ();
1512 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1513 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1514 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1515 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1517 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1518 hildon_touch_selector_get_current_text
1519 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1520 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1521 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1524 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1526 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1528 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1530 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1532 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1533 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1534 /* Add common dimming rules */
1535 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1536 modest_msg_edit_window_toolbar_dimming_entries,
1537 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1538 MODEST_WINDOW (obj));
1539 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1540 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1541 MODEST_WINDOW (obj));
1542 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1543 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1544 MODEST_WINDOW (obj));
1545 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1546 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1547 MODEST_WINDOW (obj));
1548 /* Insert dimming rules group for this window */
1549 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1550 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1552 /* Setup app menu */
1553 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1555 /* Checks the dimming rules */
1556 g_object_unref (toolbar_rules_group);
1557 g_object_unref (clipboard_rules_group);
1558 gtk_widget_hide (priv->priority_icon);
1559 gtk_widget_queue_resize (priv->subject_box);
1560 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1562 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1564 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1565 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1566 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1567 priv->update_caption_visibility = TRUE;
1569 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1571 /* Track account-removed signal, this window should be closed
1572 in the case we're creating a mail associated to the account
1574 priv->account_removed_handler_id =
1575 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1577 G_CALLBACK(on_account_removed),
1580 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1582 return (ModestWindow*) obj;
1586 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1588 GString **string_buffer = (GString **) user_data;
1590 *string_buffer = g_string_append (*string_buffer, buffer);
1596 * @result: A new string which should be freed with g_free().
1599 get_formatted_data (ModestMsgEditWindow *edit_window)
1601 ModestMsgEditWindowPrivate *priv;
1602 GString *string_buffer = g_string_new ("");
1604 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1606 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1608 modest_text_utils_hyperlinkify (string_buffer);
1610 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1612 return g_string_free (string_buffer, FALSE);
1617 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1620 const gchar *account_name;
1621 ModestMsgEditWindowPrivate *priv;
1622 TnyIterator *att_iter;
1624 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1626 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1628 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1629 g_return_val_if_fail (account_name, NULL);
1632 /* don't free these (except from) */
1633 data = g_slice_new0 (MsgData);
1634 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1636 data->account_name = g_strdup (account_name);
1637 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1638 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1639 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1640 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1641 data->references = g_strdup (priv->references);
1642 data->in_reply_to = g_strdup (priv->in_reply_to);
1643 if (priv->draft_msg) {
1644 data->draft_msg = g_object_ref (priv->draft_msg);
1645 } else if (priv->outbox_msg) {
1646 data->draft_msg = g_object_ref (priv->outbox_msg);
1648 data->draft_msg = NULL;
1651 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1653 gtk_text_buffer_get_bounds (buf, &b, &e);
1654 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1656 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1657 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1659 data->html_body = NULL;
1661 /* deep-copy the data */
1662 att_iter = tny_list_create_iterator (priv->attachments);
1663 data->attachments = NULL;
1664 while (!tny_iterator_is_done (att_iter)) {
1665 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1666 if (!(TNY_IS_MIME_PART(part))) {
1667 g_warning ("strange data in attachment list");
1668 g_object_unref (part);
1669 tny_iterator_next (att_iter);
1672 data->attachments = g_list_append (data->attachments,
1674 tny_iterator_next (att_iter);
1676 g_object_unref (att_iter);
1678 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1679 att_iter = tny_list_create_iterator (priv->images);
1680 data->images = NULL;
1681 while (!tny_iterator_is_done (att_iter)) {
1682 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1684 if (!(TNY_IS_MIME_PART(part))) {
1685 g_warning ("strange data in attachment list");
1686 g_object_unref (part);
1687 tny_iterator_next (att_iter);
1690 cid = tny_mime_part_get_content_id (part);
1692 gchar *image_tag_id;
1693 GtkTextTag *image_tag;
1695 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1696 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1697 g_free (image_tag_id);
1699 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1701 ((gtk_text_iter_has_tag (&iter, image_tag))||
1702 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1703 data->images = g_list_append (data->images,
1704 g_object_ref (part));
1706 g_object_unref (part);
1707 tny_iterator_next (att_iter);
1709 g_object_unref (att_iter);
1711 data->priority_flags = priv->priority_flags;
1718 unref_gobject (GObject *obj, gpointer data)
1720 if (!G_IS_OBJECT(obj))
1722 g_object_unref (obj);
1726 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1729 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1737 g_free (data->from);
1738 g_free (data->subject);
1739 g_free (data->plain_body);
1740 g_free (data->html_body);
1741 g_free (data->account_name);
1742 g_free (data->references);
1743 g_free (data->in_reply_to);
1745 if (data->draft_msg != NULL) {
1746 g_object_unref (data->draft_msg);
1747 data->draft_msg = NULL;
1750 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1751 g_list_free (data->attachments);
1752 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1753 g_list_free (data->images);
1755 g_slice_free (MsgData, data);
1759 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1761 guint64 *parts_size)
1763 ModestMsgEditWindowPrivate *priv;
1765 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1767 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1769 /* TODO: add images */
1770 *parts_size += priv->images_size;
1771 *parts_count += priv->images_count;
1776 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1779 ModestMsgEditWindowPrivate *priv = NULL;
1780 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1782 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1784 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1786 return MODEST_MSG_EDIT_FORMAT_HTML;
1788 return MODEST_MSG_EDIT_FORMAT_TEXT;
1792 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1793 ModestMsgEditFormat format)
1795 ModestMsgEditWindowPrivate *priv;
1797 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1801 case MODEST_MSG_EDIT_FORMAT_HTML:
1802 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1804 case MODEST_MSG_EDIT_FORMAT_TEXT:
1805 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1808 g_return_if_reached ();
1812 ModestMsgEditFormatState *
1813 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1815 ModestMsgEditFormatState *format_state = NULL;
1816 ModestMsgEditWindowPrivate *priv;
1817 WPTextBufferFormat *buffer_format;
1819 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1821 buffer_format = g_new0 (WPTextBufferFormat, 1);
1822 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1824 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1826 format_state = g_new0 (ModestMsgEditFormatState, 1);
1827 format_state->bold = buffer_format->bold&0x1;
1828 format_state->italics = buffer_format->italic&0x1;
1829 format_state->bullet = buffer_format->bullet&0x1;
1830 format_state->color = buffer_format->color;
1831 format_state->font_size = buffer_format->font_size;
1832 format_state->font_family = wp_get_font_name (buffer_format->font);
1833 format_state->justification = buffer_format->justification;
1834 g_free (buffer_format);
1836 return format_state;
1841 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1842 const ModestMsgEditFormatState *format_state)
1844 ModestMsgEditWindowPrivate *priv;
1845 WPTextBufferFormat *buffer_format;
1846 WPTextBufferFormat *current_format;
1848 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1849 g_return_if_fail (format_state != NULL);
1851 buffer_format = g_new0 (WPTextBufferFormat, 1);
1852 current_format = g_new0 (WPTextBufferFormat, 1);
1854 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1855 gtk_widget_grab_focus (priv->msg_body);
1856 buffer_format->bold = (format_state->bold != FALSE);
1857 buffer_format->italic = (format_state->italics != FALSE);
1858 buffer_format->color = format_state->color;
1859 buffer_format->font_size = format_state->font_size;
1860 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1861 buffer_format->justification = format_state->justification;
1862 buffer_format->bullet = format_state->bullet;
1864 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1866 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1867 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1868 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1869 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1870 buffer_format->cs.font = (buffer_format->font != current_format->font);
1871 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1872 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1874 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1875 if (buffer_format->cs.bold) {
1876 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1877 GINT_TO_POINTER (buffer_format->bold&0x1));
1879 if (buffer_format->cs.italic) {
1880 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1881 GINT_TO_POINTER (buffer_format->italic&0x1));
1883 if (buffer_format->cs.color) {
1884 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1885 GINT_TO_POINTER (&(buffer_format->color)));
1887 if (buffer_format->cs.font_size) {
1888 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1889 GINT_TO_POINTER (buffer_format->font_size));
1891 if (buffer_format->cs.justification) {
1892 switch (buffer_format->justification) {
1893 case GTK_JUSTIFY_LEFT:
1894 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1895 GINT_TO_POINTER(TRUE));
1897 case GTK_JUSTIFY_CENTER:
1898 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1899 GINT_TO_POINTER(TRUE));
1901 case GTK_JUSTIFY_RIGHT:
1902 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1903 GINT_TO_POINTER(TRUE));
1910 if (buffer_format->cs.font) {
1911 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1912 GINT_TO_POINTER (buffer_format->font));
1914 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1915 if (buffer_format->cs.bullet) {
1916 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1917 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1919 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1921 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1923 g_free (buffer_format);
1924 g_free (current_format);
1926 /* Check dimming rules */
1927 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1928 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1932 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1934 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1936 ModestWindowPrivate *parent_priv;
1937 ModestMsgEditWindowPrivate *priv;
1939 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1940 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1942 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1943 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1944 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1945 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1947 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1948 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1949 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1952 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1954 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1955 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1957 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1958 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1960 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1961 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1964 switch (buffer_format->justification)
1966 case GTK_JUSTIFY_LEFT:
1967 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1969 case GTK_JUSTIFY_CENTER:
1970 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1972 case GTK_JUSTIFY_RIGHT:
1973 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1980 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1982 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1983 G_CALLBACK (modest_msg_edit_window_color_button_change),
1985 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1986 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1987 G_CALLBACK (modest_msg_edit_window_color_button_change),
1990 if (priv->current_size_index != buffer_format->font_size) {
1994 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1995 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1999 priv->current_size_index = buffer_format->font_size;
2001 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2002 markup = g_strconcat ("<span font_family='Sans'>",
2003 size_text, "</span>", NULL);
2005 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2009 gtk_tree_path_free (path);
2012 if (priv->current_face_index != buffer_format->font) {
2016 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2017 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2021 priv->current_face_index = buffer_format->font;
2022 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2023 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2024 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2031 g_free (buffer_format);
2035 #ifdef MODEST_HILDON_VERSION_0
2037 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2040 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2041 ModestMsgEditWindowPrivate *priv;
2042 GtkWidget *dialog = NULL;
2044 GdkColor *new_color = NULL;
2046 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2047 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2049 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2050 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2051 g_free (buffer_format);
2053 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2054 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2055 if (new_color != NULL) {
2056 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2057 (gpointer) new_color);
2060 gtk_widget_destroy (dialog);
2065 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2068 ModestMsgEditWindowPrivate *priv;
2069 GtkWidget *dialog = NULL;
2071 GdkColor *old_color = NULL;
2072 const GdkColor *new_color = NULL;
2074 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2075 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2077 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2078 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2080 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2081 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2082 if (new_color != NULL)
2083 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2085 gtk_widget_destroy (dialog);
2091 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2094 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2095 ModestMsgEditWindowPrivate *priv;
2096 GtkWidget *dialog = NULL;
2098 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2099 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2101 dialog = hildon_color_chooser_new ();
2102 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2103 g_free (buffer_format);
2105 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2107 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2108 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2111 gtk_widget_destroy (dialog);
2116 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2119 ModestMsgEditWindowPrivate *priv;
2120 GtkWidget *dialog = NULL;
2121 GdkColor *old_color = NULL;
2123 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2124 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2126 dialog = hildon_color_chooser_new ();
2127 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2129 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2131 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2132 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2134 gtk_widget_destroy (dialog);
2137 #endif /*!MODEST_HILDON_VERSION_0*/
2142 create_stream_for_uri (const gchar* uri)
2147 TnyStream *result = NULL;
2149 GnomeVFSHandle *handle = NULL;
2150 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2151 if (test == GNOME_VFS_OK) {
2152 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2153 /* Streams over OBEX (Bluetooth) are not seekable but
2154 * we expect them to be (we might need to read them
2155 * several times). So if this is a Bluetooth URI just
2156 * read the whole file into memory (this is not a fast
2157 * protocol so we can assume that these files are not
2158 * going to be very big) */
2159 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2160 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2161 TnyStream *memstream = tny_camel_mem_stream_new ();
2162 tny_stream_write_to_stream (vfssstream, memstream);
2163 g_object_unref (vfssstream);
2166 result = vfssstream;
2174 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2177 ModestMsgEditWindowPrivate *priv;
2178 GtkWidget *dialog = NULL;
2180 GSList *uris = NULL;
2181 GSList *uri_node = NULL;
2183 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2185 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2186 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2187 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2189 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2191 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2192 GTK_WINDOW (dialog), GTK_WINDOW (window));
2194 response = gtk_dialog_run (GTK_DIALOG (dialog));
2196 case GTK_RESPONSE_OK:
2197 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2202 gtk_widget_destroy (dialog);
2204 g_object_ref (window);
2205 /* The operation could take some time so allow the dialog to be closed */
2206 while (gtk_events_pending ())
2207 gtk_main_iteration ();
2209 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2211 GnomeVFSHandle *handle = NULL;
2212 GnomeVFSResult result;
2213 GtkTextIter position;
2214 GtkTextMark *insert_mark;
2216 uri = (const gchar *) uri_node->data;
2217 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2218 if (result == GNOME_VFS_OK) {
2220 GnomeVFSFileInfo *info;
2221 gchar *filename, *basename, *escaped_filename;
2222 TnyMimePart *mime_part;
2224 const gchar *mime_type = NULL;
2225 GnomeVFSURI *vfs_uri;
2226 guint64 stream_size;
2228 gnome_vfs_close (handle);
2229 vfs_uri = gnome_vfs_uri_new (uri);
2231 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2232 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2233 g_free (escaped_filename);
2234 gnome_vfs_uri_unref (vfs_uri);
2235 info = gnome_vfs_file_info_new ();
2237 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2238 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2240 mime_type = gnome_vfs_file_info_get_mime_type (info);
2242 mime_part = tny_platform_factory_new_mime_part
2243 (modest_runtime_get_platform_factory ());
2245 TnyStream *stream = create_stream_for_uri (uri);
2247 if (stream == NULL) {
2249 modest_platform_information_banner (NULL, NULL,
2250 _FM("sfil_ib_opening_not_allowed"));
2252 g_object_unref (mime_part);
2253 gnome_vfs_file_info_unref (info);
2257 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2259 content_id = g_strdup_printf ("%d", priv->next_cid);
2260 tny_mime_part_set_content_id (mime_part, content_id);
2261 g_free (content_id);
2264 basename = g_path_get_basename (filename);
2265 tny_mime_part_set_filename (mime_part, basename);
2268 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2270 if (pixbuf != NULL) {
2271 priv->images_size += stream_size;
2272 priv->images_count ++;
2273 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2274 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2275 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2276 tny_mime_part_get_content_id (mime_part), pixbuf);
2277 g_object_unref (pixbuf);
2279 tny_list_prepend (priv->images, (GObject *) mime_part);
2280 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2282 modest_platform_information_banner (NULL, NULL,
2283 _("mail_ib_file_operation_failed"));
2287 g_object_unref (mime_part);
2288 gnome_vfs_file_info_unref (info);
2292 g_object_unref (window);
2296 on_attach_file_response (GtkDialog *dialog,
2300 GSList *uris = NULL;
2302 GnomeVFSFileSize total_size, allowed_size;
2303 ModestMsgEditWindow *window;
2304 ModestMsgEditWindowPrivate *priv;
2309 case GTK_RESPONSE_OK:
2310 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2316 window = MODEST_MSG_EDIT_WINDOW (user_data);
2317 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2319 /* allowed size is the maximum size - what's already there */
2320 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2321 &att_num, &att_size);
2322 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2325 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2327 const gchar *uri = (const gchar *) uri_node->data;
2330 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2332 if (total_size > allowed_size) {
2333 g_warning ("%s: total size: %u",
2334 __FUNCTION__, (unsigned int)total_size);
2337 allowed_size -= total_size;
2339 g_slist_foreach (uris, (GFunc) g_free, NULL);
2340 g_slist_free (uris);
2342 gtk_widget_destroy (GTK_WIDGET (dialog));
2346 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2348 GtkWidget *dialog = NULL;
2349 ModestMsgEditWindowPrivate *priv;
2351 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2353 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2355 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2358 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2359 GTK_FILE_CHOOSER_ACTION_OPEN);
2360 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2361 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2362 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2363 GTK_WINDOW (dialog), GTK_WINDOW (window));
2365 /* Connect to response & show */
2366 g_signal_connect (dialog, "response",
2367 G_CALLBACK (on_attach_file_response), window);
2368 gtk_widget_show (dialog);
2373 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2375 GnomeVFSFileSize allowed_size)
2378 GnomeVFSHandle *handle = NULL;
2379 ModestMsgEditWindowPrivate *priv;
2380 GnomeVFSResult result;
2381 GnomeVFSFileSize size = 0;
2382 g_return_val_if_fail (window, 0);
2383 g_return_val_if_fail (uri, 0);
2385 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2387 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2388 if (result == GNOME_VFS_OK) {
2389 TnyMimePart *mime_part;
2391 const gchar *mime_type = NULL;
2393 gchar *escaped_filename;
2396 GnomeVFSFileInfo *info;
2397 GnomeVFSURI *vfs_uri;
2399 gnome_vfs_close (handle);
2400 vfs_uri = gnome_vfs_uri_new (uri);
2403 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2404 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2405 g_free (escaped_filename);
2406 gnome_vfs_uri_unref (vfs_uri);
2408 info = gnome_vfs_file_info_new ();
2410 if (gnome_vfs_get_file_info (uri,
2412 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2414 mime_type = gnome_vfs_file_info_get_mime_type (info);
2415 mime_part = tny_platform_factory_new_mime_part
2416 (modest_runtime_get_platform_factory ());
2418 /* try to get the attachment's size; this may fail for weird
2419 * file systems, like obex, upnp... */
2420 if (allowed_size != 0 &&
2421 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2423 if (size > allowed_size) {
2424 modest_platform_information_banner (NULL, NULL,
2425 _FM("sfil_ib_opening_not_allowed"));
2430 g_warning ("%s: could not get attachment size", __FUNCTION__);
2432 stream = create_stream_for_uri (uri);
2434 if (stream == NULL) {
2436 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2438 g_object_unref (mime_part);
2440 gnome_vfs_file_info_unref (info);
2444 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2445 g_object_unref (stream);
2447 content_id = g_strdup_printf ("%d", priv->next_cid);
2448 tny_mime_part_set_content_id (mime_part, content_id);
2449 g_free (content_id);
2452 basename = g_path_get_basename (filename);
2453 tny_mime_part_set_filename (mime_part, basename);
2456 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2457 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2459 info->size == 0, info->size);
2460 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2461 gtk_widget_show_all (priv->attachments_caption);
2462 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2464 g_object_unref (mime_part);
2465 gnome_vfs_file_info_unref (info);
2472 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2475 ModestMsgEditWindowPrivate *priv;
2478 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2479 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2481 if (att_list == NULL) {
2482 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2483 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2484 g_object_unref (att_list);
2489 g_object_ref (att_list);
2492 if (tny_list_get_length (att_list) == 0) {
2493 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2495 gboolean dialog_response;
2496 gchar *message = NULL;
2497 gchar *filename = NULL;
2499 if (tny_list_get_length (att_list) == 1) {
2501 iter = tny_list_create_iterator (att_list);
2502 part = (TnyMimePart *) tny_iterator_get_current (iter);
2503 g_object_unref (iter);
2504 if (TNY_IS_MSG (part)) {
2505 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2507 filename = tny_header_dup_subject (header);
2508 g_object_unref (header);
2510 if (filename == NULL) {
2511 filename = g_strdup (_("mail_va_no_subject"));
2514 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2516 g_object_unref (part);
2518 filename = g_strdup ("");
2520 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2521 "emev_nc_delete_attachments",
2522 tny_list_get_length (att_list)), filename);
2525 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2529 if (dialog_response != GTK_RESPONSE_OK) {
2530 g_object_unref (att_list);
2534 for (iter = tny_list_create_iterator (att_list);
2535 !tny_iterator_is_done (iter);
2536 tny_iterator_next (iter)) {
2537 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2538 const gchar *att_id;
2539 tny_list_remove (priv->attachments, (GObject *) mime_part);
2541 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2543 if (tny_list_get_length (priv->attachments) == 0)
2544 gtk_widget_hide (priv->attachments_caption);
2545 att_id = tny_mime_part_get_content_id (mime_part);
2547 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2549 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2550 g_object_unref (mime_part);
2552 g_object_unref (iter);
2555 g_object_unref (att_list);
2557 /* if the last attachment has been removed, focus the Subject: field */
2558 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2559 gtk_widget_grab_focus (priv->subject_field);
2563 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2566 ModestMsgEditWindowPrivate *priv;
2567 GdkColor *new_color;
2568 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2570 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2571 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2574 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2576 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2578 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2580 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2585 font_size_clicked (GtkToolButton *button,
2586 ModestMsgEditWindow *window)
2588 ModestMsgEditWindowPrivate *priv;
2589 GtkWidget *selector, *dialog;
2591 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2593 selector = hildon_touch_selector_new ();
2594 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2595 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2597 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2598 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2599 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2601 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2605 WPTextBufferFormat format;
2607 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2609 memset (&format, 0, sizeof (format));
2610 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2612 format.cs.font_size = TRUE;
2613 format.cs.text_position = TRUE;
2614 format.cs.font = TRUE;
2615 format.font_size = new_index;
2616 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2618 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2619 GINT_TO_POINTER (new_index)))
2620 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2622 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2623 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2624 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2625 size_text, "</span>", NULL);
2627 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2631 gtk_widget_destroy (dialog);
2633 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2638 font_face_clicked (GtkToolButton *button,
2639 ModestMsgEditWindow *window)
2641 ModestMsgEditWindowPrivate *priv;
2642 GtkWidget *selector, *dialog;
2643 GtkCellRenderer *renderer;
2645 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2647 selector = hildon_touch_selector_new ();
2648 renderer = gtk_cell_renderer_text_new ();
2649 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2650 renderer, "family", 0, "text", 0, NULL);
2651 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2653 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2654 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2655 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2657 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2658 gint new_font_index;
2662 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2663 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2664 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2668 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2670 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2671 GINT_TO_POINTER(new_font_index)))
2672 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2674 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2675 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2677 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2681 gtk_tree_path_free (path);
2684 gtk_widget_destroy (dialog);
2686 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2691 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2694 ModestMsgEditWindowPrivate *priv = NULL;
2695 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2697 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2698 if (!priv->update_caption_visibility)
2701 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2703 gtk_widget_show (priv->cc_caption);
2705 gtk_widget_hide (priv->cc_caption);
2707 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2711 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2714 ModestMsgEditWindowPrivate *priv = NULL;
2715 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2717 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2718 if (!priv->update_caption_visibility)
2721 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2723 gtk_widget_show (priv->bcc_caption);
2725 gtk_widget_hide (priv->bcc_caption);
2727 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2731 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2732 ModestRecptEditor *editor)
2734 ModestMsgEditWindowPrivate *priv;
2736 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2737 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2739 /* we check for low-mem; in that case, show a warning, and don't allow
2740 * for the addressbook
2742 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2745 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2747 if (editor == NULL) {
2748 GtkWidget *view_focus;
2749 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2751 /* This code should be kept in sync with ModestRecptEditor. The
2752 textview inside the recpt editor is the one that really gets the
2753 focus. As it's inside a scrolled window, and this one inside the
2754 hbox recpt editor inherits from, we'll need to go up in the
2755 hierarchy to know if the text view is part of the recpt editor
2756 or if it's a different text entry */
2758 if (gtk_widget_get_parent (view_focus)) {
2759 GtkWidget *first_parent;
2761 first_parent = gtk_widget_get_parent (view_focus);
2762 if (gtk_widget_get_parent (first_parent) &&
2763 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2764 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2769 editor = MODEST_RECPT_EDITOR (priv->to_field);
2773 modest_address_book_select_addresses (editor);
2778 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2780 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2782 modest_msg_edit_window_open_addressbook (window, NULL);
2786 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2787 gboolean show_toolbar)
2789 ModestWindowPrivate *parent_priv;
2791 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2792 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2794 /* We can not just use the code of
2795 modest_msg_edit_window_setup_toolbar because it has a
2796 mixture of both initialization and creation code. */
2798 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2800 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2804 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2805 TnyHeaderFlags priority_flags)
2807 ModestMsgEditWindowPrivate *priv;
2808 ModestWindowPrivate *parent_priv;
2810 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2812 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2813 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2815 if (priv->priority_flags != priority_flags) {
2816 GtkAction *priority_action = NULL;
2818 priv->priority_flags = priority_flags;
2820 switch (priority_flags) {
2821 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2822 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2823 MODEST_HEADER_ICON_HIGH,
2824 HILDON_ICON_SIZE_SMALL);
2825 gtk_widget_show (priv->priority_icon);
2826 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2827 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2829 case TNY_HEADER_FLAG_LOW_PRIORITY:
2830 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2831 MODEST_HEADER_ICON_LOW,
2832 HILDON_ICON_SIZE_SMALL);
2833 gtk_widget_show (priv->priority_icon);
2834 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2835 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2838 gtk_widget_hide (priv->priority_icon);
2839 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2840 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2843 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2844 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2846 gtk_widget_queue_resize (priv->subject_box);
2850 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2853 ModestMsgEditWindowPrivate *priv;
2854 ModestWindowPrivate *parent_priv;
2855 gint current_format;
2857 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2859 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2860 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2862 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2863 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2865 if (current_format != file_format) {
2866 switch (file_format) {
2867 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2868 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2869 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2871 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2875 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2876 response = gtk_dialog_run (GTK_DIALOG (dialog));
2877 gtk_widget_destroy (dialog);
2878 if (response == GTK_RESPONSE_OK) {
2879 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2881 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2882 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2887 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2888 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2889 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2894 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2897 ModestMsgEditWindowPrivate *priv;
2898 WPTextBufferFormat oldfmt, fmt;
2899 gint old_position = 0;
2903 GdkColor *color = NULL;
2904 gboolean bold, bold_set, italic, italic_set;
2905 gboolean underline, underline_set;
2906 gboolean strikethrough, strikethrough_set;
2907 gboolean position_set;
2908 gboolean font_size_set, font_set, color_set;
2911 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2912 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2914 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2915 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2916 GTK_WINDOW(dialog), GTK_WINDOW (window));
2918 /* First we get the currently selected font information */
2919 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2921 switch (oldfmt.text_position) {
2922 case TEXT_POSITION_NORMAL:
2925 case TEXT_POSITION_SUPERSCRIPT:
2933 g_object_set (G_OBJECT (dialog),
2934 "bold", oldfmt.bold != FALSE,
2935 "bold-set", !oldfmt.cs.bold,
2936 "underline", oldfmt.underline != FALSE,
2937 "underline-set", !oldfmt.cs.underline,
2938 "italic", oldfmt.italic != FALSE,
2939 "italic-set", !oldfmt.cs.italic,
2940 "strikethrough", oldfmt.strikethrough != FALSE,
2941 "strikethrough-set", !oldfmt.cs.strikethrough,
2942 "color", &oldfmt.color,
2943 "color-set", !oldfmt.cs.color,
2944 "size", wp_font_size[oldfmt.font_size],
2945 "size-set", !oldfmt.cs.font_size,
2946 "position", old_position,
2947 "position-set", !oldfmt.cs.text_position,
2948 "family", wp_get_font_name (oldfmt.font),
2949 "family-set", !oldfmt.cs.font,
2952 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2953 GTK_WINDOW (dialog), GTK_WINDOW (window));
2954 gtk_widget_show_all (dialog);
2955 priv->font_dialog = dialog;
2956 response = gtk_dialog_run (GTK_DIALOG (dialog));
2957 priv->font_dialog = NULL;
2958 if (response == GTK_RESPONSE_OK) {
2960 g_object_get( dialog,
2962 "bold-set", &bold_set,
2963 "underline", &underline,
2964 "underline-set", &underline_set,
2966 "italic-set", &italic_set,
2967 "strikethrough", &strikethrough,
2968 "strikethrough-set", &strikethrough_set,
2970 "color-set", &color_set,
2972 "size-set", &font_size_set,
2973 "family", &font_name,
2974 "family-set", &font_set,
2975 "position", &position,
2976 "position-set", &position_set,
2981 if (response == GTK_RESPONSE_OK) {
2982 memset(&fmt, 0, sizeof(fmt));
2988 fmt.italic = italic;
2989 fmt.cs.italic = TRUE;
2991 if (underline_set) {
2992 fmt.underline = underline;
2993 fmt.cs.underline = TRUE;
2995 if (strikethrough_set) {
2996 fmt.strikethrough = strikethrough;
2997 fmt.cs.strikethrough = TRUE;
3002 ? TEXT_POSITION_NORMAL
3003 : ( ( position == 1 )
3004 ? TEXT_POSITION_SUPERSCRIPT
3005 : TEXT_POSITION_SUBSCRIPT );
3006 fmt.cs.text_position = TRUE;
3007 fmt.font_size = oldfmt.font_size;
3011 fmt.cs.color = TRUE;
3014 fmt.font = wp_get_font_index(font_name,
3019 if (font_size_set) {
3020 fmt.cs.font_size = TRUE;
3021 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3023 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3024 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3026 gtk_widget_destroy (dialog);
3028 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3032 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3034 ModestMsgEditWindowPrivate *priv;
3036 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3037 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3039 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3041 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3042 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3046 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3048 ModestMsgEditWindowPrivate *priv;
3050 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3051 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3053 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3055 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3056 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3061 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3063 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3065 priv->can_undo = can_undo;
3069 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3071 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3073 priv->can_redo = can_redo;
3077 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3079 ModestMsgEditWindowPrivate *priv;
3080 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3081 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3083 return priv->can_undo;
3087 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3089 ModestMsgEditWindowPrivate *priv;
3090 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3091 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3093 return priv->can_redo;
3098 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3101 GtkTextIter match_start, match_end;
3103 if (image_id == NULL)
3106 gtk_text_buffer_get_start_iter (buffer, &iter);
3108 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3109 GSList *tags = gtk_text_iter_get_tags (&match_start);
3111 for (node = tags; node != NULL; node = g_slist_next (node)) {
3112 GtkTextTag *tag = (GtkTextTag *) node->data;
3113 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3114 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3115 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3117 offset = gtk_text_iter_get_offset (&match_start);
3118 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3119 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3123 gtk_text_iter_forward_char (&iter);
3128 message_is_empty (ModestMsgEditWindow *window)
3130 ModestMsgEditWindowPrivate *priv = NULL;
3132 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3133 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3135 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3136 * so we can ignore markup.
3138 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3141 count = gtk_text_buffer_get_char_count (buf);
3147 msg_body_focus (GtkWidget *focus,
3148 GdkEventFocus *event,
3152 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3153 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3154 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3159 recpt_field_changed (GtkTextBuffer *buffer,
3160 ModestMsgEditWindow *editor)
3162 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3163 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3167 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3169 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3170 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3174 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3177 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3178 GtkTextBuffer *buffer;
3180 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3181 gtk_text_buffer_set_modified (buffer, modified);
3182 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3183 gtk_text_buffer_set_modified (buffer, modified);
3184 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3185 gtk_text_buffer_set_modified (buffer, modified);
3186 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3190 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3192 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3193 const char *account_name;
3194 GtkTextBuffer *buffer;
3196 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3197 if (gtk_text_buffer_get_modified (buffer))
3199 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3200 if (gtk_text_buffer_get_modified (buffer))
3202 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3203 if (gtk_text_buffer_get_modified (buffer))
3205 if (gtk_text_buffer_get_modified (priv->text_buffer))
3207 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3208 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3219 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3221 ModestMsgEditWindowPrivate *priv = NULL;
3223 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3224 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3226 /* check if there's no recipient added */
3227 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3228 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3229 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3230 /* no recipient contents, then select contacts */
3231 modest_msg_edit_window_open_addressbook (window, NULL);
3235 g_object_ref (window);
3236 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3237 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3238 g_object_unref (window);
3241 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3242 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3243 g_object_unref (window);
3246 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3247 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3248 g_object_unref (window);
3252 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3253 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3254 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3255 g_object_unref (window);
3262 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3263 ModestMsgEditWindow *window)
3265 modest_msg_edit_window_offer_attach_file (window);
3269 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3271 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3273 return priv->clipboard_text;
3277 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3279 ModestMsgEditWindow *window)
3281 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3282 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3285 /* It could happen that the window was already closed */
3286 if (!GTK_WIDGET_VISIBLE (window))
3289 g_object_ref (window);
3290 text = gtk_clipboard_wait_for_text (selection_clipboard);
3292 if (priv->clipboard_text != NULL) {
3293 g_free (priv->clipboard_text);
3295 priv->clipboard_text = text;
3297 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3299 g_object_unref (window);
3302 static gboolean clipboard_owner_change_idle (gpointer userdata)
3304 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3305 ModestMsgEditWindowPrivate *priv;
3307 gdk_threads_enter ();
3308 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3309 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3311 priv->clipboard_owner_idle = 0;
3312 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3313 gdk_threads_leave ();
3319 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3321 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3322 if (priv->clipboard_owner_idle == 0) {
3323 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3324 clipboard_owner_change_idle,
3325 g_object_ref (window),
3331 subject_field_move_cursor (GtkEntry *entry,
3332 GtkMovementStep step,
3337 /* It could happen that the window was already closed */
3338 if (!GTK_WIDGET_VISIBLE (window))
3341 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3345 update_window_title (ModestMsgEditWindow *window)
3347 ModestMsgEditWindowPrivate *priv = NULL;
3348 const gchar *subject;
3350 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3351 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3352 if (subject == NULL || subject[0] == '\0')
3353 subject = _("mail_va_new_email");
3355 gtk_window_set_title (GTK_WINDOW (window), subject);
3360 subject_field_changed (GtkEditable *editable,
3361 ModestMsgEditWindow *window)
3363 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3364 update_window_title (window);
3365 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3366 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3367 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3371 subject_field_insert_text (GtkEditable *editable,
3373 gint new_text_length,
3375 ModestMsgEditWindow *window)
3377 GString *result = g_string_new ("");
3379 gint result_len = 0;
3380 const gchar *entry_text = NULL;
3383 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3384 old_length = g_utf8_strlen (entry_text, -1);
3386 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3387 gunichar c = g_utf8_get_char_validated (current, 8);
3388 /* Invalid unichar, stop */
3394 result = g_string_append_unichar (result, c);
3398 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3399 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3402 /* Prevent endless recursion */
3403 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3404 g_signal_emit_by_name (editable, "insert-text",
3405 (gpointer) result->str, (gpointer) result->len,
3406 (gpointer) position, (gpointer) window);
3407 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3411 if (result_len + old_length > 1000) {
3412 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3413 _CS("ckdg_ib_maximum_characters_reached"));
3415 g_string_free (result, TRUE);
3419 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3422 ModestMsgEditWindowPrivate *priv = NULL;
3424 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3425 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3427 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3430 gtk_widget_show_all (priv->find_toolbar);
3431 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3433 gtk_widget_hide_all (priv->find_toolbar);
3434 gtk_widget_grab_focus (priv->msg_body);
3439 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3441 GtkTextIter *match_start,
3442 GtkTextIter *match_end)
3444 GtkTextIter end_iter;
3445 gchar *str_casefold;
3448 gchar *range_casefold;
3451 gboolean result = FALSE;
3458 gtk_text_iter_forward_to_end (&end_iter);
3460 str_casefold = g_utf8_casefold (str, -1);
3461 str_chars_n = strlen (str);
3463 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3464 range_casefold = g_utf8_casefold (range_text, -1);
3465 range_chars_n = strlen (range_casefold);
3467 if (range_chars_n < str_chars_n) {
3468 g_free (str_casefold);
3469 g_free (range_text);
3470 g_free (range_casefold);
3474 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3475 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3476 if (!g_utf8_collate (range_subtext, str_casefold)) {
3477 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3479 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3480 match_start, match_end, NULL)) {
3481 g_warning ("Matched string with collate, but not matched in model");
3483 g_free (found_text);
3485 g_free (range_subtext);
3489 g_free (str_casefold);
3490 g_free (range_text);
3491 g_free (range_casefold);
3498 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3499 ModestMsgEditWindow *window)
3501 gchar *current_search = NULL;
3502 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3504 GtkTextIter selection_start, selection_end;
3505 GtkTextIter match_start, match_end;
3506 gboolean continue_search = FALSE;
3508 if (message_is_empty (window)) {
3509 g_free (priv->last_search);
3510 priv->last_search = NULL;
3511 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3515 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3516 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3517 g_free (current_search);
3518 g_free (priv->last_search);
3519 priv->last_search = NULL;
3520 /* Information banner about empty search */
3521 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3525 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3526 continue_search = TRUE;
3528 g_free (priv->last_search);
3529 priv->last_search = g_strdup (current_search);
3532 if (continue_search) {
3533 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3534 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3535 &match_start, &match_end);
3537 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3539 GtkTextIter buffer_start;
3540 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3541 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3542 &match_start, &match_end);
3544 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3547 /* Mark as selected the string found in search */
3549 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3550 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3551 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3553 g_free (priv->last_search);
3554 priv->last_search = NULL;
3556 g_free (current_search);
3560 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3562 ModestMsgEditWindowPrivate *priv;
3564 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3569 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3572 ModestMsgEditWindowPrivate *priv;
3574 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3579 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3580 ModestMsgEditWindow *window)
3582 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3586 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3589 ModestMsgEditWindowPrivate *priv;
3590 TnyHeader *header = NULL;
3592 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3593 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3595 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3597 if (priv->draft_msg != NULL) {
3598 g_object_unref (priv->draft_msg);
3601 if (draft != NULL) {
3602 g_object_ref (draft);
3603 header = tny_msg_get_header (draft);
3604 if (priv->msg_uid) {
3605 g_free (priv->msg_uid);
3606 priv->msg_uid = NULL;
3608 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3611 priv->draft_msg = draft;
3615 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3616 GtkTextIter *start, GtkTextIter *end,
3619 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3620 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3623 if (tag == NULL) return;
3624 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3625 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3626 replace_with_images (window, priv->images);
3631 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3634 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3636 g_return_if_fail (TNY_IS_MIME_PART (part));
3637 tny_list_prepend (priv->attachments, (GObject *) part);
3638 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3639 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3640 gtk_widget_show_all (priv->attachments_caption);
3641 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3645 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3647 ModestMsgEditWindowPrivate *priv;
3649 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3650 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3652 return priv->msg_uid;
3656 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3657 ModestMsgEditWindowWidgetType widget_type)
3659 ModestMsgEditWindowPrivate *priv;
3661 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3662 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3664 switch (widget_type) {
3665 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3666 return priv->msg_body;
3668 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3669 return priv->to_field;
3671 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3672 return priv->cc_field;
3674 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3675 return priv->bcc_field;
3677 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3678 return priv->subject_field;
3680 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3681 return priv->attachments_view;
3689 remove_tags (WPTextBuffer *buffer)
3691 GtkTextIter start, end;
3693 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3694 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3696 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3700 on_account_removed (TnyAccountStore *account_store,
3701 TnyAccount *account,
3704 /* Do nothing if it's a store account, because we use the
3705 transport to send the messages */
3706 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3707 const gchar *parent_acc = NULL;
3708 const gchar *our_acc = NULL;
3710 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3711 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3712 /* Close this window if I'm showing a message of the removed account */
3713 if (strcmp (parent_acc, our_acc) == 0)
3714 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3719 from_field_changed (HildonPickerButton *button,
3720 ModestMsgEditWindow *self)
3722 ModestMsgEditWindowPrivate *priv;
3723 gboolean has_old_signature, has_new_signature;
3725 GtkTextIter match_start, match_end;
3726 ModestAccountMgr *mgr;
3728 gchar *full_signature;
3730 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3732 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3733 mgr = modest_runtime_get_account_mgr ();
3734 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3735 if (has_old_signature) {
3736 full_signature = g_strconcat ("\n--\n", signature, NULL);
3737 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3738 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3740 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3741 &match_start, &match_end, NULL)) {
3744 g_free (full_signature);
3748 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3749 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3750 if (has_new_signature) {
3751 full_signature = g_strconcat ("\n--\n", signature, NULL);
3752 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3753 g_free (full_signature);
3758 typedef struct _MessageSettingsHelper {
3759 ModestMsgEditWindow *window;
3760 GSList *priority_group;
3761 GSList *format_group;
3762 GtkToggleButton *current_priority;
3763 GtkToggleButton *current_format;
3764 } MessageSettingsHelper;
3767 on_priority_toggle (GtkToggleButton *button,
3768 MessageSettingsHelper *helper)
3771 ModestMsgEditWindowPrivate *priv;
3773 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3774 if (gtk_toggle_button_get_active (button)) {
3776 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3777 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3778 if ((node_button != button) &&
3779 gtk_toggle_button_get_active (node_button)) {
3780 gtk_toggle_button_set_active (node_button, FALSE);
3783 helper->current_priority = button;
3785 gboolean found = FALSE;
3786 /* If no one is active, activate it again */
3787 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3788 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3789 if (gtk_toggle_button_get_active (node_button)) {
3795 gtk_toggle_button_set_active (button, TRUE);
3801 on_format_toggle (GtkToggleButton *button,
3802 MessageSettingsHelper *helper)
3805 ModestMsgEditWindowPrivate *priv;
3807 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3808 if (gtk_toggle_button_get_active (button)) {
3810 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3811 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3812 if ((node_button != button) &&
3813 gtk_toggle_button_get_active (node_button)) {
3814 gtk_toggle_button_set_active (node_button, FALSE);
3817 helper->current_format = button;
3819 gboolean found = FALSE;
3820 /* If no one is active, activate it again */
3821 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3822 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3823 if (gtk_toggle_button_get_active (node_button)) {
3829 gtk_toggle_button_set_active (button, TRUE);
3836 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3841 GtkWidget *priority_hbox;
3842 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3843 GtkWidget *captioned;
3844 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3845 GtkWidget *format_hbox;
3846 GtkWidget *html_toggle, *text_toggle;
3847 ModestMsgEditWindowPrivate *priv;
3848 MessageSettingsHelper helper = {0,};
3850 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3851 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3852 helper.window = window;
3853 helper.priority_group = NULL;
3854 helper.format_group = NULL;
3856 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3857 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3859 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3860 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3861 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3862 vbox = gtk_vbox_new (FALSE, 0);
3863 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3864 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3865 gtk_container_add (GTK_CONTAINER (align), vbox);
3866 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3867 gtk_widget_show (align);
3868 gtk_widget_show (vbox);
3870 /* Priority toggles */
3871 priority_hbox = gtk_hbox_new (TRUE, 0);
3872 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3873 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3874 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3875 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3876 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3877 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3878 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3879 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3880 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3881 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3882 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3883 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3884 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3885 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3886 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3887 gtk_widget_show_all (priority_hbox);
3888 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3889 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3890 gtk_widget_show (captioned);
3891 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3893 /* format toggles */
3894 format_hbox = gtk_hbox_new (TRUE, 0);
3895 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3896 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3897 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3898 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3899 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3900 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3901 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3902 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3903 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3904 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3905 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3906 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3907 gtk_widget_show_all (format_hbox);
3908 gtk_widget_show (format_hbox);
3909 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3912 g_object_unref (title_sizegroup);
3913 g_object_unref (value_sizegroup);
3915 /* Set current values */
3916 switch (priv->priority_flags) {
3917 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3918 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3919 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3921 case TNY_HEADER_FLAG_LOW_PRIORITY:
3922 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3923 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3926 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3927 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3931 switch (modest_msg_edit_window_get_format (window)) {
3932 case MODEST_MSG_EDIT_FORMAT_TEXT:
3933 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3934 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3936 case MODEST_MSG_EDIT_FORMAT_HTML:
3938 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3939 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3943 /* Signal connects */
3944 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3945 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3946 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3947 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3948 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3950 /* Save settings if the user clicked on done */
3951 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3952 TnyHeaderFlags flags;
3953 ModestMsgEditFormat old_format, new_format;
3955 /* Set priority flags */
3956 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3957 if (priv->priority_flags != flags)
3958 modest_msg_edit_window_set_priority_flags (window, flags);
3960 /* Set edit format */
3961 old_format = modest_msg_edit_window_get_format (window);
3962 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3963 if (old_format != new_format) {
3964 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3965 modest_msg_edit_window_set_file_format (window, file_format);
3969 gtk_widget_destroy (dialog);
3970 g_slist_free (helper.priority_group);
3974 on_message_settings (GtkAction *action,
3975 ModestMsgEditWindow *window)
3977 modest_msg_edit_window_show_msg_settings_dialog (window);
3981 on_cc_button_toggled (HildonCheckButton *button,
3982 ModestMsgEditWindow *window)
3984 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3986 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3987 hildon_check_button_get_active (button));
3991 on_bcc_button_toggled (HildonCheckButton *button,
3992 ModestMsgEditWindow *window)
3994 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3996 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3997 hildon_check_button_get_active (button));
4001 setup_menu (ModestMsgEditWindow *self)
4003 ModestMsgEditWindowPrivate *priv = NULL;
4005 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4007 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4009 /* Settings menu buttons */
4010 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4011 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4013 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4014 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4015 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4017 priv->cc_button = hildon_check_button_new (0);
4018 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4019 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4021 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4023 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4024 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4025 priv->bcc_button = hildon_check_button_new (0);
4026 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4027 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4029 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4031 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4032 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4034 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4035 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4036 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4037 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4038 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4039 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4040 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4041 APP_MENU_CALLBACK (on_message_settings),
4043 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4044 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),