1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38 #include <tny-camel-mem-stream.h>
42 #include <modest-account-mgr.h>
43 #include <modest-account-mgr-helpers.h>
45 #include <widgets/modest-msg-edit-window.h>
46 #include <modest-selector-picker.h>
47 #include <widgets/modest-recpt-editor.h>
48 #include <widgets/modest-attachments-view.h>
50 #include <modest-runtime.h>
52 #include "modest-platform.h"
53 #include "modest-icon-names.h"
54 #include "modest-widget-memory.h"
55 #include "modest-window-priv.h"
56 #include "modest-mail-operation.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-tny-folder.h"
60 #include "modest-tny-account.h"
61 #include "modest-address-book.h"
62 #include "modest-text-utils.h"
63 #include <tny-simple-list.h>
64 #include <modest-wp-text-view.h>
65 #include <wptextbuffer.h>
66 #include <hildon/hildon-pannable-area.h>
67 #include <hildon/hildon-touch-selector.h>
68 #include <hildon/hildon-picker-dialog.h>
69 #include "modest-msg-edit-window-ui-dimming.h"
71 #include "modest-hildon-includes.h"
72 #ifdef MODEST_HAVE_HILDON0_WIDGETS
73 #include <hildon-widgets/hildon-color-chooser.h>
75 #include "widgets/modest-msg-edit-window-ui.h"
76 #ifdef MODEST_HAVE_HILDON0_WIDGETS
77 #include <libgnomevfs/gnome-vfs-mime-utils.h>
79 #include <libgnomevfs/gnome-vfs-mime.h>
81 #include <modest-utils.h>
82 #include "modest-maemo-utils.h"
83 #include <modest-ui-constants.h>
86 #define DEFAULT_FONT_SIZE 3
87 #define DEFAULT_FONT 2
88 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
89 #define DEFAULT_MAIN_VBOX_SPACING 6
90 #define SUBJECT_MAX_LENGTH 1000
91 #define IMAGE_MAX_WIDTH 560
92 #define DEFAULT_FONT_SCALE 1.5
93 #define ATTACHMENT_BUTTON_WIDTH 118
95 static gboolean is_wp_text_buffer_started = FALSE;
97 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
98 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
99 static void modest_msg_edit_window_finalize (GObject *obj);
101 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
102 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
103 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
105 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
106 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
107 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
108 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
109 GtkTextIter *start, GtkTextIter *end,
111 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
112 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
113 static void subject_field_insert_text (GtkEditable *editable,
115 gint new_text_length,
117 ModestMsgEditWindow *window);
118 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
122 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
123 ModestRecptEditor *editor);
124 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
125 ModestMsgEditWindow *window);
127 /* ModestWindow methods implementation */
128 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
129 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
130 gboolean show_toolbar);
131 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
133 ModestMsgEditWindow *window);
134 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
135 static void subject_field_move_cursor (GtkEntry *entry,
136 GtkMovementStep step,
140 static void update_window_title (ModestMsgEditWindow *window);
143 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
144 ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
149 GtkTextIter *match_start,
150 GtkTextIter *match_end);
152 static void remove_tags (WPTextBuffer *buffer);
154 static void on_account_removed (TnyAccountStore *account_store,
158 static void init_window (ModestMsgEditWindow *obj);
160 gboolean scroll_drag_timeout (gpointer userdata);
161 static void correct_scroll (ModestMsgEditWindow *w);
162 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
163 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
164 ModestMsgEditWindow *userdata);
165 static void text_buffer_mark_set (GtkTextBuffer *buffer,
168 ModestMsgEditWindow *userdata);
169 static void on_message_settings (GtkAction *action,
170 ModestMsgEditWindow *window);
171 static void setup_menu (ModestMsgEditWindow *self);
173 static void from_field_changed (HildonPickerButton *button,
174 ModestMsgEditWindow *self);
175 static void font_size_clicked (GtkToolButton *button,
176 ModestMsgEditWindow *window);
177 static void font_face_clicked (GtkToolButton *button,
178 ModestMsgEditWindow *window);
179 static void DEBUG_BUFFER (WPTextBuffer *buffer)
183 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
185 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
186 while (!gtk_text_iter_is_end (&iter)) {
187 GString *output = g_string_new ("");
188 GSList *toggled_tags;
191 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
192 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
193 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
194 GtkTextTag *tag = (GtkTextTag *) node->data;
196 g_object_get (G_OBJECT (tag), "name", &name, NULL);
197 output = g_string_append (output, name);
198 g_string_append (output, " ");
200 output = g_string_append (output, "] OPENED [ ");
201 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
202 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
203 GtkTextTag *tag = (GtkTextTag *) node->data;
205 g_object_get (G_OBJECT (tag), "name", &name, NULL);
206 output = g_string_append (output, name);
207 g_string_append (output, " ");
209 output = g_string_append (output, "]\n");
210 g_message ("%s", output->str);
211 g_string_free (output, TRUE);
212 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
214 g_message ("END BUFFER");
218 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
219 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
223 /* static gboolean */
224 /* on_key_pressed (GtkWidget *self, */
225 /* GdkEventKey *event, */
226 /* gpointer user_data); */
228 /* list my signals */
235 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
236 struct _ModestMsgEditWindowPrivate {
238 GtkWidget *header_box;
240 ModestPairList *from_field_protos;
241 GtkWidget *from_field;
242 gchar *last_from_account;
243 gchar *original_account_name;
247 GtkWidget *bcc_field;
248 GtkWidget *subject_field;
249 GtkWidget *attachments_view;
250 GtkWidget *priority_icon;
251 GtkWidget *subject_box;
252 GtkWidget *add_attachment_button;
254 GtkWidget *cc_caption;
255 GtkWidget *bcc_caption;
256 gboolean update_caption_visibility;
257 GtkWidget *attachments_caption;
259 GtkTextBuffer *text_buffer;
261 GtkWidget *font_size_toolitem;
262 GtkWidget *font_face_toolitem;
263 GtkWidget *font_color_button;
264 GtkWidget *font_color_toolitem;
265 GSList *font_items_group;
266 GtkTreeModel *faces_model;
267 gint current_face_index;
268 GtkWidget *font_tool_button_label;
269 GtkTreeModel *sizes_model;
270 gint current_size_index;
271 GtkWidget *size_tool_button_label;
273 GtkWidget *find_toolbar;
276 GtkWidget *font_dialog;
279 guint correct_scroll_idle;
280 guint scroll_drag_timeout_id;
284 TnyList *attachments;
289 TnyHeaderFlags priority_flags;
291 gboolean can_undo, can_redo;
292 gulong clipboard_change_handler_id;
293 gulong default_clipboard_change_handler_id;
294 gulong account_removed_handler_id;
295 guint clipboard_owner_idle;
296 gchar *clipboard_text;
305 GtkWidget *cc_button;
306 GtkWidget *bcc_button;
309 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
310 MODEST_TYPE_MSG_EDIT_WINDOW, \
311 ModestMsgEditWindowPrivate))
313 static GtkWindowClass *parent_class = NULL;
315 /* uncomment the following if you have defined any signals */
316 /* static guint signals[LAST_SIGNAL] = {0}; */
319 modest_msg_edit_window_get_type (void)
321 static GType my_type = 0;
323 static const GTypeInfo my_info = {
324 sizeof(ModestMsgEditWindowClass),
325 NULL, /* base init */
326 NULL, /* base finalize */
327 (GClassInitFunc) modest_msg_edit_window_class_init,
328 NULL, /* class finalize */
329 NULL, /* class data */
330 sizeof(ModestMsgEditWindow),
332 (GInstanceInitFunc) modest_msg_edit_window_init,
335 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
336 "ModestMsgEditWindow",
344 save_state (ModestWindow *self)
346 modest_widget_memory_save (modest_runtime_get_conf(),
347 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
352 restore_settings (ModestMsgEditWindow *self)
354 ModestConf *conf = NULL;
356 conf = modest_runtime_get_conf ();
358 /* Dim at start clipboard actions */
359 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
364 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
366 GObjectClass *gobject_class;
367 ModestWindowClass *modest_window_class;
368 gobject_class = (GObjectClass*) klass;
369 modest_window_class = (ModestWindowClass*) klass;
371 parent_class = g_type_class_peek_parent (klass);
372 gobject_class->finalize = modest_msg_edit_window_finalize;
374 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
375 modest_window_class->save_state_func = save_state;
376 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
378 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
382 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
384 ModestMsgEditWindowPrivate *priv;
385 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
387 priv->msg_body = NULL;
388 priv->from_field = NULL;
389 priv->to_field = NULL;
390 priv->cc_field = NULL;
391 priv->bcc_field = NULL;
392 priv->subject_field = NULL;
393 priv->attachments = TNY_LIST (tny_simple_list_new ());
394 priv->images = TNY_LIST (tny_simple_list_new ());
395 priv->images_size = 0;
396 priv->images_count = 0;
399 priv->cc_caption = NULL;
400 priv->bcc_caption = NULL;
401 priv->update_caption_visibility = FALSE;
403 priv->priority_flags = 0;
405 priv->find_toolbar = NULL;
406 priv->last_search = NULL;
408 priv->draft_msg = NULL;
409 priv->outbox_msg = NULL;
410 priv->msg_uid = NULL;
412 priv->can_undo = FALSE;
413 priv->can_redo = FALSE;
414 priv->clipboard_change_handler_id = 0;
415 priv->default_clipboard_change_handler_id = 0;
416 priv->account_removed_handler_id = 0;
417 priv->clipboard_owner_idle = 0;
418 priv->clipboard_text = NULL;
421 priv->scroll_drag_timeout_id = 0;
422 priv->correct_scroll_idle = 0;
423 priv->last_upper = 0.0;
425 priv->font_dialog = NULL;
426 priv->app_menu = NULL;
428 if (!is_wp_text_buffer_started) {
429 is_wp_text_buffer_started = TRUE;
430 wp_text_buffer_library_init ();
435 hildon_program_add_window (hildon_program_get_instance(),
441 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
443 static ModestPairList*
444 get_transports (void)
446 GSList *transports = NULL;
448 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
449 GSList *accounts = modest_account_mgr_account_names (account_mgr,
450 TRUE /* only enabled accounts. */);
452 GSList *cursor = accounts;
454 gchar *account_name = cursor->data;
455 gchar *from_string = NULL;
457 from_string = modest_account_mgr_get_from_string (account_mgr,
461 if (from_string && account_name) {
462 gchar *name = account_name;
463 ModestPair *pair = modest_pair_new ((gpointer) name,
464 (gpointer) from_string , TRUE);
465 transports = g_slist_prepend (transports, pair);
468 cursor = cursor->next;
470 g_slist_free (accounts); /* only free the accounts, not the elements,
471 * because they are used in the pairlist */
475 static void window_focus (GtkWindow *window,
479 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
483 scroll_drag_timeout (gpointer userdata)
485 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
486 ModestMsgEditWindowPrivate *priv;
488 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
490 correct_scroll_without_drag_check (win, TRUE);
492 priv->scroll_drag_timeout_id = 0;
498 correct_scroll_without_drag_check_idle (gpointer userdata)
500 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
501 ModestMsgEditWindowPrivate *priv;
503 GdkRectangle rectangle;
504 gint offset_min, offset_max;
508 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
510 insert = gtk_text_buffer_get_insert (priv->text_buffer);
511 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
513 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
514 offset_min = priv->msg_body->allocation.y + rectangle.y;
515 offset_max = offset_min + rectangle.height;
517 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
518 offset_min = MAX (offset_min - 48, 0);
519 offset_max = MIN (offset_max + 48, vadj->upper);
521 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
523 priv->correct_scroll_idle = 0;
528 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
530 ModestMsgEditWindowPrivate *priv;
532 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
534 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
537 if (priv->correct_scroll_idle > 0) {
541 priv->correct_scroll_idle = g_idle_add ((GSourceFunc) correct_scroll_without_drag_check_idle,
546 correct_scroll (ModestMsgEditWindow *w)
548 ModestMsgEditWindowPrivate *priv;
550 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
551 if (gtk_grab_get_current () == priv->msg_body) {
552 if (priv->scroll_drag_timeout_id == 0) {
553 priv->scroll_drag_timeout_id = g_timeout_add (500, (GSourceFunc) scroll_drag_timeout,
559 correct_scroll_without_drag_check (w, TRUE);
563 text_buffer_end_user_action (GtkTextBuffer *buffer,
564 ModestMsgEditWindow *userdata)
567 correct_scroll (userdata);
571 text_buffer_mark_set (GtkTextBuffer *buffer,
574 ModestMsgEditWindow *userdata)
576 gtk_text_buffer_begin_user_action (buffer);
577 gtk_text_buffer_end_user_action (buffer);
581 cut_clipboard_check (GtkTextView *text_view,
584 GtkTextBuffer *buffer;
586 buffer = gtk_text_view_get_buffer (text_view);
587 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
588 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
593 copy_clipboard_check (GtkTextView *text_view,
596 GtkTextBuffer *buffer;
598 buffer = gtk_text_view_get_buffer (text_view);
599 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
600 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
605 attachment_deleted (ModestAttachmentsView *attachments_view,
608 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
613 connect_signals (ModestMsgEditWindow *obj)
615 ModestMsgEditWindowPrivate *priv;
617 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
619 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
620 G_CALLBACK (text_buffer_refresh_attributes), obj);
621 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
622 G_CALLBACK (text_buffer_can_undo), obj);
623 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
624 G_CALLBACK (text_buffer_can_redo), obj);
625 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
626 G_CALLBACK (body_changed), obj);
627 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
628 G_CALLBACK (body_changed), obj);
629 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
630 G_CALLBACK (text_buffer_end_user_action), obj);
631 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
632 G_CALLBACK (text_buffer_mark_set), obj);
633 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
634 G_CALLBACK (text_buffer_apply_tag), obj);
635 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
636 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
637 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
638 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
639 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
640 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
642 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
643 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
644 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
645 G_CALLBACK (from_field_changed), obj);
647 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
648 G_CALLBACK (msg_body_focus), obj);
649 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
650 G_CALLBACK (msg_body_focus), obj);
651 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
652 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
653 "changed", G_CALLBACK (recpt_field_changed), obj);
654 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
655 "changed", G_CALLBACK (recpt_field_changed), obj);
656 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
657 "changed", G_CALLBACK (recpt_field_changed), obj);
658 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
659 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
660 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
662 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
663 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
665 priv->clipboard_change_handler_id =
666 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
667 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
668 priv->default_clipboard_change_handler_id =
669 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
670 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
672 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
673 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
674 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
678 init_wp_text_view_style ()
680 static gboolean initialized = FALSE;
683 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
689 init_window (ModestMsgEditWindow *obj)
691 GtkWidget *to_caption, *subject_caption;
692 GtkWidget *main_vbox;
693 GtkWidget *add_attachment_align;
694 ModestMsgEditWindowPrivate *priv;
695 GtkActionGroup *action_group;
696 ModestWindowPrivate *parent_priv;
697 GdkPixbuf *window_icon = NULL;
698 GError *error = NULL;
700 GtkSizeGroup *title_size_group;
701 GtkSizeGroup *value_size_group;
702 GtkWidget *attachment_icon;
703 GtkWidget *window_box;
704 GtkWidget *window_align;
705 #if (GTK_MINOR_VERSION >= 10)
706 GdkAtom deserialize_type;
709 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
710 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
712 parent_priv->ui_manager = gtk_ui_manager_new();
713 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
714 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
716 /* Add common actions */
717 gtk_action_group_add_actions (action_group,
718 modest_msg_edit_action_entries,
719 G_N_ELEMENTS (modest_msg_edit_action_entries),
721 gtk_action_group_add_actions (action_group,
722 hildon2_msg_edit_action_entries,
723 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
725 gtk_action_group_add_toggle_actions (action_group,
726 modest_msg_edit_toggle_action_entries,
727 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
729 gtk_action_group_add_radio_actions (action_group,
730 modest_msg_edit_alignment_radio_action_entries,
731 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
733 G_CALLBACK (modest_ui_actions_on_change_justify),
735 gtk_action_group_add_radio_actions (action_group,
736 modest_msg_edit_priority_action_entries,
737 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
739 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
741 gtk_action_group_add_radio_actions (action_group,
742 modest_msg_edit_file_format_action_entries,
743 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
744 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
745 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
747 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
748 g_object_unref (action_group);
750 /* Load the UI definition */
751 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
754 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
755 g_clear_error (&error);
758 /* Add accelerators */
759 gtk_window_add_accel_group (GTK_WINDOW (obj),
760 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
762 parent_priv->menubar = NULL;
764 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
765 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
767 /* Note: This ModestPairList* must exist for as long as the picker
768 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
769 * so it can't know how to manage its memory. */
770 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
771 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
773 modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group,
774 _("mail_va_from"), priv->from_field);
776 priv->to_field = modest_recpt_editor_new ();
777 priv->cc_field = modest_recpt_editor_new ();
778 priv->bcc_field = modest_recpt_editor_new ();
779 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
780 priv->priority_icon = gtk_image_new ();
781 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
782 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
783 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
784 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
785 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
786 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
787 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
788 priv->add_attachment_button = hildon_button_new (MODEST_EDITABLE_SIZE, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
789 gtk_widget_set_size_request (priv->add_attachment_button, ATTACHMENT_BUTTON_WIDTH, -1);
790 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
791 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
792 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
793 hildon_button_set_image (HILDON_BUTTON (priv->add_attachment_button), attachment_icon);
794 add_attachment_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
795 gtk_alignment_set_padding (GTK_ALIGNMENT (add_attachment_align), 0, 0, MODEST_MARGIN_DEFAULT, 0);
796 gtk_container_add (GTK_CONTAINER (add_attachment_align), priv->add_attachment_button);
797 gtk_box_pack_start (GTK_BOX (priv->subject_box), add_attachment_align, FALSE, FALSE, 0);
798 priv->attachments_view = modest_attachments_view_new (NULL);
799 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
800 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
802 priv->header_box = gtk_vbox_new (FALSE, 0);
804 to_caption = modest_maemo_utils_create_captioned_with_size_type
805 (title_size_group, value_size_group,
806 _("mail_va_to"), FALSE, priv->to_field,
807 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
808 priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type
809 (title_size_group, value_size_group,
810 _("mail_va_cc"), FALSE, priv->cc_field,
811 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
812 priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
813 (title_size_group, value_size_group,
814 _("mail_va_hotfix1"), FALSE, priv->bcc_field,
815 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
816 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
817 _("mail_va_subject"), FALSE, priv->subject_box);
818 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
819 _("mail_va_attachment"),
821 priv->attachments_view,
822 HILDON_SIZE_AUTO_WIDTH |
823 HILDON_SIZE_AUTO_HEIGHT);
824 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
825 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
826 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
827 g_object_unref (title_size_group);
828 g_object_unref (value_size_group);
830 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
831 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
832 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
833 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
834 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
835 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
836 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
838 init_wp_text_view_style ();
840 priv->msg_body = modest_wp_text_view_new ();
843 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
844 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
845 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
846 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
847 #if (GTK_MINOR_VERSION >= 10)
848 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
849 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
851 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
852 deserialize_type, TRUE);
854 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
856 priv->find_toolbar = hildon_find_toolbar_new (NULL);
857 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
859 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
861 priv->pannable = hildon_pannable_area_new ();
863 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
864 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
865 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
867 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
868 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
869 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
871 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
872 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox),
873 hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable)));
874 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
876 window_box = gtk_vbox_new (FALSE, 0);
877 gtk_container_add (GTK_CONTAINER(obj), window_box);
879 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
881 /* Set window icon */
882 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
884 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
885 g_object_unref (window_icon);
890 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
892 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
894 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
895 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
896 priv->clipboard_change_handler_id))
897 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
898 priv->clipboard_change_handler_id);
899 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
900 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
901 priv->default_clipboard_change_handler_id))
902 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
903 priv->default_clipboard_change_handler_id);
905 if (priv->account_removed_handler_id &&
906 g_signal_handler_is_connected (modest_runtime_get_account_store (),
907 priv->account_removed_handler_id))
908 g_signal_handler_disconnect(modest_runtime_get_account_store (),
909 priv->account_removed_handler_id);
913 modest_msg_edit_window_finalize (GObject *obj)
915 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
917 /* Sanity check: shouldn't be needed, the window mgr should
918 call this function before */
919 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
921 if (priv->font_dialog != NULL) {
922 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
925 if (priv->clipboard_text != NULL) {
926 g_free (priv->clipboard_text);
927 priv->clipboard_text = NULL;
930 if (priv->draft_msg != NULL) {
931 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
932 if (TNY_IS_HEADER (header)) {
933 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
934 modest_window_mgr_unregister_header (mgr, header);
936 g_object_unref (priv->draft_msg);
937 priv->draft_msg = NULL;
939 if (priv->outbox_msg != NULL) {
940 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
941 if (TNY_IS_HEADER (header)) {
942 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
943 modest_window_mgr_unregister_header (mgr, header);
945 g_object_unref (priv->outbox_msg);
946 priv->outbox_msg = NULL;
948 if (priv->correct_scroll_idle > 0) {
949 g_source_remove (priv->correct_scroll_idle);
950 priv->correct_scroll_idle = 0;
952 if (priv->scroll_drag_timeout_id > 0) {
953 g_source_remove (priv->scroll_drag_timeout_id);
954 priv->scroll_drag_timeout_id = 0;
956 if (priv->clipboard_owner_idle > 0) {
957 g_source_remove (priv->clipboard_owner_idle);
958 priv->clipboard_owner_idle = 0;
960 if (priv->original_account_name)
961 g_free (priv->original_account_name);
962 g_free (priv->msg_uid);
963 g_free (priv->last_search);
964 g_object_unref (priv->faces_model);
965 g_object_unref (priv->sizes_model);
966 g_object_unref (priv->attachments);
967 g_object_unref (priv->images);
969 /* This had to stay alive for as long as the picker that used it: */
970 modest_pair_list_free (priv->from_field_protos);
972 G_OBJECT_CLASS(parent_class)->finalize (obj);
976 pixbuf_size_prepared (GdkPixbufLoader *loader,
979 ModestMsgEditWindow *self)
981 gint new_height, new_width;
988 if (width > IMAGE_MAX_WIDTH) {
989 new_height = height * IMAGE_MAX_WIDTH / width;
990 new_width = IMAGE_MAX_WIDTH;
993 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
997 pixbuf_from_stream (TnyStream *stream,
998 const gchar *mime_type,
999 guint64 *stream_size,
1000 ModestMsgEditWindow *self)
1002 GdkPixbufLoader *loader;
1005 GError *error = NULL;
1009 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1011 if (loader == NULL) {
1016 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1018 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1020 tny_stream_reset (TNY_STREAM (stream));
1021 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1022 unsigned char read_buffer[128];
1024 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1026 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1029 /* Allow some UI responsiveness */
1030 while (gtk_events_pending ())
1031 gtk_main_iteration ();
1033 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1035 gdk_pixbuf_loader_close (loader, &error);
1038 g_error_free (error);
1039 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1041 g_object_ref (pixbuf);
1042 g_object_unref (loader);
1047 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1048 GdkPixbuf *new_pixbuf;
1050 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1051 gdk_pixbuf_get_width (pixbuf);
1052 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1053 g_object_unref (pixbuf);
1054 pixbuf = new_pixbuf;
1058 *stream_size = size;
1064 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1066 ModestMsgEditWindowPrivate *priv;
1069 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1071 g_object_ref (self);
1072 for (iter = tny_list_create_iterator (attachments);
1073 !tny_iterator_is_done (iter);
1074 tny_iterator_next (iter)) {
1075 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1076 const gchar *cid = tny_mime_part_get_content_id (part);
1077 const gchar *mime_type = tny_mime_part_get_content_type (part);
1078 if ((cid != NULL)&&(mime_type != NULL)) {
1079 guint64 stream_size;
1080 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1081 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1084 g_object_unref (stream);
1086 if (pixbuf != NULL) {
1087 priv->images_count ++;
1088 priv->images_size += stream_size;
1089 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1090 g_object_unref (pixbuf);
1093 g_object_unref (part);
1095 g_object_unref (iter);
1096 g_object_unref (self);
1100 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1102 TnyMimePart *parent = NULL;
1103 const gchar *content_type = NULL;
1104 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1106 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1108 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1109 parent = g_object_ref (msg);
1110 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1111 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1114 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1115 iter = tny_list_create_iterator (parts);
1116 while (!tny_iterator_is_done (iter)) {
1118 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1119 content_type = tny_mime_part_get_content_type (part);
1120 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1124 g_object_unref (part);
1126 tny_iterator_next (iter);
1128 g_object_unref (iter);
1129 g_object_unref (parts);
1132 if (parent != NULL) {
1133 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1136 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1137 iter = tny_list_create_iterator (parts);
1138 while (!tny_iterator_is_done (iter)) {
1140 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1141 content_type = tny_mime_part_get_content_type (part);
1142 if (content_type && g_str_has_prefix (content_type, "image/")) {
1143 tny_list_prepend (priv->images, (GObject *) part);
1145 g_object_unref (part);
1146 tny_iterator_next (iter);
1148 g_object_unref (iter);
1149 g_object_unref (parts);
1150 g_object_unref (parent);
1155 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1158 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1160 for (iter = tny_list_create_iterator (attachments) ;
1161 !tny_iterator_is_done (iter);
1162 tny_iterator_next (iter)) {
1163 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1164 const gchar *cid = tny_mime_part_get_content_id (part);
1166 char *invalid = NULL;
1167 gint int_cid = strtol (cid, &invalid, 10);
1168 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1169 priv->next_cid = int_cid + 1;
1172 g_object_unref (part);
1174 g_object_unref (iter);
1178 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1181 gchar *to, *cc, *bcc, *subject;
1183 ModestMsgEditWindowPrivate *priv;
1184 ModestWindowPrivate *parent_priv;
1186 TnyHeaderFlags priority_flags;
1187 TnyFolder *msg_folder;
1188 gboolean is_html = FALSE;
1189 gboolean field_view_set;
1191 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1192 g_return_if_fail (TNY_IS_MSG (msg));
1194 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1195 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1197 header = tny_msg_get_header (msg);
1198 to = tny_header_dup_to (header);
1199 cc = tny_header_dup_cc (header);
1200 bcc = tny_header_dup_bcc (header);
1201 subject = tny_header_dup_subject (header);
1202 priority_flags = tny_header_get_priority (header);
1205 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1207 field_view_set = TRUE;
1209 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1210 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1211 gtk_widget_show (priv->cc_caption);
1212 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1213 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1214 gtk_widget_hide (priv->cc_caption);
1215 field_view_set = FALSE;
1217 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1219 field_view_set = TRUE;
1221 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1222 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1223 gtk_widget_show (priv->bcc_caption);
1224 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1225 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1226 gtk_widget_hide (priv->bcc_caption);
1227 field_view_set = FALSE;
1229 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1233 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1234 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1237 update_window_title (self);
1239 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1240 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1242 if ((body == NULL)||(body[0] == '\0')) {
1244 body = modest_text_utils_convert_to_html ("");
1247 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1248 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1251 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1254 /* Add attachments to the view */
1255 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1256 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1257 if (tny_list_get_length (priv->attachments) == 0) {
1258 gtk_widget_hide (priv->attachments_caption);
1260 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1261 gtk_widget_show_all (priv->attachments_caption);
1263 get_related_images (self, msg);
1264 update_next_cid (self, priv->attachments);
1265 update_next_cid (self, priv->images);
1266 replace_with_images (self, priv->images);
1268 if (preserve_is_rich && !is_html) {
1269 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1270 /* Get the default format required from configuration */
1271 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1272 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1275 /* Set the default focus depending on having already a To: field or not */
1276 if ((!to)||(*to == '\0')) {
1277 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1279 gtk_widget_grab_focus (priv->msg_body);
1282 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1284 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1285 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1287 modest_msg_edit_window_set_modified (self, FALSE);
1289 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1290 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1291 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1292 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1294 if (priv->msg_uid) {
1295 g_free (priv->msg_uid);
1296 priv->msg_uid = NULL;
1299 /* we should set a reference to the incoming message if it is a draft */
1300 msg_folder = tny_msg_get_folder (msg);
1302 if (modest_tny_folder_is_local_folder (msg_folder)) {
1303 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1304 if (type == TNY_FOLDER_TYPE_INVALID)
1305 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1307 if (type == TNY_FOLDER_TYPE_DRAFTS)
1308 priv->draft_msg = g_object_ref(msg);
1309 if (type == TNY_FOLDER_TYPE_OUTBOX)
1310 priv->outbox_msg = g_object_ref(msg);
1311 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1313 g_object_unref (msg_folder);
1324 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1326 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1327 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1328 GtkWidget *placeholder;
1329 GtkWidget *tool_item;
1334 GtkWidget *sizes_menu;
1335 GtkWidget *fonts_menu;
1339 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1340 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1341 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1342 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1344 /* Font color placeholder */
1345 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1346 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1349 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1350 priv->font_color_button = hildon_color_button_new ();
1351 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1352 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1353 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1354 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1355 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1356 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1357 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1358 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1360 G_CALLBACK (modest_msg_edit_window_color_button_change),
1363 /* Font size and face placeholder */
1364 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1365 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1367 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1368 priv->size_tool_button_label = gtk_label_new (NULL);
1369 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1370 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1371 size_text, "</span>", NULL);
1372 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1374 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1375 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1376 sizes_menu = gtk_menu_new ();
1377 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1378 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1381 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1382 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1384 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1388 if (wp_font_size[size_index] == 12)
1389 priv->current_size_index = size_index;
1393 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1394 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1395 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1396 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1397 priv->font_size_toolitem = tool_item;
1400 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1401 priv->font_tool_button_label = gtk_label_new (NULL);
1402 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1403 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1405 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1406 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1407 fonts_menu = gtk_menu_new ();
1408 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1409 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1412 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1414 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1415 0, wp_get_font_name (font_index),
1418 if (font_index == DEFAULT_FONT)
1419 priv->current_face_index = font_index;
1421 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1422 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1423 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1424 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1425 priv->font_face_toolitem = tool_item;
1427 /* Set expand and homogeneous for remaining items */
1428 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1429 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1430 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1431 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1432 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1433 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1434 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1435 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1436 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1438 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1439 will not show the tool items added to the placeholders) */
1440 gtk_widget_show_all (parent_priv->toolbar);
1442 /* Set the no show all *after* showing all items. We do not
1443 want the toolbar to be shown with a show all because it
1444 could go agains the gconf setting regarding showing or not
1445 the toolbar of the editor window */
1446 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1452 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1455 ModestWindowPrivate *parent_priv;
1456 ModestMsgEditWindowPrivate *priv;
1457 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1458 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1459 ModestWindowMgr *mgr = NULL;
1461 g_return_val_if_fail (msg, NULL);
1462 g_return_val_if_fail (account_name, NULL);
1464 mgr = modest_runtime_get_window_mgr ();
1466 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1468 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1469 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1471 /* Menubar. Update the state of some toggles */
1472 priv->from_field_protos = get_transports ();
1473 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1474 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1475 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1476 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1478 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1479 hildon_touch_selector_get_current_text
1480 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1481 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1482 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1485 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1487 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1489 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1491 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1493 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1494 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1495 /* Add common dimming rules */
1496 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1497 modest_msg_edit_window_toolbar_dimming_entries,
1498 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1499 MODEST_WINDOW (obj));
1500 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1501 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1502 MODEST_WINDOW (obj));
1503 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1504 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1505 MODEST_WINDOW (obj));
1506 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1507 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1508 MODEST_WINDOW (obj));
1509 /* Insert dimming rules group for this window */
1510 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1511 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1513 /* Setup app menu */
1514 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1516 /* Checks the dimming rules */
1517 g_object_unref (toolbar_rules_group);
1518 g_object_unref (clipboard_rules_group);
1519 gtk_widget_hide (priv->priority_icon);
1520 gtk_widget_queue_resize (priv->subject_box);
1521 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1523 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1525 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1526 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1527 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1528 priv->update_caption_visibility = TRUE;
1530 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1532 /* Track account-removed signal, this window should be closed
1533 in the case we're creating a mail associated to the account
1535 priv->account_removed_handler_id =
1536 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1538 G_CALLBACK(on_account_removed),
1541 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1543 return (ModestWindow*) obj;
1547 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1549 GString **string_buffer = (GString **) user_data;
1551 *string_buffer = g_string_append (*string_buffer, buffer);
1557 * @result: A new string which should be freed with g_free().
1560 get_formatted_data (ModestMsgEditWindow *edit_window)
1562 ModestMsgEditWindowPrivate *priv;
1563 GString *string_buffer = g_string_new ("");
1565 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1567 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1569 modest_text_utils_hyperlinkify (string_buffer);
1571 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1573 return g_string_free (string_buffer, FALSE);
1578 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1581 const gchar *account_name;
1582 ModestMsgEditWindowPrivate *priv;
1583 TnyIterator *att_iter;
1585 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1587 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1589 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1590 g_return_val_if_fail (account_name, NULL);
1593 /* don't free these (except from) */
1594 data = g_slice_new0 (MsgData);
1595 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1597 data->account_name = g_strdup (account_name);
1598 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1599 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1600 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1601 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1602 if (priv->draft_msg) {
1603 data->draft_msg = g_object_ref (priv->draft_msg);
1604 } else if (priv->outbox_msg) {
1605 data->draft_msg = g_object_ref (priv->outbox_msg);
1607 data->draft_msg = NULL;
1610 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1612 gtk_text_buffer_get_bounds (buf, &b, &e);
1613 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1615 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1616 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1618 data->html_body = NULL;
1620 /* deep-copy the data */
1621 att_iter = tny_list_create_iterator (priv->attachments);
1622 data->attachments = NULL;
1623 while (!tny_iterator_is_done (att_iter)) {
1624 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1625 if (!(TNY_IS_MIME_PART(part))) {
1626 g_warning ("strange data in attachment list");
1627 g_object_unref (part);
1628 tny_iterator_next (att_iter);
1631 data->attachments = g_list_append (data->attachments,
1633 tny_iterator_next (att_iter);
1635 g_object_unref (att_iter);
1637 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1638 att_iter = tny_list_create_iterator (priv->images);
1639 data->images = NULL;
1640 while (!tny_iterator_is_done (att_iter)) {
1641 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1643 if (!(TNY_IS_MIME_PART(part))) {
1644 g_warning ("strange data in attachment list");
1645 g_object_unref (part);
1646 tny_iterator_next (att_iter);
1649 cid = tny_mime_part_get_content_id (part);
1651 gchar *image_tag_id;
1652 GtkTextTag *image_tag;
1654 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1655 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1656 g_free (image_tag_id);
1658 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1660 ((gtk_text_iter_has_tag (&iter, image_tag))||
1661 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1662 data->images = g_list_append (data->images,
1663 g_object_ref (part));
1665 g_object_unref (part);
1666 tny_iterator_next (att_iter);
1668 g_object_unref (att_iter);
1670 data->priority_flags = priv->priority_flags;
1677 unref_gobject (GObject *obj, gpointer data)
1679 if (!G_IS_OBJECT(obj))
1681 g_object_unref (obj);
1685 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1688 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1696 g_free (data->from);
1697 g_free (data->subject);
1698 g_free (data->plain_body);
1699 g_free (data->html_body);
1700 g_free (data->account_name);
1702 if (data->draft_msg != NULL) {
1703 g_object_unref (data->draft_msg);
1704 data->draft_msg = NULL;
1707 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1708 g_list_free (data->attachments);
1709 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1710 g_list_free (data->images);
1712 g_slice_free (MsgData, data);
1716 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1718 guint64 *parts_size)
1720 ModestMsgEditWindowPrivate *priv;
1722 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1724 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1726 /* TODO: add images */
1727 *parts_size += priv->images_size;
1728 *parts_count += priv->images_count;
1733 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1736 ModestMsgEditWindowPrivate *priv = NULL;
1737 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1739 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1741 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1743 return MODEST_MSG_EDIT_FORMAT_HTML;
1745 return MODEST_MSG_EDIT_FORMAT_TEXT;
1749 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1750 ModestMsgEditFormat format)
1752 ModestMsgEditWindowPrivate *priv;
1754 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1755 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1758 case MODEST_MSG_EDIT_FORMAT_HTML:
1759 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1761 case MODEST_MSG_EDIT_FORMAT_TEXT:
1762 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1765 g_return_if_reached ();
1769 ModestMsgEditFormatState *
1770 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1772 ModestMsgEditFormatState *format_state = NULL;
1773 ModestMsgEditWindowPrivate *priv;
1774 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1776 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1777 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1779 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1781 format_state = g_new0 (ModestMsgEditFormatState, 1);
1782 format_state->bold = buffer_format->bold&0x1;
1783 format_state->italics = buffer_format->italic&0x1;
1784 format_state->bullet = buffer_format->bullet&0x1;
1785 format_state->color = buffer_format->color;
1786 format_state->font_size = buffer_format->font_size;
1787 format_state->font_family = wp_get_font_name (buffer_format->font);
1788 format_state->justification = buffer_format->justification;
1789 g_free (buffer_format);
1791 return format_state;
1796 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1797 const ModestMsgEditFormatState *format_state)
1799 ModestMsgEditWindowPrivate *priv;
1800 WPTextBufferFormat *buffer_format;
1801 WPTextBufferFormat *current_format;
1803 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1804 g_return_if_fail (format_state != NULL);
1806 buffer_format = g_new0 (WPTextBufferFormat, 1);
1807 current_format = g_new0 (WPTextBufferFormat, 1);
1809 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1810 gtk_widget_grab_focus (priv->msg_body);
1811 buffer_format->bold = (format_state->bold != FALSE);
1812 buffer_format->italic = (format_state->italics != FALSE);
1813 buffer_format->color = format_state->color;
1814 buffer_format->font_size = format_state->font_size;
1815 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1816 buffer_format->justification = format_state->justification;
1817 buffer_format->bullet = format_state->bullet;
1819 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1821 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1822 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1823 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1824 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1825 buffer_format->cs.font = (buffer_format->font != current_format->font);
1826 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1827 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1829 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1830 if (buffer_format->cs.bold) {
1831 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1832 GINT_TO_POINTER (buffer_format->bold&0x1));
1834 if (buffer_format->cs.italic) {
1835 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1836 GINT_TO_POINTER (buffer_format->italic&0x1));
1838 if (buffer_format->cs.color) {
1839 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1840 GINT_TO_POINTER (&(buffer_format->color)));
1842 if (buffer_format->cs.font_size) {
1843 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1844 GINT_TO_POINTER (buffer_format->font_size));
1846 if (buffer_format->cs.justification) {
1847 switch (buffer_format->justification) {
1848 case GTK_JUSTIFY_LEFT:
1849 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1850 GINT_TO_POINTER(TRUE));
1852 case GTK_JUSTIFY_CENTER:
1853 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1854 GINT_TO_POINTER(TRUE));
1856 case GTK_JUSTIFY_RIGHT:
1857 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1858 GINT_TO_POINTER(TRUE));
1865 if (buffer_format->cs.font) {
1866 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1867 GINT_TO_POINTER (buffer_format->font));
1869 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1870 if (buffer_format->cs.bullet) {
1871 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1872 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1874 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1876 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1878 g_free (buffer_format);
1879 g_free (current_format);
1881 /* Check dimming rules */
1882 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1883 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1887 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1889 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1891 ModestWindowPrivate *parent_priv;
1892 ModestMsgEditWindowPrivate *priv;
1894 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1895 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1897 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1898 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1899 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1900 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1902 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1903 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1904 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1907 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1909 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1910 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1912 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1913 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1915 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1916 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1919 switch (buffer_format->justification)
1921 case GTK_JUSTIFY_LEFT:
1922 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1924 case GTK_JUSTIFY_CENTER:
1925 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1927 case GTK_JUSTIFY_RIGHT:
1928 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1935 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1937 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1938 G_CALLBACK (modest_msg_edit_window_color_button_change),
1940 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1941 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1942 G_CALLBACK (modest_msg_edit_window_color_button_change),
1945 if (priv->current_size_index != buffer_format->font_size) {
1949 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1950 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1954 priv->current_size_index = buffer_format->font_size;
1956 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
1957 markup = g_strconcat ("<span font_family='Sans'>",
1958 size_text, "</span>", NULL);
1960 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1964 gtk_tree_path_free (path);
1967 if (priv->current_face_index != buffer_format->font) {
1971 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
1972 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
1976 priv->current_face_index = buffer_format->font;
1977 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
1978 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
1979 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1986 g_free (buffer_format);
1990 #ifdef MODEST_HILDON_VERSION_0
1992 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1995 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1996 ModestMsgEditWindowPrivate *priv;
1997 GtkWidget *dialog = NULL;
1999 GdkColor *new_color = NULL;
2001 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2002 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2004 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2005 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2006 g_free (buffer_format);
2008 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2009 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2010 if (new_color != NULL) {
2011 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2012 (gpointer) new_color);
2015 gtk_widget_destroy (dialog);
2020 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2023 ModestMsgEditWindowPrivate *priv;
2024 GtkWidget *dialog = NULL;
2026 GdkColor *old_color = NULL;
2027 const GdkColor *new_color = NULL;
2029 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2030 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2032 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2033 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2035 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2036 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2037 if (new_color != NULL)
2038 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2040 gtk_widget_destroy (dialog);
2046 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2049 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2050 ModestMsgEditWindowPrivate *priv;
2051 GtkWidget *dialog = NULL;
2053 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2054 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2056 dialog = hildon_color_chooser_new ();
2057 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2058 g_free (buffer_format);
2060 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2062 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2063 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2066 gtk_widget_destroy (dialog);
2071 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2074 ModestMsgEditWindowPrivate *priv;
2075 GtkWidget *dialog = NULL;
2076 GdkColor *old_color = NULL;
2078 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2079 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2081 dialog = hildon_color_chooser_new ();
2082 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2084 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2086 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2087 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2089 gtk_widget_destroy (dialog);
2092 #endif /*!MODEST_HILDON_VERSION_0*/
2097 create_stream_for_uri (const gchar* uri)
2102 TnyStream *result = NULL;
2104 GnomeVFSHandle *handle = NULL;
2105 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2106 if (test == GNOME_VFS_OK) {
2107 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2108 /* Streams over OBEX (Bluetooth) are not seekable but
2109 * we expect them to be (we might need to read them
2110 * several times). So if this is a Bluetooth URI just
2111 * read the whole file into memory (this is not a fast
2112 * protocol so we can assume that these files are not
2113 * going to be very big) */
2114 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2115 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2116 TnyStream *memstream = tny_camel_mem_stream_new ();
2117 tny_stream_write_to_stream (vfssstream, memstream);
2118 g_object_unref (vfssstream);
2121 result = vfssstream;
2129 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2132 ModestMsgEditWindowPrivate *priv;
2133 GtkWidget *dialog = NULL;
2135 GSList *uris = NULL;
2136 GSList *uri_node = NULL;
2138 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2140 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2141 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2142 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2144 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2146 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2147 GTK_WINDOW (dialog), GTK_WINDOW (window));
2149 response = gtk_dialog_run (GTK_DIALOG (dialog));
2151 case GTK_RESPONSE_OK:
2152 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2157 gtk_widget_destroy (dialog);
2159 g_object_ref (window);
2160 /* The operation could take some time so allow the dialog to be closed */
2161 while (gtk_events_pending ())
2162 gtk_main_iteration ();
2164 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2166 GnomeVFSHandle *handle = NULL;
2167 GnomeVFSResult result;
2168 GtkTextIter position;
2169 GtkTextMark *insert_mark;
2171 uri = (const gchar *) uri_node->data;
2172 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2173 if (result == GNOME_VFS_OK) {
2175 GnomeVFSFileInfo *info;
2176 gchar *filename, *basename, *escaped_filename;
2177 TnyMimePart *mime_part;
2179 const gchar *mime_type = NULL;
2180 GnomeVFSURI *vfs_uri;
2181 guint64 stream_size;
2183 gnome_vfs_close (handle);
2184 vfs_uri = gnome_vfs_uri_new (uri);
2186 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2187 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2188 g_free (escaped_filename);
2189 gnome_vfs_uri_unref (vfs_uri);
2190 info = gnome_vfs_file_info_new ();
2192 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2193 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2195 mime_type = gnome_vfs_file_info_get_mime_type (info);
2197 mime_part = tny_platform_factory_new_mime_part
2198 (modest_runtime_get_platform_factory ());
2200 TnyStream *stream = create_stream_for_uri (uri);
2202 if (stream == NULL) {
2204 modest_platform_information_banner (NULL, NULL,
2205 _FM("sfil_ib_opening_not_allowed"));
2207 g_object_unref (mime_part);
2208 gnome_vfs_file_info_unref (info);
2212 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2214 content_id = g_strdup_printf ("%d", priv->next_cid);
2215 tny_mime_part_set_content_id (mime_part, content_id);
2216 g_free (content_id);
2219 basename = g_path_get_basename (filename);
2220 tny_mime_part_set_filename (mime_part, basename);
2223 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2225 if (pixbuf != NULL) {
2226 priv->images_size += stream_size;
2227 priv->images_count ++;
2228 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2229 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2230 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2231 tny_mime_part_get_content_id (mime_part), pixbuf);
2232 g_object_unref (pixbuf);
2234 tny_list_prepend (priv->images, (GObject *) mime_part);
2235 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2237 modest_platform_information_banner (NULL, NULL,
2238 _("mail_ib_file_operation_failed"));
2242 g_object_unref (mime_part);
2243 gnome_vfs_file_info_unref (info);
2247 g_object_unref (window);
2251 on_attach_file_response (GtkDialog *dialog,
2255 GSList *uris = NULL;
2257 GnomeVFSFileSize total_size, allowed_size;
2258 ModestMsgEditWindow *window;
2259 ModestMsgEditWindowPrivate *priv;
2264 case GTK_RESPONSE_OK:
2265 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2271 window = MODEST_MSG_EDIT_WINDOW (user_data);
2272 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2274 /* allowed size is the maximum size - what's already there */
2275 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2276 &att_num, &att_size);
2277 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2280 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2282 const gchar *uri = (const gchar *) uri_node->data;
2285 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2287 if (total_size > allowed_size) {
2288 g_warning ("%s: total size: %u",
2289 __FUNCTION__, (unsigned int)total_size);
2292 allowed_size -= total_size;
2294 g_slist_foreach (uris, (GFunc) g_free, NULL);
2295 g_slist_free (uris);
2297 gtk_widget_destroy (GTK_WIDGET (dialog));
2301 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2303 GtkWidget *dialog = NULL;
2304 ModestMsgEditWindowPrivate *priv;
2306 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2308 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2310 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2313 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2314 GTK_FILE_CHOOSER_ACTION_OPEN);
2315 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2316 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2317 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2318 GTK_WINDOW (dialog), GTK_WINDOW (window));
2320 /* Connect to response & show */
2321 g_signal_connect (dialog, "response",
2322 G_CALLBACK (on_attach_file_response), window);
2323 gtk_widget_show (dialog);
2328 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2330 GnomeVFSFileSize allowed_size)
2333 GnomeVFSHandle *handle = NULL;
2334 ModestMsgEditWindowPrivate *priv;
2335 GnomeVFSResult result;
2336 GnomeVFSFileSize size = 0;
2337 g_return_val_if_fail (window, 0);
2338 g_return_val_if_fail (uri, 0);
2340 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2342 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2343 if (result == GNOME_VFS_OK) {
2344 TnyMimePart *mime_part;
2346 const gchar *mime_type = NULL;
2348 gchar *escaped_filename;
2351 GnomeVFSFileInfo *info;
2352 GnomeVFSURI *vfs_uri;
2354 gnome_vfs_close (handle);
2355 vfs_uri = gnome_vfs_uri_new (uri);
2358 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2359 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2360 g_free (escaped_filename);
2361 gnome_vfs_uri_unref (vfs_uri);
2363 info = gnome_vfs_file_info_new ();
2365 if (gnome_vfs_get_file_info (uri,
2367 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2369 mime_type = gnome_vfs_file_info_get_mime_type (info);
2370 mime_part = tny_platform_factory_new_mime_part
2371 (modest_runtime_get_platform_factory ());
2373 /* try to get the attachment's size; this may fail for weird
2374 * file systems, like obex, upnp... */
2375 if (allowed_size != 0 &&
2376 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2378 if (size > allowed_size) {
2379 modest_platform_information_banner (NULL, NULL,
2380 _FM("sfil_ib_opening_not_allowed"));
2385 g_warning ("%s: could not get attachment size", __FUNCTION__);
2387 stream = create_stream_for_uri (uri);
2389 if (stream == NULL) {
2391 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2393 g_object_unref (mime_part);
2395 gnome_vfs_file_info_unref (info);
2399 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2400 g_object_unref (stream);
2402 content_id = g_strdup_printf ("%d", priv->next_cid);
2403 tny_mime_part_set_content_id (mime_part, content_id);
2404 g_free (content_id);
2407 basename = g_path_get_basename (filename);
2408 tny_mime_part_set_filename (mime_part, basename);
2411 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2412 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2414 info->size == 0, info->size);
2415 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2416 gtk_widget_show_all (priv->attachments_caption);
2417 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2419 g_object_unref (mime_part);
2420 gnome_vfs_file_info_unref (info);
2427 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2430 ModestMsgEditWindowPrivate *priv;
2433 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2434 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2436 if (att_list == NULL) {
2437 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2438 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2439 g_object_unref (att_list);
2444 g_object_ref (att_list);
2447 if (tny_list_get_length (att_list) == 0) {
2448 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2450 gboolean dialog_response;
2451 gchar *message = NULL;
2452 gchar *filename = NULL;
2454 if (tny_list_get_length (att_list) == 1) {
2456 iter = tny_list_create_iterator (att_list);
2457 part = (TnyMimePart *) tny_iterator_get_current (iter);
2458 g_object_unref (iter);
2459 if (TNY_IS_MSG (part)) {
2460 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2462 filename = tny_header_dup_subject (header);
2463 g_object_unref (header);
2465 if (filename == NULL) {
2466 filename = g_strdup (_("mail_va_no_subject"));
2469 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2471 g_object_unref (part);
2473 filename = g_strdup ("");
2475 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2476 "emev_nc_delete_attachments",
2477 tny_list_get_length (att_list)), filename);
2480 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2484 if (dialog_response != GTK_RESPONSE_OK) {
2485 g_object_unref (att_list);
2489 for (iter = tny_list_create_iterator (att_list);
2490 !tny_iterator_is_done (iter);
2491 tny_iterator_next (iter)) {
2492 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2493 const gchar *att_id;
2494 tny_list_remove (priv->attachments, (GObject *) mime_part);
2496 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2498 if (tny_list_get_length (priv->attachments) == 0)
2499 gtk_widget_hide (priv->attachments_caption);
2500 att_id = tny_mime_part_get_content_id (mime_part);
2502 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2504 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2505 g_object_unref (mime_part);
2507 g_object_unref (iter);
2510 g_object_unref (att_list);
2512 /* if the last attachment has been removed, focus the Subject: field */
2513 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2514 gtk_widget_grab_focus (priv->subject_field);
2518 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2521 ModestMsgEditWindowPrivate *priv;
2522 GdkColor *new_color;
2523 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2525 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2526 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2529 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2531 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2533 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2535 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2540 font_size_clicked (GtkToolButton *button,
2541 ModestMsgEditWindow *window)
2543 ModestMsgEditWindowPrivate *priv;
2544 GtkWidget *selector, *dialog;
2546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2548 selector = hildon_touch_selector_new ();
2549 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2550 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2552 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2553 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2555 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2559 WPTextBufferFormat format;
2561 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2563 memset (&format, 0, sizeof (format));
2564 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2566 format.cs.font_size = TRUE;
2567 format.cs.text_position = TRUE;
2568 format.cs.font = TRUE;
2569 format.font_size = new_index;
2570 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2572 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2573 GINT_TO_POINTER (new_index)))
2574 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2576 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2577 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2578 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2579 size_text, "</span>", NULL);
2581 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2585 gtk_widget_destroy (dialog);
2587 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2592 font_face_clicked (GtkToolButton *button,
2593 ModestMsgEditWindow *window)
2595 ModestMsgEditWindowPrivate *priv;
2596 GtkWidget *selector, *dialog;
2597 GtkCellRenderer *renderer;
2599 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2601 selector = hildon_touch_selector_new ();
2602 renderer = gtk_cell_renderer_text_new ();
2603 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2604 renderer, "family", 0, "text", 0, NULL);
2605 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2607 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2608 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2610 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2611 gint new_font_index;
2615 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2616 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2617 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2621 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2623 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2624 GINT_TO_POINTER(new_font_index)))
2625 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2627 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2628 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2630 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2634 gtk_tree_path_free (path);
2637 gtk_widget_destroy (dialog);
2639 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2644 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2647 ModestMsgEditWindowPrivate *priv = NULL;
2648 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2650 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2651 if (!priv->update_caption_visibility)
2654 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2656 gtk_widget_show (priv->cc_caption);
2658 gtk_widget_hide (priv->cc_caption);
2660 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2664 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2667 ModestMsgEditWindowPrivate *priv = NULL;
2668 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2670 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2671 if (!priv->update_caption_visibility)
2674 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2676 gtk_widget_show (priv->bcc_caption);
2678 gtk_widget_hide (priv->bcc_caption);
2680 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2684 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2685 ModestRecptEditor *editor)
2687 ModestMsgEditWindowPrivate *priv;
2689 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2690 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2692 /* we check for low-mem; in that case, show a warning, and don't allow
2693 * for the addressbook
2695 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2698 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2700 if (editor == NULL) {
2701 GtkWidget *view_focus;
2702 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2704 /* This code should be kept in sync with ModestRecptEditor. The
2705 textview inside the recpt editor is the one that really gets the
2706 focus. As it's inside a scrolled window, and this one inside the
2707 hbox recpt editor inherits from, we'll need to go up in the
2708 hierarchy to know if the text view is part of the recpt editor
2709 or if it's a different text entry */
2711 if (gtk_widget_get_parent (view_focus)) {
2712 GtkWidget *first_parent;
2714 first_parent = gtk_widget_get_parent (view_focus);
2715 if (gtk_widget_get_parent (first_parent) &&
2716 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2717 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2722 editor = MODEST_RECPT_EDITOR (priv->to_field);
2726 modest_address_book_select_addresses (editor);
2731 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2733 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2735 modest_msg_edit_window_open_addressbook (window, NULL);
2739 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2740 gboolean show_toolbar)
2742 ModestWindowPrivate *parent_priv;
2744 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2745 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2747 /* We can not just use the code of
2748 modest_msg_edit_window_setup_toolbar because it has a
2749 mixture of both initialization and creation code. */
2751 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2753 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2757 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2758 TnyHeaderFlags priority_flags)
2760 ModestMsgEditWindowPrivate *priv;
2761 ModestWindowPrivate *parent_priv;
2763 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2765 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2766 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2768 if (priv->priority_flags != priority_flags) {
2769 GtkAction *priority_action = NULL;
2771 priv->priority_flags = priority_flags;
2773 switch (priority_flags) {
2774 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2775 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2776 MODEST_HEADER_ICON_HIGH,
2777 HILDON_ICON_SIZE_SMALL);
2778 gtk_widget_show (priv->priority_icon);
2779 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2780 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2782 case TNY_HEADER_FLAG_LOW_PRIORITY:
2783 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2784 MODEST_HEADER_ICON_LOW,
2785 HILDON_ICON_SIZE_SMALL);
2786 gtk_widget_show (priv->priority_icon);
2787 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2788 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2791 gtk_widget_hide (priv->priority_icon);
2792 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2793 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2796 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2797 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2799 gtk_widget_queue_resize (priv->subject_box);
2803 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2806 ModestMsgEditWindowPrivate *priv;
2807 ModestWindowPrivate *parent_priv;
2808 gint current_format;
2810 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2812 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2813 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2815 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2816 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2818 if (current_format != file_format) {
2819 switch (file_format) {
2820 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2821 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2822 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2824 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2828 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2829 response = gtk_dialog_run (GTK_DIALOG (dialog));
2830 gtk_widget_destroy (dialog);
2831 if (response == GTK_RESPONSE_OK) {
2832 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2834 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2835 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2840 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2841 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2842 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2847 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2850 ModestMsgEditWindowPrivate *priv;
2851 WPTextBufferFormat oldfmt, fmt;
2852 gint old_position = 0;
2856 GdkColor *color = NULL;
2857 gboolean bold, bold_set, italic, italic_set;
2858 gboolean underline, underline_set;
2859 gboolean strikethrough, strikethrough_set;
2860 gboolean position_set;
2861 gboolean font_size_set, font_set, color_set;
2864 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2865 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2867 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2868 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2869 GTK_WINDOW(dialog), GTK_WINDOW (window));
2871 /* First we get the currently selected font information */
2872 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2874 switch (oldfmt.text_position) {
2875 case TEXT_POSITION_NORMAL:
2878 case TEXT_POSITION_SUPERSCRIPT:
2886 g_object_set (G_OBJECT (dialog),
2887 "bold", oldfmt.bold != FALSE,
2888 "bold-set", !oldfmt.cs.bold,
2889 "underline", oldfmt.underline != FALSE,
2890 "underline-set", !oldfmt.cs.underline,
2891 "italic", oldfmt.italic != FALSE,
2892 "italic-set", !oldfmt.cs.italic,
2893 "strikethrough", oldfmt.strikethrough != FALSE,
2894 "strikethrough-set", !oldfmt.cs.strikethrough,
2895 "color", &oldfmt.color,
2896 "color-set", !oldfmt.cs.color,
2897 "size", wp_font_size[oldfmt.font_size],
2898 "size-set", !oldfmt.cs.font_size,
2899 "position", old_position,
2900 "position-set", !oldfmt.cs.text_position,
2901 "family", wp_get_font_name (oldfmt.font),
2902 "family-set", !oldfmt.cs.font,
2905 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2906 GTK_WINDOW (dialog), GTK_WINDOW (window));
2907 gtk_widget_show_all (dialog);
2908 priv->font_dialog = dialog;
2909 response = gtk_dialog_run (GTK_DIALOG (dialog));
2910 priv->font_dialog = NULL;
2911 if (response == GTK_RESPONSE_OK) {
2913 g_object_get( dialog,
2915 "bold-set", &bold_set,
2916 "underline", &underline,
2917 "underline-set", &underline_set,
2919 "italic-set", &italic_set,
2920 "strikethrough", &strikethrough,
2921 "strikethrough-set", &strikethrough_set,
2923 "color-set", &color_set,
2925 "size-set", &font_size_set,
2926 "family", &font_name,
2927 "family-set", &font_set,
2928 "position", &position,
2929 "position-set", &position_set,
2934 if (response == GTK_RESPONSE_OK) {
2935 memset(&fmt, 0, sizeof(fmt));
2941 fmt.italic = italic;
2942 fmt.cs.italic = TRUE;
2944 if (underline_set) {
2945 fmt.underline = underline;
2946 fmt.cs.underline = TRUE;
2948 if (strikethrough_set) {
2949 fmt.strikethrough = strikethrough;
2950 fmt.cs.strikethrough = TRUE;
2955 ? TEXT_POSITION_NORMAL
2956 : ( ( position == 1 )
2957 ? TEXT_POSITION_SUPERSCRIPT
2958 : TEXT_POSITION_SUBSCRIPT );
2959 fmt.cs.text_position = TRUE;
2960 fmt.font_size = oldfmt.font_size;
2964 fmt.cs.color = TRUE;
2967 fmt.font = wp_get_font_index(font_name,
2972 if (font_size_set) {
2973 fmt.cs.font_size = TRUE;
2974 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2976 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2977 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2979 gtk_widget_destroy (dialog);
2981 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2985 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2987 ModestMsgEditWindowPrivate *priv;
2989 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2990 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2992 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2994 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2995 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2999 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3001 ModestMsgEditWindowPrivate *priv;
3003 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3004 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3006 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3008 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3009 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3014 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3016 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3018 priv->can_undo = can_undo;
3022 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3024 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3026 priv->can_redo = can_redo;
3030 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3032 ModestMsgEditWindowPrivate *priv;
3033 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3034 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3036 return priv->can_undo;
3040 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3042 ModestMsgEditWindowPrivate *priv;
3043 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3044 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3046 return priv->can_redo;
3051 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3054 GtkTextIter match_start, match_end;
3056 if (image_id == NULL)
3059 gtk_text_buffer_get_start_iter (buffer, &iter);
3061 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3062 GSList *tags = gtk_text_iter_get_tags (&match_start);
3064 for (node = tags; node != NULL; node = g_slist_next (node)) {
3065 GtkTextTag *tag = (GtkTextTag *) node->data;
3066 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3067 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3068 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3070 offset = gtk_text_iter_get_offset (&match_start);
3071 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3072 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3076 gtk_text_iter_forward_char (&iter);
3081 message_is_empty (ModestMsgEditWindow *window)
3083 ModestMsgEditWindowPrivate *priv = NULL;
3085 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3086 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3088 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3089 * so we can ignore markup.
3091 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3094 count = gtk_text_buffer_get_char_count (buf);
3100 msg_body_focus (GtkWidget *focus,
3101 GdkEventFocus *event,
3105 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3106 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3107 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3112 recpt_field_changed (GtkTextBuffer *buffer,
3113 ModestMsgEditWindow *editor)
3115 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3116 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3120 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3122 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3123 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3127 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3130 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3131 GtkTextBuffer *buffer;
3133 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3134 gtk_text_buffer_set_modified (buffer, modified);
3135 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3136 gtk_text_buffer_set_modified (buffer, modified);
3137 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3138 gtk_text_buffer_set_modified (buffer, modified);
3139 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3143 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3145 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3146 const char *account_name;
3147 GtkTextBuffer *buffer;
3149 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3150 if (gtk_text_buffer_get_modified (buffer))
3152 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3153 if (gtk_text_buffer_get_modified (buffer))
3155 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3156 if (gtk_text_buffer_get_modified (buffer))
3158 if (gtk_text_buffer_get_modified (priv->text_buffer))
3160 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3161 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3172 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3174 ModestMsgEditWindowPrivate *priv = NULL;
3176 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3177 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3179 /* check if there's no recipient added */
3180 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3181 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3182 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3183 /* no recipient contents, then select contacts */
3184 modest_msg_edit_window_open_addressbook (window, NULL);
3188 g_object_ref (window);
3189 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3190 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3191 g_object_unref (window);
3194 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3195 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3196 g_object_unref (window);
3199 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3200 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3201 g_object_unref (window);
3205 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3206 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3207 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3208 g_object_unref (window);
3215 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3216 ModestMsgEditWindow *window)
3218 modest_msg_edit_window_offer_attach_file (window);
3222 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3224 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3226 return priv->clipboard_text;
3230 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3232 ModestMsgEditWindow *window)
3234 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3235 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3237 if (!GTK_WIDGET_VISIBLE (window))
3240 g_object_ref (window);
3241 text = gtk_clipboard_wait_for_text (selection_clipboard);
3243 if (priv->clipboard_text != NULL) {
3244 g_free (priv->clipboard_text);
3246 priv->clipboard_text = text;
3248 if (GTK_WIDGET_VISIBLE (window)) {
3249 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3251 g_object_unref (window);
3254 static gboolean clipboard_owner_change_idle (gpointer userdata)
3256 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3257 ModestMsgEditWindowPrivate *priv;
3259 gdk_threads_enter ();
3260 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3261 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3263 priv->clipboard_owner_idle = 0;
3264 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3265 gdk_threads_leave ();
3271 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3273 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3274 if (priv->clipboard_owner_idle == 0) {
3275 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3280 subject_field_move_cursor (GtkEntry *entry,
3281 GtkMovementStep step,
3286 if (!GTK_WIDGET_VISIBLE (window))
3289 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3293 update_window_title (ModestMsgEditWindow *window)
3295 ModestMsgEditWindowPrivate *priv = NULL;
3296 const gchar *subject;
3298 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3299 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3300 if (subject == NULL || subject[0] == '\0')
3301 subject = _("mail_va_new_email");
3303 gtk_window_set_title (GTK_WINDOW (window), subject);
3308 subject_field_changed (GtkEditable *editable,
3309 ModestMsgEditWindow *window)
3311 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3312 update_window_title (window);
3313 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3314 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3315 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3319 subject_field_insert_text (GtkEditable *editable,
3321 gint new_text_length,
3323 ModestMsgEditWindow *window)
3325 GString *result = g_string_new ("");
3327 gint result_len = 0;
3328 const gchar *entry_text = NULL;
3331 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3332 old_length = g_utf8_strlen (entry_text, -1);
3334 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3335 gunichar c = g_utf8_get_char_validated (current, 8);
3336 /* Invalid unichar, stop */
3342 result = g_string_append_unichar (result, c);
3346 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3347 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3350 /* Prevent endless recursion */
3351 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3352 g_signal_emit_by_name (editable, "insert-text",
3353 (gpointer) result->str, (gpointer) result->len,
3354 (gpointer) position, (gpointer) window);
3355 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3359 if (result_len + old_length > 1000) {
3360 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3361 _CS("ckdg_ib_maximum_characters_reached"));
3363 g_string_free (result, TRUE);
3367 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3370 ModestMsgEditWindowPrivate *priv = NULL;
3372 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3373 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3375 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3378 gtk_widget_show_all (priv->find_toolbar);
3379 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3381 gtk_widget_hide_all (priv->find_toolbar);
3382 gtk_widget_grab_focus (priv->msg_body);
3387 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3389 GtkTextIter *match_start,
3390 GtkTextIter *match_end)
3392 GtkTextIter end_iter;
3393 gchar *str_casefold;
3396 gchar *range_casefold;
3399 gboolean result = FALSE;
3406 gtk_text_iter_forward_to_end (&end_iter);
3408 str_casefold = g_utf8_casefold (str, -1);
3409 str_chars_n = strlen (str);
3411 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3412 range_casefold = g_utf8_casefold (range_text, -1);
3413 range_chars_n = strlen (range_casefold);
3415 if (range_chars_n < str_chars_n) {
3416 g_free (str_casefold);
3417 g_free (range_text);
3418 g_free (range_casefold);
3422 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3423 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3424 if (!g_utf8_collate (range_subtext, str_casefold)) {
3425 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3427 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3428 match_start, match_end, NULL);
3429 g_free (found_text);
3431 g_free (range_subtext);
3435 g_free (str_casefold);
3436 g_free (range_text);
3437 g_free (range_casefold);
3444 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3445 ModestMsgEditWindow *window)
3447 gchar *current_search = NULL;
3448 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3450 GtkTextIter selection_start, selection_end;
3451 GtkTextIter match_start, match_end;
3452 gboolean continue_search = FALSE;
3454 if (message_is_empty (window)) {
3455 g_free (priv->last_search);
3456 priv->last_search = NULL;
3457 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3461 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3462 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3463 g_free (current_search);
3464 g_free (priv->last_search);
3465 priv->last_search = NULL;
3466 /* Information banner about empty search */
3467 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3471 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3472 continue_search = TRUE;
3474 g_free (priv->last_search);
3475 priv->last_search = g_strdup (current_search);
3478 if (continue_search) {
3479 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3480 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3481 &match_start, &match_end);
3483 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3485 GtkTextIter buffer_start;
3486 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3487 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3488 &match_start, &match_end);
3490 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3493 /* Mark as selected the string found in search */
3495 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3496 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3497 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3499 g_free (priv->last_search);
3500 priv->last_search = NULL;
3502 g_free (current_search);
3506 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3508 ModestMsgEditWindowPrivate *priv;
3510 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3515 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3518 ModestMsgEditWindowPrivate *priv;
3520 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3525 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3526 ModestMsgEditWindow *window)
3528 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3532 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3535 ModestMsgEditWindowPrivate *priv;
3536 TnyHeader *header = NULL;
3538 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3539 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3541 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3542 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3544 if (priv->draft_msg != NULL) {
3545 g_object_unref (priv->draft_msg);
3548 if (draft != NULL) {
3549 g_object_ref (draft);
3550 header = tny_msg_get_header (draft);
3551 if (priv->msg_uid) {
3552 g_free (priv->msg_uid);
3553 priv->msg_uid = NULL;
3555 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3556 if (GTK_WIDGET_REALIZED (window)) {
3557 if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3558 gtk_widget_destroy (GTK_WIDGET (window));
3564 priv->draft_msg = draft;
3568 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3569 GtkTextIter *start, GtkTextIter *end,
3572 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3573 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3576 if (tag == NULL) return;
3577 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3578 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3579 replace_with_images (window, priv->images);
3584 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3587 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3589 g_return_if_fail (TNY_IS_MIME_PART (part));
3590 tny_list_prepend (priv->attachments, (GObject *) part);
3591 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3592 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3593 gtk_widget_show_all (priv->attachments_caption);
3594 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3598 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3600 ModestMsgEditWindowPrivate *priv;
3602 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3603 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3605 return priv->msg_uid;
3609 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3610 ModestMsgEditWindowWidgetType widget_type)
3612 ModestMsgEditWindowPrivate *priv;
3614 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3615 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3617 switch (widget_type) {
3618 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3619 return priv->msg_body;
3621 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3622 return priv->to_field;
3624 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3625 return priv->cc_field;
3627 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3628 return priv->bcc_field;
3630 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3631 return priv->subject_field;
3633 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3634 return priv->attachments_view;
3642 remove_tags (WPTextBuffer *buffer)
3644 GtkTextIter start, end;
3646 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3647 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3649 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3653 on_account_removed (TnyAccountStore *account_store,
3654 TnyAccount *account,
3657 /* Do nothing if it's a store account, because we use the
3658 transport to send the messages */
3659 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3660 const gchar *parent_acc = NULL;
3661 const gchar *our_acc = NULL;
3663 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3664 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3665 /* Close this window if I'm showing a message of the removed account */
3666 if (strcmp (parent_acc, our_acc) == 0)
3667 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3672 from_field_changed (HildonPickerButton *button,
3673 ModestMsgEditWindow *self)
3675 ModestMsgEditWindowPrivate *priv;
3676 gboolean has_old_signature, has_new_signature;
3678 GtkTextIter match_start, match_end;
3679 ModestAccountMgr *mgr;
3681 gchar *full_signature;
3683 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3685 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3686 mgr = modest_runtime_get_account_mgr ();
3687 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3688 if (has_old_signature) {
3689 full_signature = g_strconcat ("\n--\n", signature, NULL);
3690 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3691 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3693 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3694 &match_start, &match_end, NULL)) {
3697 g_free (full_signature);
3701 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3702 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3703 if (has_new_signature) {
3704 full_signature = g_strconcat ("\n--\n", signature, NULL);
3705 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3706 g_free (full_signature);
3711 typedef struct _MessageSettingsHelper {
3712 ModestMsgEditWindow *window;
3713 GSList *priority_group;
3714 GSList *format_group;
3715 GtkToggleButton *current_priority;
3716 GtkToggleButton *current_format;
3717 } MessageSettingsHelper;
3720 on_priority_toggle (GtkToggleButton *button,
3721 MessageSettingsHelper *helper)
3724 ModestMsgEditWindowPrivate *priv;
3726 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3727 if (gtk_toggle_button_get_active (button)) {
3729 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3730 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3731 if ((node_button != button) &&
3732 gtk_toggle_button_get_active (node_button)) {
3733 gtk_toggle_button_set_active (node_button, FALSE);
3736 helper->current_priority = button;
3738 gboolean found = FALSE;
3739 /* If no one is active, activate it again */
3740 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3741 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3742 if (gtk_toggle_button_get_active (node_button)) {
3748 gtk_toggle_button_set_active (button, TRUE);
3754 on_format_toggle (GtkToggleButton *button,
3755 MessageSettingsHelper *helper)
3758 ModestMsgEditWindowPrivate *priv;
3760 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3761 if (gtk_toggle_button_get_active (button)) {
3763 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3764 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3765 if ((node_button != button) &&
3766 gtk_toggle_button_get_active (node_button)) {
3767 gtk_toggle_button_set_active (node_button, FALSE);
3770 helper->current_format = button;
3772 gboolean found = FALSE;
3773 /* If no one is active, activate it again */
3774 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3775 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3776 if (gtk_toggle_button_get_active (node_button)) {
3782 gtk_toggle_button_set_active (button, TRUE);
3789 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3794 GtkWidget *priority_hbox;
3795 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3796 GtkWidget *captioned;
3797 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3798 GtkWidget *format_hbox;
3799 GtkWidget *html_toggle, *text_toggle;
3800 ModestMsgEditWindowPrivate *priv;
3801 MessageSettingsHelper helper = {0,};
3803 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3804 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3805 helper.window = window;
3806 helper.priority_group = NULL;
3807 helper.format_group = NULL;
3809 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3810 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3812 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3813 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3814 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3815 vbox = gtk_vbox_new (FALSE, 0);
3816 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3817 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3818 gtk_container_add (GTK_CONTAINER (align), vbox);
3819 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3820 gtk_widget_show (align);
3821 gtk_widget_show (vbox);
3823 /* Priority toggles */
3824 priority_hbox = gtk_hbox_new (TRUE, 0);
3825 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3826 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3827 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3828 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3829 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3830 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3831 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3832 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3833 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3834 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3835 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3836 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3837 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3838 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3839 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3840 gtk_widget_show_all (priority_hbox);
3841 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3842 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3843 gtk_widget_show (captioned);
3844 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3846 /* format toggles */
3847 format_hbox = gtk_hbox_new (TRUE, 0);
3848 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3849 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3850 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3851 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3852 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3853 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3854 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3855 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3856 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3857 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3858 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3859 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3860 gtk_widget_show_all (format_hbox);
3861 gtk_widget_show (format_hbox);
3862 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3865 g_object_unref (title_sizegroup);
3866 g_object_unref (value_sizegroup);
3868 /* Set current values */
3869 switch (priv->priority_flags) {
3870 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3871 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3872 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3874 case TNY_HEADER_FLAG_LOW_PRIORITY:
3875 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3876 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3879 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3880 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3884 switch (modest_msg_edit_window_get_format (window)) {
3885 case MODEST_MSG_EDIT_FORMAT_TEXT:
3886 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3887 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3889 case MODEST_MSG_EDIT_FORMAT_HTML:
3891 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3892 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3896 /* Signal connects */
3897 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3898 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3899 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3900 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3901 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3903 /* Save settings if the user clicked on done */
3904 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3905 TnyHeaderFlags flags;
3906 ModestMsgEditFormat old_format, new_format;
3908 /* Set priority flags */
3909 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3910 if (priv->priority_flags != flags)
3911 modest_msg_edit_window_set_priority_flags (window, flags);
3913 /* Set edit format */
3914 old_format = modest_msg_edit_window_get_format (window);
3915 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3916 if (old_format != new_format) {
3917 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3918 modest_msg_edit_window_set_file_format (window, file_format);
3922 gtk_widget_destroy (dialog);
3923 g_slist_free (helper.priority_group);
3927 on_message_settings (GtkAction *action,
3928 ModestMsgEditWindow *window)
3930 modest_msg_edit_window_show_msg_settings_dialog (window);
3934 on_cc_button_toggled (HildonCheckButton *button,
3935 ModestMsgEditWindow *window)
3937 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3939 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3940 hildon_check_button_get_active (button));
3944 on_bcc_button_toggled (HildonCheckButton *button,
3945 ModestMsgEditWindow *window)
3947 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3949 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3950 hildon_check_button_get_active (button));
3954 setup_menu (ModestMsgEditWindow *self)
3956 ModestMsgEditWindowPrivate *priv = NULL;
3958 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3960 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3962 /* Settings menu buttons */
3963 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3964 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3966 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3967 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3968 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3970 priv->cc_button = hildon_check_button_new (0);
3971 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
3972 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
3974 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
3976 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
3977 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
3978 priv->bcc_button = hildon_check_button_new (0);
3979 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
3980 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
3982 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
3984 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
3985 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
3987 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
3988 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
3989 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
3990 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3991 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
3992 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
3993 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
3994 APP_MENU_CALLBACK (on_message_settings),
3996 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
3997 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),