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 /* It could happen that the window was already closed */
489 if (!GTK_WIDGET_VISIBLE (win))
492 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
494 correct_scroll_without_drag_check (win, TRUE);
496 priv->scroll_drag_timeout_id = 0;
502 correct_scroll_without_drag_check_idle (gpointer userdata)
504 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
505 ModestMsgEditWindowPrivate *priv;
507 GdkRectangle rectangle;
508 gint offset_min, offset_max;
512 /* It could happen that the window was already closed */
513 if (!GTK_WIDGET_VISIBLE (w))
516 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
518 insert = gtk_text_buffer_get_insert (priv->text_buffer);
519 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
521 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
522 offset_min = priv->msg_body->allocation.y + rectangle.y;
523 offset_max = offset_min + rectangle.height;
525 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
526 offset_min = MAX (offset_min - 48, 0);
527 offset_max = MIN (offset_max + 48, vadj->upper);
529 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
531 priv->correct_scroll_idle = 0;
536 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
538 ModestMsgEditWindowPrivate *priv;
540 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
542 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
545 if (priv->correct_scroll_idle > 0) {
549 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
550 (GSourceFunc) correct_scroll_without_drag_check_idle,
556 correct_scroll (ModestMsgEditWindow *w)
558 ModestMsgEditWindowPrivate *priv;
560 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
561 if (gtk_grab_get_current () == priv->msg_body) {
562 if (priv->scroll_drag_timeout_id == 0) {
563 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
565 (GSourceFunc) scroll_drag_timeout,
572 correct_scroll_without_drag_check (w, TRUE);
576 text_buffer_end_user_action (GtkTextBuffer *buffer,
577 ModestMsgEditWindow *userdata)
580 correct_scroll (userdata);
584 text_buffer_mark_set (GtkTextBuffer *buffer,
587 ModestMsgEditWindow *userdata)
589 gtk_text_buffer_begin_user_action (buffer);
590 gtk_text_buffer_end_user_action (buffer);
594 cut_clipboard_check (GtkTextView *text_view,
597 GtkTextBuffer *buffer;
599 buffer = gtk_text_view_get_buffer (text_view);
600 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
601 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
606 copy_clipboard_check (GtkTextView *text_view,
609 GtkTextBuffer *buffer;
611 buffer = gtk_text_view_get_buffer (text_view);
612 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
613 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
618 attachment_deleted (ModestAttachmentsView *attachments_view,
621 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
626 connect_signals (ModestMsgEditWindow *obj)
628 ModestMsgEditWindowPrivate *priv;
630 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
632 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
633 G_CALLBACK (text_buffer_refresh_attributes), obj);
634 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
635 G_CALLBACK (text_buffer_can_undo), obj);
636 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
637 G_CALLBACK (text_buffer_can_redo), obj);
638 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
639 G_CALLBACK (body_changed), obj);
640 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
641 G_CALLBACK (body_changed), obj);
642 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
643 G_CALLBACK (text_buffer_end_user_action), obj);
644 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
645 G_CALLBACK (text_buffer_mark_set), obj);
646 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
647 G_CALLBACK (text_buffer_apply_tag), obj);
648 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
649 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
650 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
651 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
652 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
653 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
655 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
656 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
657 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
658 G_CALLBACK (from_field_changed), obj);
660 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
661 G_CALLBACK (msg_body_focus), obj);
662 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
663 G_CALLBACK (msg_body_focus), obj);
664 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
665 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
666 "changed", G_CALLBACK (recpt_field_changed), obj);
667 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
668 "changed", G_CALLBACK (recpt_field_changed), obj);
669 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
670 "changed", G_CALLBACK (recpt_field_changed), obj);
671 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
672 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
673 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
675 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
676 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
678 priv->clipboard_change_handler_id =
679 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
680 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
681 priv->default_clipboard_change_handler_id =
682 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
683 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
685 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
686 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
687 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
691 init_wp_text_view_style ()
693 static gboolean initialized = FALSE;
696 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
702 init_window (ModestMsgEditWindow *obj)
704 GtkWidget *to_caption, *subject_caption;
705 GtkWidget *main_vbox;
706 GtkWidget *add_attachment_align;
707 ModestMsgEditWindowPrivate *priv;
708 GtkActionGroup *action_group;
709 ModestWindowPrivate *parent_priv;
710 GdkPixbuf *window_icon = NULL;
711 GError *error = NULL;
713 GtkSizeGroup *title_size_group;
714 GtkSizeGroup *value_size_group;
715 GtkWidget *attachment_icon;
716 GtkWidget *window_box;
717 GtkWidget *window_align;
718 #if (GTK_MINOR_VERSION >= 10)
719 GdkAtom deserialize_type;
722 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
723 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
725 parent_priv->ui_manager = gtk_ui_manager_new();
726 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
727 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
729 /* Add common actions */
730 gtk_action_group_add_actions (action_group,
731 modest_msg_edit_action_entries,
732 G_N_ELEMENTS (modest_msg_edit_action_entries),
734 gtk_action_group_add_actions (action_group,
735 hildon2_msg_edit_action_entries,
736 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
738 gtk_action_group_add_toggle_actions (action_group,
739 modest_msg_edit_toggle_action_entries,
740 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
742 gtk_action_group_add_radio_actions (action_group,
743 modest_msg_edit_alignment_radio_action_entries,
744 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
746 G_CALLBACK (modest_ui_actions_on_change_justify),
748 gtk_action_group_add_radio_actions (action_group,
749 modest_msg_edit_priority_action_entries,
750 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
752 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
754 gtk_action_group_add_radio_actions (action_group,
755 modest_msg_edit_file_format_action_entries,
756 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
757 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
758 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
760 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
761 g_object_unref (action_group);
763 /* Load the UI definition */
764 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
767 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
768 g_clear_error (&error);
771 /* Add accelerators */
772 gtk_window_add_accel_group (GTK_WINDOW (obj),
773 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
775 parent_priv->menubar = NULL;
777 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
778 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
780 /* Note: This ModestPairList* must exist for as long as the picker
781 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
782 * so it can't know how to manage its memory. */
783 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
784 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
786 modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group,
787 _("mail_va_from"), priv->from_field);
789 priv->to_field = modest_recpt_editor_new ();
790 priv->cc_field = modest_recpt_editor_new ();
791 priv->bcc_field = modest_recpt_editor_new ();
792 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
793 priv->priority_icon = gtk_image_new ();
794 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
795 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
796 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
797 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
798 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
799 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
800 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
801 priv->add_attachment_button = hildon_button_new (MODEST_EDITABLE_SIZE, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
802 gtk_widget_set_size_request (priv->add_attachment_button, ATTACHMENT_BUTTON_WIDTH, -1);
803 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
804 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
805 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
806 hildon_button_set_image (HILDON_BUTTON (priv->add_attachment_button), attachment_icon);
807 add_attachment_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
808 gtk_alignment_set_padding (GTK_ALIGNMENT (add_attachment_align), 0, 0, MODEST_MARGIN_DEFAULT, 0);
809 gtk_container_add (GTK_CONTAINER (add_attachment_align), priv->add_attachment_button);
810 gtk_box_pack_start (GTK_BOX (priv->subject_box), add_attachment_align, FALSE, FALSE, 0);
811 priv->attachments_view = modest_attachments_view_new (NULL);
812 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
813 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
815 priv->header_box = gtk_vbox_new (FALSE, 0);
817 to_caption = modest_maemo_utils_create_captioned_with_size_type
818 (title_size_group, value_size_group,
819 _("mail_va_to"), FALSE, priv->to_field,
820 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
821 priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type
822 (title_size_group, value_size_group,
823 _("mail_va_cc"), FALSE, priv->cc_field,
824 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
825 priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
826 (title_size_group, value_size_group,
827 _("mail_va_hotfix1"), FALSE, priv->bcc_field,
828 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
829 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
830 _("mail_va_subject"), FALSE, priv->subject_box);
831 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
832 _("mail_va_attachment"),
834 priv->attachments_view,
835 HILDON_SIZE_AUTO_WIDTH |
836 HILDON_SIZE_AUTO_HEIGHT);
837 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
838 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
839 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
840 g_object_unref (title_size_group);
841 g_object_unref (value_size_group);
843 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
844 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
845 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
846 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
847 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
848 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
849 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
851 init_wp_text_view_style ();
853 priv->msg_body = modest_wp_text_view_new ();
856 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
857 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
858 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
859 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
860 #if (GTK_MINOR_VERSION >= 10)
861 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
862 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
864 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
865 deserialize_type, TRUE);
867 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
869 priv->find_toolbar = hildon_find_toolbar_new (NULL);
870 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
872 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
874 priv->pannable = hildon_pannable_area_new ();
876 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
877 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
878 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
880 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
881 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
882 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
884 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
885 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox),
886 hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable)));
887 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
889 window_box = gtk_vbox_new (FALSE, 0);
890 gtk_container_add (GTK_CONTAINER(obj), window_box);
892 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
894 /* Set window icon */
895 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
897 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
898 g_object_unref (window_icon);
903 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
905 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
907 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
908 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
909 priv->clipboard_change_handler_id))
910 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
911 priv->clipboard_change_handler_id);
912 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
913 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
914 priv->default_clipboard_change_handler_id))
915 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
916 priv->default_clipboard_change_handler_id);
918 if (priv->account_removed_handler_id &&
919 g_signal_handler_is_connected (modest_runtime_get_account_store (),
920 priv->account_removed_handler_id))
921 g_signal_handler_disconnect(modest_runtime_get_account_store (),
922 priv->account_removed_handler_id);
926 modest_msg_edit_window_finalize (GObject *obj)
928 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
930 /* Sanity check: shouldn't be needed, the window mgr should
931 call this function before */
932 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
934 if (priv->font_dialog != NULL) {
935 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
938 if (priv->clipboard_text != NULL) {
939 g_free (priv->clipboard_text);
940 priv->clipboard_text = NULL;
943 if (priv->draft_msg != NULL) {
944 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
945 if (TNY_IS_HEADER (header)) {
946 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
947 modest_window_mgr_unregister_header (mgr, header);
949 g_object_unref (priv->draft_msg);
950 priv->draft_msg = NULL;
952 if (priv->outbox_msg != NULL) {
953 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
954 if (TNY_IS_HEADER (header)) {
955 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
956 modest_window_mgr_unregister_header (mgr, header);
958 g_object_unref (priv->outbox_msg);
959 priv->outbox_msg = NULL;
961 if (priv->correct_scroll_idle > 0) {
962 g_source_remove (priv->correct_scroll_idle);
963 priv->correct_scroll_idle = 0;
965 if (priv->scroll_drag_timeout_id > 0) {
966 g_source_remove (priv->scroll_drag_timeout_id);
967 priv->scroll_drag_timeout_id = 0;
969 if (priv->clipboard_owner_idle > 0) {
970 g_source_remove (priv->clipboard_owner_idle);
971 priv->clipboard_owner_idle = 0;
973 if (priv->original_account_name)
974 g_free (priv->original_account_name);
975 g_free (priv->msg_uid);
976 g_free (priv->last_search);
977 g_object_unref (priv->faces_model);
978 g_object_unref (priv->sizes_model);
979 g_object_unref (priv->attachments);
980 g_object_unref (priv->images);
982 /* This had to stay alive for as long as the picker that used it: */
983 modest_pair_list_free (priv->from_field_protos);
985 G_OBJECT_CLASS(parent_class)->finalize (obj);
989 pixbuf_size_prepared (GdkPixbufLoader *loader,
992 ModestMsgEditWindow *self)
994 gint new_height, new_width;
1001 if (width > IMAGE_MAX_WIDTH) {
1002 new_height = height * IMAGE_MAX_WIDTH / width;
1003 new_width = IMAGE_MAX_WIDTH;
1006 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1010 pixbuf_from_stream (TnyStream *stream,
1011 const gchar *mime_type,
1012 guint64 *stream_size,
1013 ModestMsgEditWindow *self)
1015 GdkPixbufLoader *loader;
1018 GError *error = NULL;
1022 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1024 if (loader == NULL) {
1029 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1031 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1033 tny_stream_reset (TNY_STREAM (stream));
1034 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1035 unsigned char read_buffer[128];
1037 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1039 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1042 /* Allow some UI responsiveness */
1043 while (gtk_events_pending ())
1044 gtk_main_iteration ();
1046 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1048 gdk_pixbuf_loader_close (loader, &error);
1051 g_error_free (error);
1052 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1054 g_object_ref (pixbuf);
1055 g_object_unref (loader);
1060 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1061 GdkPixbuf *new_pixbuf;
1063 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1064 gdk_pixbuf_get_width (pixbuf);
1065 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1066 g_object_unref (pixbuf);
1067 pixbuf = new_pixbuf;
1071 *stream_size = size;
1077 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1079 ModestMsgEditWindowPrivate *priv;
1082 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1084 g_object_ref (self);
1085 for (iter = tny_list_create_iterator (attachments);
1086 !tny_iterator_is_done (iter);
1087 tny_iterator_next (iter)) {
1088 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1089 const gchar *cid = tny_mime_part_get_content_id (part);
1090 const gchar *mime_type = tny_mime_part_get_content_type (part);
1091 if ((cid != NULL)&&(mime_type != NULL)) {
1092 guint64 stream_size;
1093 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1094 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1097 g_object_unref (stream);
1099 if (pixbuf != NULL) {
1100 priv->images_count ++;
1101 priv->images_size += stream_size;
1102 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1103 g_object_unref (pixbuf);
1106 g_object_unref (part);
1108 g_object_unref (iter);
1109 g_object_unref (self);
1113 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1115 TnyMimePart *parent = NULL;
1116 const gchar *content_type = NULL;
1117 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1119 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1121 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1122 parent = g_object_ref (msg);
1123 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1124 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1127 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1128 iter = tny_list_create_iterator (parts);
1129 while (!tny_iterator_is_done (iter)) {
1131 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1132 content_type = tny_mime_part_get_content_type (part);
1133 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1137 g_object_unref (part);
1139 tny_iterator_next (iter);
1141 g_object_unref (iter);
1142 g_object_unref (parts);
1145 if (parent != NULL) {
1146 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1149 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1150 iter = tny_list_create_iterator (parts);
1151 while (!tny_iterator_is_done (iter)) {
1153 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1154 content_type = tny_mime_part_get_content_type (part);
1155 if (content_type && g_str_has_prefix (content_type, "image/")) {
1156 tny_list_prepend (priv->images, (GObject *) part);
1158 g_object_unref (part);
1159 tny_iterator_next (iter);
1161 g_object_unref (iter);
1162 g_object_unref (parts);
1163 g_object_unref (parent);
1168 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1171 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1173 for (iter = tny_list_create_iterator (attachments) ;
1174 !tny_iterator_is_done (iter);
1175 tny_iterator_next (iter)) {
1176 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1177 const gchar *cid = tny_mime_part_get_content_id (part);
1179 char *invalid = NULL;
1180 gint int_cid = strtol (cid, &invalid, 10);
1181 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1182 priv->next_cid = int_cid + 1;
1185 g_object_unref (part);
1187 g_object_unref (iter);
1191 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1194 gchar *to, *cc, *bcc, *subject;
1196 ModestMsgEditWindowPrivate *priv;
1197 ModestWindowPrivate *parent_priv;
1199 TnyHeaderFlags priority_flags;
1200 TnyFolder *msg_folder;
1201 gboolean is_html = FALSE;
1202 gboolean field_view_set;
1204 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1205 g_return_if_fail (TNY_IS_MSG (msg));
1207 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1208 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1210 header = tny_msg_get_header (msg);
1211 to = tny_header_dup_to (header);
1212 cc = tny_header_dup_cc (header);
1213 bcc = tny_header_dup_bcc (header);
1214 subject = tny_header_dup_subject (header);
1215 priority_flags = tny_header_get_priority (header);
1218 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1220 field_view_set = TRUE;
1222 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1223 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1224 gtk_widget_show (priv->cc_caption);
1225 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1226 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1227 gtk_widget_hide (priv->cc_caption);
1228 field_view_set = FALSE;
1230 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1232 field_view_set = TRUE;
1234 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1235 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1236 gtk_widget_show (priv->bcc_caption);
1237 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1238 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1239 gtk_widget_hide (priv->bcc_caption);
1240 field_view_set = FALSE;
1242 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1246 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1247 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1250 update_window_title (self);
1252 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1253 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1255 if ((body == NULL)||(body[0] == '\0')) {
1257 body = modest_text_utils_convert_to_html ("");
1260 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1261 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1264 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1267 /* Add attachments to the view */
1268 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1269 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1270 if (tny_list_get_length (priv->attachments) == 0) {
1271 gtk_widget_hide (priv->attachments_caption);
1273 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1274 gtk_widget_show_all (priv->attachments_caption);
1276 get_related_images (self, msg);
1277 update_next_cid (self, priv->attachments);
1278 update_next_cid (self, priv->images);
1279 replace_with_images (self, priv->images);
1281 if (preserve_is_rich && !is_html) {
1282 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1283 /* Get the default format required from configuration */
1284 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1285 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1288 /* Set the default focus depending on having already a To: field or not */
1289 if ((!to)||(*to == '\0')) {
1290 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1292 gtk_widget_grab_focus (priv->msg_body);
1295 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1297 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1298 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1300 modest_msg_edit_window_set_modified (self, FALSE);
1302 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1303 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1304 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1305 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1307 if (priv->msg_uid) {
1308 g_free (priv->msg_uid);
1309 priv->msg_uid = NULL;
1312 /* we should set a reference to the incoming message if it is a draft */
1313 msg_folder = tny_msg_get_folder (msg);
1315 if (modest_tny_folder_is_local_folder (msg_folder)) {
1316 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1317 if (type == TNY_FOLDER_TYPE_INVALID)
1318 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1320 if (type == TNY_FOLDER_TYPE_DRAFTS)
1321 priv->draft_msg = g_object_ref(msg);
1322 if (type == TNY_FOLDER_TYPE_OUTBOX)
1323 priv->outbox_msg = g_object_ref(msg);
1324 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1326 g_object_unref (msg_folder);
1337 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1339 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1340 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1341 GtkWidget *placeholder;
1342 GtkWidget *tool_item;
1347 GtkWidget *sizes_menu;
1348 GtkWidget *fonts_menu;
1354 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1355 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1356 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1357 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1359 /* Font color placeholder */
1360 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1361 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1364 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1365 priv->font_color_button = hildon_color_button_new ();
1366 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1367 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1368 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1369 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1370 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1371 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1372 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1373 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1375 G_CALLBACK (modest_msg_edit_window_color_button_change),
1378 /* Font size and face placeholder */
1379 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1380 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1382 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1383 priv->size_tool_button_label = gtk_label_new (NULL);
1384 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1385 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1386 size_text, "</span>", NULL);
1387 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1388 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1390 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1391 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1392 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1393 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1394 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1395 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1396 gtk_widget_set_sensitive (arrow, FALSE);
1397 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1398 sizes_menu = gtk_menu_new ();
1399 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1400 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1403 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1404 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1406 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1410 if (wp_font_size[size_index] == 12)
1411 priv->current_size_index = size_index;
1415 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1416 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1417 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1418 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1419 priv->font_size_toolitem = tool_item;
1422 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1423 priv->font_tool_button_label = gtk_label_new (NULL);
1424 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1425 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1427 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1428 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1429 fonts_menu = gtk_menu_new ();
1430 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1431 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1434 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1436 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1437 0, wp_get_font_name (font_index),
1440 if (font_index == DEFAULT_FONT)
1441 priv->current_face_index = font_index;
1443 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1444 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1445 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1446 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1447 priv->font_face_toolitem = tool_item;
1449 /* Set expand and homogeneous for remaining items */
1450 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1451 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1452 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1453 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1454 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1455 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1456 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1457 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1458 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1460 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1461 will not show the tool items added to the placeholders) */
1462 gtk_widget_show_all (parent_priv->toolbar);
1464 /* Set the no show all *after* showing all items. We do not
1465 want the toolbar to be shown with a show all because it
1466 could go agains the gconf setting regarding showing or not
1467 the toolbar of the editor window */
1468 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1474 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1477 ModestWindowPrivate *parent_priv;
1478 ModestMsgEditWindowPrivate *priv;
1479 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1480 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1481 ModestWindowMgr *mgr = NULL;
1483 g_return_val_if_fail (msg, NULL);
1484 g_return_val_if_fail (account_name, NULL);
1486 mgr = modest_runtime_get_window_mgr ();
1488 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1490 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1491 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1493 /* Menubar. Update the state of some toggles */
1494 priv->from_field_protos = get_transports ();
1495 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1496 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1497 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1498 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1500 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1501 hildon_touch_selector_get_current_text
1502 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1503 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1504 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1507 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1509 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1511 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1513 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1515 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1516 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1517 /* Add common dimming rules */
1518 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1519 modest_msg_edit_window_toolbar_dimming_entries,
1520 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1521 MODEST_WINDOW (obj));
1522 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1523 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1524 MODEST_WINDOW (obj));
1525 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1526 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1527 MODEST_WINDOW (obj));
1528 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1529 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1530 MODEST_WINDOW (obj));
1531 /* Insert dimming rules group for this window */
1532 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1533 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1535 /* Setup app menu */
1536 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1538 /* Checks the dimming rules */
1539 g_object_unref (toolbar_rules_group);
1540 g_object_unref (clipboard_rules_group);
1541 gtk_widget_hide (priv->priority_icon);
1542 gtk_widget_queue_resize (priv->subject_box);
1543 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1545 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1547 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1548 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1549 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1550 priv->update_caption_visibility = TRUE;
1552 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1554 /* Track account-removed signal, this window should be closed
1555 in the case we're creating a mail associated to the account
1557 priv->account_removed_handler_id =
1558 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1560 G_CALLBACK(on_account_removed),
1563 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1565 return (ModestWindow*) obj;
1569 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1571 GString **string_buffer = (GString **) user_data;
1573 *string_buffer = g_string_append (*string_buffer, buffer);
1579 * @result: A new string which should be freed with g_free().
1582 get_formatted_data (ModestMsgEditWindow *edit_window)
1584 ModestMsgEditWindowPrivate *priv;
1585 GString *string_buffer = g_string_new ("");
1587 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1589 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1591 modest_text_utils_hyperlinkify (string_buffer);
1593 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1595 return g_string_free (string_buffer, FALSE);
1600 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1603 const gchar *account_name;
1604 ModestMsgEditWindowPrivate *priv;
1605 TnyIterator *att_iter;
1607 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1609 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1611 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1612 g_return_val_if_fail (account_name, NULL);
1615 /* don't free these (except from) */
1616 data = g_slice_new0 (MsgData);
1617 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1619 data->account_name = g_strdup (account_name);
1620 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1621 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1622 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1623 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1624 if (priv->draft_msg) {
1625 data->draft_msg = g_object_ref (priv->draft_msg);
1626 } else if (priv->outbox_msg) {
1627 data->draft_msg = g_object_ref (priv->outbox_msg);
1629 data->draft_msg = NULL;
1632 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1634 gtk_text_buffer_get_bounds (buf, &b, &e);
1635 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1637 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1638 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1640 data->html_body = NULL;
1642 /* deep-copy the data */
1643 att_iter = tny_list_create_iterator (priv->attachments);
1644 data->attachments = NULL;
1645 while (!tny_iterator_is_done (att_iter)) {
1646 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1647 if (!(TNY_IS_MIME_PART(part))) {
1648 g_warning ("strange data in attachment list");
1649 g_object_unref (part);
1650 tny_iterator_next (att_iter);
1653 data->attachments = g_list_append (data->attachments,
1655 tny_iterator_next (att_iter);
1657 g_object_unref (att_iter);
1659 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1660 att_iter = tny_list_create_iterator (priv->images);
1661 data->images = NULL;
1662 while (!tny_iterator_is_done (att_iter)) {
1663 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1665 if (!(TNY_IS_MIME_PART(part))) {
1666 g_warning ("strange data in attachment list");
1667 g_object_unref (part);
1668 tny_iterator_next (att_iter);
1671 cid = tny_mime_part_get_content_id (part);
1673 gchar *image_tag_id;
1674 GtkTextTag *image_tag;
1676 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1677 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1678 g_free (image_tag_id);
1680 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1682 ((gtk_text_iter_has_tag (&iter, image_tag))||
1683 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1684 data->images = g_list_append (data->images,
1685 g_object_ref (part));
1687 g_object_unref (part);
1688 tny_iterator_next (att_iter);
1690 g_object_unref (att_iter);
1692 data->priority_flags = priv->priority_flags;
1699 unref_gobject (GObject *obj, gpointer data)
1701 if (!G_IS_OBJECT(obj))
1703 g_object_unref (obj);
1707 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1710 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1718 g_free (data->from);
1719 g_free (data->subject);
1720 g_free (data->plain_body);
1721 g_free (data->html_body);
1722 g_free (data->account_name);
1724 if (data->draft_msg != NULL) {
1725 g_object_unref (data->draft_msg);
1726 data->draft_msg = NULL;
1729 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1730 g_list_free (data->attachments);
1731 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1732 g_list_free (data->images);
1734 g_slice_free (MsgData, data);
1738 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1740 guint64 *parts_size)
1742 ModestMsgEditWindowPrivate *priv;
1744 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1746 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1748 /* TODO: add images */
1749 *parts_size += priv->images_size;
1750 *parts_count += priv->images_count;
1755 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1758 ModestMsgEditWindowPrivate *priv = NULL;
1759 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1761 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1763 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1765 return MODEST_MSG_EDIT_FORMAT_HTML;
1767 return MODEST_MSG_EDIT_FORMAT_TEXT;
1771 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1772 ModestMsgEditFormat format)
1774 ModestMsgEditWindowPrivate *priv;
1776 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1777 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1780 case MODEST_MSG_EDIT_FORMAT_HTML:
1781 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1783 case MODEST_MSG_EDIT_FORMAT_TEXT:
1784 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1787 g_return_if_reached ();
1791 ModestMsgEditFormatState *
1792 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1794 ModestMsgEditFormatState *format_state = NULL;
1795 ModestMsgEditWindowPrivate *priv;
1796 WPTextBufferFormat *buffer_format;
1798 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1800 buffer_format = g_new0 (WPTextBufferFormat, 1);
1801 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1803 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1805 format_state = g_new0 (ModestMsgEditFormatState, 1);
1806 format_state->bold = buffer_format->bold&0x1;
1807 format_state->italics = buffer_format->italic&0x1;
1808 format_state->bullet = buffer_format->bullet&0x1;
1809 format_state->color = buffer_format->color;
1810 format_state->font_size = buffer_format->font_size;
1811 format_state->font_family = wp_get_font_name (buffer_format->font);
1812 format_state->justification = buffer_format->justification;
1813 g_free (buffer_format);
1815 return format_state;
1820 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1821 const ModestMsgEditFormatState *format_state)
1823 ModestMsgEditWindowPrivate *priv;
1824 WPTextBufferFormat *buffer_format;
1825 WPTextBufferFormat *current_format;
1827 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1828 g_return_if_fail (format_state != NULL);
1830 buffer_format = g_new0 (WPTextBufferFormat, 1);
1831 current_format = g_new0 (WPTextBufferFormat, 1);
1833 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1834 gtk_widget_grab_focus (priv->msg_body);
1835 buffer_format->bold = (format_state->bold != FALSE);
1836 buffer_format->italic = (format_state->italics != FALSE);
1837 buffer_format->color = format_state->color;
1838 buffer_format->font_size = format_state->font_size;
1839 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1840 buffer_format->justification = format_state->justification;
1841 buffer_format->bullet = format_state->bullet;
1843 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1845 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1846 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1847 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1848 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1849 buffer_format->cs.font = (buffer_format->font != current_format->font);
1850 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1851 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1853 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1854 if (buffer_format->cs.bold) {
1855 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1856 GINT_TO_POINTER (buffer_format->bold&0x1));
1858 if (buffer_format->cs.italic) {
1859 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1860 GINT_TO_POINTER (buffer_format->italic&0x1));
1862 if (buffer_format->cs.color) {
1863 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1864 GINT_TO_POINTER (&(buffer_format->color)));
1866 if (buffer_format->cs.font_size) {
1867 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1868 GINT_TO_POINTER (buffer_format->font_size));
1870 if (buffer_format->cs.justification) {
1871 switch (buffer_format->justification) {
1872 case GTK_JUSTIFY_LEFT:
1873 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1874 GINT_TO_POINTER(TRUE));
1876 case GTK_JUSTIFY_CENTER:
1877 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1878 GINT_TO_POINTER(TRUE));
1880 case GTK_JUSTIFY_RIGHT:
1881 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1882 GINT_TO_POINTER(TRUE));
1889 if (buffer_format->cs.font) {
1890 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1891 GINT_TO_POINTER (buffer_format->font));
1893 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1894 if (buffer_format->cs.bullet) {
1895 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1896 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1898 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1900 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1902 g_free (buffer_format);
1903 g_free (current_format);
1905 /* Check dimming rules */
1906 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1907 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1911 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1913 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1915 ModestWindowPrivate *parent_priv;
1916 ModestMsgEditWindowPrivate *priv;
1918 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1919 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1921 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1922 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1923 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1924 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1926 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1927 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1928 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1931 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1933 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1934 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1936 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1937 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1939 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1940 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1943 switch (buffer_format->justification)
1945 case GTK_JUSTIFY_LEFT:
1946 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1948 case GTK_JUSTIFY_CENTER:
1949 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1951 case GTK_JUSTIFY_RIGHT:
1952 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1959 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1961 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1962 G_CALLBACK (modest_msg_edit_window_color_button_change),
1964 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1965 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1966 G_CALLBACK (modest_msg_edit_window_color_button_change),
1969 if (priv->current_size_index != buffer_format->font_size) {
1973 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1974 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1978 priv->current_size_index = buffer_format->font_size;
1980 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
1981 markup = g_strconcat ("<span font_family='Sans'>",
1982 size_text, "</span>", NULL);
1984 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1988 gtk_tree_path_free (path);
1991 if (priv->current_face_index != buffer_format->font) {
1995 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
1996 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2000 priv->current_face_index = buffer_format->font;
2001 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2002 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2003 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2010 g_free (buffer_format);
2014 #ifdef MODEST_HILDON_VERSION_0
2016 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2019 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2020 ModestMsgEditWindowPrivate *priv;
2021 GtkWidget *dialog = NULL;
2023 GdkColor *new_color = NULL;
2025 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2026 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2028 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2029 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2030 g_free (buffer_format);
2032 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2033 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2034 if (new_color != NULL) {
2035 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2036 (gpointer) new_color);
2039 gtk_widget_destroy (dialog);
2044 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2047 ModestMsgEditWindowPrivate *priv;
2048 GtkWidget *dialog = NULL;
2050 GdkColor *old_color = NULL;
2051 const GdkColor *new_color = NULL;
2053 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2054 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2056 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2057 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2059 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2060 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2061 if (new_color != NULL)
2062 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2064 gtk_widget_destroy (dialog);
2070 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2073 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2074 ModestMsgEditWindowPrivate *priv;
2075 GtkWidget *dialog = NULL;
2077 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2078 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2080 dialog = hildon_color_chooser_new ();
2081 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2082 g_free (buffer_format);
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_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2090 gtk_widget_destroy (dialog);
2095 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2098 ModestMsgEditWindowPrivate *priv;
2099 GtkWidget *dialog = NULL;
2100 GdkColor *old_color = NULL;
2102 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2103 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2105 dialog = hildon_color_chooser_new ();
2106 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2108 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2110 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2111 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2113 gtk_widget_destroy (dialog);
2116 #endif /*!MODEST_HILDON_VERSION_0*/
2121 create_stream_for_uri (const gchar* uri)
2126 TnyStream *result = NULL;
2128 GnomeVFSHandle *handle = NULL;
2129 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2130 if (test == GNOME_VFS_OK) {
2131 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2132 /* Streams over OBEX (Bluetooth) are not seekable but
2133 * we expect them to be (we might need to read them
2134 * several times). So if this is a Bluetooth URI just
2135 * read the whole file into memory (this is not a fast
2136 * protocol so we can assume that these files are not
2137 * going to be very big) */
2138 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2139 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2140 TnyStream *memstream = tny_camel_mem_stream_new ();
2141 tny_stream_write_to_stream (vfssstream, memstream);
2142 g_object_unref (vfssstream);
2145 result = vfssstream;
2153 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2156 ModestMsgEditWindowPrivate *priv;
2157 GtkWidget *dialog = NULL;
2159 GSList *uris = NULL;
2160 GSList *uri_node = NULL;
2162 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2164 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2165 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2166 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2168 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2170 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2171 GTK_WINDOW (dialog), GTK_WINDOW (window));
2173 response = gtk_dialog_run (GTK_DIALOG (dialog));
2175 case GTK_RESPONSE_OK:
2176 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2181 gtk_widget_destroy (dialog);
2183 g_object_ref (window);
2184 /* The operation could take some time so allow the dialog to be closed */
2185 while (gtk_events_pending ())
2186 gtk_main_iteration ();
2188 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2190 GnomeVFSHandle *handle = NULL;
2191 GnomeVFSResult result;
2192 GtkTextIter position;
2193 GtkTextMark *insert_mark;
2195 uri = (const gchar *) uri_node->data;
2196 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2197 if (result == GNOME_VFS_OK) {
2199 GnomeVFSFileInfo *info;
2200 gchar *filename, *basename, *escaped_filename;
2201 TnyMimePart *mime_part;
2203 const gchar *mime_type = NULL;
2204 GnomeVFSURI *vfs_uri;
2205 guint64 stream_size;
2207 gnome_vfs_close (handle);
2208 vfs_uri = gnome_vfs_uri_new (uri);
2210 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2211 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2212 g_free (escaped_filename);
2213 gnome_vfs_uri_unref (vfs_uri);
2214 info = gnome_vfs_file_info_new ();
2216 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2217 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2219 mime_type = gnome_vfs_file_info_get_mime_type (info);
2221 mime_part = tny_platform_factory_new_mime_part
2222 (modest_runtime_get_platform_factory ());
2224 TnyStream *stream = create_stream_for_uri (uri);
2226 if (stream == NULL) {
2228 modest_platform_information_banner (NULL, NULL,
2229 _FM("sfil_ib_opening_not_allowed"));
2231 g_object_unref (mime_part);
2232 gnome_vfs_file_info_unref (info);
2236 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2238 content_id = g_strdup_printf ("%d", priv->next_cid);
2239 tny_mime_part_set_content_id (mime_part, content_id);
2240 g_free (content_id);
2243 basename = g_path_get_basename (filename);
2244 tny_mime_part_set_filename (mime_part, basename);
2247 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2249 if (pixbuf != NULL) {
2250 priv->images_size += stream_size;
2251 priv->images_count ++;
2252 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2253 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2254 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2255 tny_mime_part_get_content_id (mime_part), pixbuf);
2256 g_object_unref (pixbuf);
2258 tny_list_prepend (priv->images, (GObject *) mime_part);
2259 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2261 modest_platform_information_banner (NULL, NULL,
2262 _("mail_ib_file_operation_failed"));
2266 g_object_unref (mime_part);
2267 gnome_vfs_file_info_unref (info);
2271 g_object_unref (window);
2275 on_attach_file_response (GtkDialog *dialog,
2279 GSList *uris = NULL;
2281 GnomeVFSFileSize total_size, allowed_size;
2282 ModestMsgEditWindow *window;
2283 ModestMsgEditWindowPrivate *priv;
2288 case GTK_RESPONSE_OK:
2289 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2295 window = MODEST_MSG_EDIT_WINDOW (user_data);
2296 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2298 /* allowed size is the maximum size - what's already there */
2299 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2300 &att_num, &att_size);
2301 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2304 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2306 const gchar *uri = (const gchar *) uri_node->data;
2309 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2311 if (total_size > allowed_size) {
2312 g_warning ("%s: total size: %u",
2313 __FUNCTION__, (unsigned int)total_size);
2316 allowed_size -= total_size;
2318 g_slist_foreach (uris, (GFunc) g_free, NULL);
2319 g_slist_free (uris);
2321 gtk_widget_destroy (GTK_WIDGET (dialog));
2325 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2327 GtkWidget *dialog = NULL;
2328 ModestMsgEditWindowPrivate *priv;
2330 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2332 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2334 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2337 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2338 GTK_FILE_CHOOSER_ACTION_OPEN);
2339 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2340 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2341 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2342 GTK_WINDOW (dialog), GTK_WINDOW (window));
2344 /* Connect to response & show */
2345 g_signal_connect (dialog, "response",
2346 G_CALLBACK (on_attach_file_response), window);
2347 gtk_widget_show (dialog);
2352 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2354 GnomeVFSFileSize allowed_size)
2357 GnomeVFSHandle *handle = NULL;
2358 ModestMsgEditWindowPrivate *priv;
2359 GnomeVFSResult result;
2360 GnomeVFSFileSize size = 0;
2361 g_return_val_if_fail (window, 0);
2362 g_return_val_if_fail (uri, 0);
2364 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2366 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2367 if (result == GNOME_VFS_OK) {
2368 TnyMimePart *mime_part;
2370 const gchar *mime_type = NULL;
2372 gchar *escaped_filename;
2375 GnomeVFSFileInfo *info;
2376 GnomeVFSURI *vfs_uri;
2378 gnome_vfs_close (handle);
2379 vfs_uri = gnome_vfs_uri_new (uri);
2382 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2383 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2384 g_free (escaped_filename);
2385 gnome_vfs_uri_unref (vfs_uri);
2387 info = gnome_vfs_file_info_new ();
2389 if (gnome_vfs_get_file_info (uri,
2391 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2393 mime_type = gnome_vfs_file_info_get_mime_type (info);
2394 mime_part = tny_platform_factory_new_mime_part
2395 (modest_runtime_get_platform_factory ());
2397 /* try to get the attachment's size; this may fail for weird
2398 * file systems, like obex, upnp... */
2399 if (allowed_size != 0 &&
2400 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2402 if (size > allowed_size) {
2403 modest_platform_information_banner (NULL, NULL,
2404 _FM("sfil_ib_opening_not_allowed"));
2409 g_warning ("%s: could not get attachment size", __FUNCTION__);
2411 stream = create_stream_for_uri (uri);
2413 if (stream == NULL) {
2415 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2417 g_object_unref (mime_part);
2419 gnome_vfs_file_info_unref (info);
2423 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2424 g_object_unref (stream);
2426 content_id = g_strdup_printf ("%d", priv->next_cid);
2427 tny_mime_part_set_content_id (mime_part, content_id);
2428 g_free (content_id);
2431 basename = g_path_get_basename (filename);
2432 tny_mime_part_set_filename (mime_part, basename);
2435 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2436 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2438 info->size == 0, info->size);
2439 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2440 gtk_widget_show_all (priv->attachments_caption);
2441 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2443 g_object_unref (mime_part);
2444 gnome_vfs_file_info_unref (info);
2451 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2454 ModestMsgEditWindowPrivate *priv;
2457 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2458 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2460 if (att_list == NULL) {
2461 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2462 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2463 g_object_unref (att_list);
2468 g_object_ref (att_list);
2471 if (tny_list_get_length (att_list) == 0) {
2472 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2474 gboolean dialog_response;
2475 gchar *message = NULL;
2476 gchar *filename = NULL;
2478 if (tny_list_get_length (att_list) == 1) {
2480 iter = tny_list_create_iterator (att_list);
2481 part = (TnyMimePart *) tny_iterator_get_current (iter);
2482 g_object_unref (iter);
2483 if (TNY_IS_MSG (part)) {
2484 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2486 filename = tny_header_dup_subject (header);
2487 g_object_unref (header);
2489 if (filename == NULL) {
2490 filename = g_strdup (_("mail_va_no_subject"));
2493 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2495 g_object_unref (part);
2497 filename = g_strdup ("");
2499 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2500 "emev_nc_delete_attachments",
2501 tny_list_get_length (att_list)), filename);
2504 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2508 if (dialog_response != GTK_RESPONSE_OK) {
2509 g_object_unref (att_list);
2513 for (iter = tny_list_create_iterator (att_list);
2514 !tny_iterator_is_done (iter);
2515 tny_iterator_next (iter)) {
2516 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2517 const gchar *att_id;
2518 tny_list_remove (priv->attachments, (GObject *) mime_part);
2520 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2522 if (tny_list_get_length (priv->attachments) == 0)
2523 gtk_widget_hide (priv->attachments_caption);
2524 att_id = tny_mime_part_get_content_id (mime_part);
2526 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2528 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2529 g_object_unref (mime_part);
2531 g_object_unref (iter);
2534 g_object_unref (att_list);
2536 /* if the last attachment has been removed, focus the Subject: field */
2537 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2538 gtk_widget_grab_focus (priv->subject_field);
2542 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2545 ModestMsgEditWindowPrivate *priv;
2546 GdkColor *new_color;
2547 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2549 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2550 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2553 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2555 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2557 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2559 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2564 font_size_clicked (GtkToolButton *button,
2565 ModestMsgEditWindow *window)
2567 ModestMsgEditWindowPrivate *priv;
2568 GtkWidget *selector, *dialog;
2570 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2572 selector = hildon_touch_selector_new ();
2573 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2574 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2576 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2577 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2578 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2580 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2584 WPTextBufferFormat format;
2586 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2588 memset (&format, 0, sizeof (format));
2589 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2591 format.cs.font_size = TRUE;
2592 format.cs.text_position = TRUE;
2593 format.cs.font = TRUE;
2594 format.font_size = new_index;
2595 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2597 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2598 GINT_TO_POINTER (new_index)))
2599 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2601 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2602 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2603 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2604 size_text, "</span>", NULL);
2606 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2610 gtk_widget_destroy (dialog);
2612 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2617 font_face_clicked (GtkToolButton *button,
2618 ModestMsgEditWindow *window)
2620 ModestMsgEditWindowPrivate *priv;
2621 GtkWidget *selector, *dialog;
2622 GtkCellRenderer *renderer;
2624 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2626 selector = hildon_touch_selector_new ();
2627 renderer = gtk_cell_renderer_text_new ();
2628 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2629 renderer, "family", 0, "text", 0, NULL);
2630 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2632 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2633 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2634 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2636 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2637 gint new_font_index;
2641 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2642 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2643 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2647 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2649 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2650 GINT_TO_POINTER(new_font_index)))
2651 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2653 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2654 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2656 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2660 gtk_tree_path_free (path);
2663 gtk_widget_destroy (dialog);
2665 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2670 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2673 ModestMsgEditWindowPrivate *priv = NULL;
2674 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2676 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2677 if (!priv->update_caption_visibility)
2680 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2682 gtk_widget_show (priv->cc_caption);
2684 gtk_widget_hide (priv->cc_caption);
2686 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2690 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2693 ModestMsgEditWindowPrivate *priv = NULL;
2694 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2696 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2697 if (!priv->update_caption_visibility)
2700 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2702 gtk_widget_show (priv->bcc_caption);
2704 gtk_widget_hide (priv->bcc_caption);
2706 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2710 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2711 ModestRecptEditor *editor)
2713 ModestMsgEditWindowPrivate *priv;
2715 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2716 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2718 /* we check for low-mem; in that case, show a warning, and don't allow
2719 * for the addressbook
2721 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2724 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2726 if (editor == NULL) {
2727 GtkWidget *view_focus;
2728 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2730 /* This code should be kept in sync with ModestRecptEditor. The
2731 textview inside the recpt editor is the one that really gets the
2732 focus. As it's inside a scrolled window, and this one inside the
2733 hbox recpt editor inherits from, we'll need to go up in the
2734 hierarchy to know if the text view is part of the recpt editor
2735 or if it's a different text entry */
2737 if (gtk_widget_get_parent (view_focus)) {
2738 GtkWidget *first_parent;
2740 first_parent = gtk_widget_get_parent (view_focus);
2741 if (gtk_widget_get_parent (first_parent) &&
2742 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2743 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2748 editor = MODEST_RECPT_EDITOR (priv->to_field);
2752 modest_address_book_select_addresses (editor);
2757 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2759 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2761 modest_msg_edit_window_open_addressbook (window, NULL);
2765 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2766 gboolean show_toolbar)
2768 ModestWindowPrivate *parent_priv;
2770 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2771 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2773 /* We can not just use the code of
2774 modest_msg_edit_window_setup_toolbar because it has a
2775 mixture of both initialization and creation code. */
2777 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2779 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2783 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2784 TnyHeaderFlags priority_flags)
2786 ModestMsgEditWindowPrivate *priv;
2787 ModestWindowPrivate *parent_priv;
2789 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2791 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2792 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2794 if (priv->priority_flags != priority_flags) {
2795 GtkAction *priority_action = NULL;
2797 priv->priority_flags = priority_flags;
2799 switch (priority_flags) {
2800 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2801 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2802 MODEST_HEADER_ICON_HIGH,
2803 HILDON_ICON_SIZE_SMALL);
2804 gtk_widget_show (priv->priority_icon);
2805 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2806 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2808 case TNY_HEADER_FLAG_LOW_PRIORITY:
2809 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2810 MODEST_HEADER_ICON_LOW,
2811 HILDON_ICON_SIZE_SMALL);
2812 gtk_widget_show (priv->priority_icon);
2813 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2814 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2817 gtk_widget_hide (priv->priority_icon);
2818 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2819 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2822 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2823 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2825 gtk_widget_queue_resize (priv->subject_box);
2829 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2832 ModestMsgEditWindowPrivate *priv;
2833 ModestWindowPrivate *parent_priv;
2834 gint current_format;
2836 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2838 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2839 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2841 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2842 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2844 if (current_format != file_format) {
2845 switch (file_format) {
2846 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2847 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2848 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2850 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2854 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2855 response = gtk_dialog_run (GTK_DIALOG (dialog));
2856 gtk_widget_destroy (dialog);
2857 if (response == GTK_RESPONSE_OK) {
2858 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2860 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2861 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2866 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2867 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2868 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2873 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2876 ModestMsgEditWindowPrivate *priv;
2877 WPTextBufferFormat oldfmt, fmt;
2878 gint old_position = 0;
2882 GdkColor *color = NULL;
2883 gboolean bold, bold_set, italic, italic_set;
2884 gboolean underline, underline_set;
2885 gboolean strikethrough, strikethrough_set;
2886 gboolean position_set;
2887 gboolean font_size_set, font_set, color_set;
2890 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2891 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2893 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2894 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2895 GTK_WINDOW(dialog), GTK_WINDOW (window));
2897 /* First we get the currently selected font information */
2898 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2900 switch (oldfmt.text_position) {
2901 case TEXT_POSITION_NORMAL:
2904 case TEXT_POSITION_SUPERSCRIPT:
2912 g_object_set (G_OBJECT (dialog),
2913 "bold", oldfmt.bold != FALSE,
2914 "bold-set", !oldfmt.cs.bold,
2915 "underline", oldfmt.underline != FALSE,
2916 "underline-set", !oldfmt.cs.underline,
2917 "italic", oldfmt.italic != FALSE,
2918 "italic-set", !oldfmt.cs.italic,
2919 "strikethrough", oldfmt.strikethrough != FALSE,
2920 "strikethrough-set", !oldfmt.cs.strikethrough,
2921 "color", &oldfmt.color,
2922 "color-set", !oldfmt.cs.color,
2923 "size", wp_font_size[oldfmt.font_size],
2924 "size-set", !oldfmt.cs.font_size,
2925 "position", old_position,
2926 "position-set", !oldfmt.cs.text_position,
2927 "family", wp_get_font_name (oldfmt.font),
2928 "family-set", !oldfmt.cs.font,
2931 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2932 GTK_WINDOW (dialog), GTK_WINDOW (window));
2933 gtk_widget_show_all (dialog);
2934 priv->font_dialog = dialog;
2935 response = gtk_dialog_run (GTK_DIALOG (dialog));
2936 priv->font_dialog = NULL;
2937 if (response == GTK_RESPONSE_OK) {
2939 g_object_get( dialog,
2941 "bold-set", &bold_set,
2942 "underline", &underline,
2943 "underline-set", &underline_set,
2945 "italic-set", &italic_set,
2946 "strikethrough", &strikethrough,
2947 "strikethrough-set", &strikethrough_set,
2949 "color-set", &color_set,
2951 "size-set", &font_size_set,
2952 "family", &font_name,
2953 "family-set", &font_set,
2954 "position", &position,
2955 "position-set", &position_set,
2960 if (response == GTK_RESPONSE_OK) {
2961 memset(&fmt, 0, sizeof(fmt));
2967 fmt.italic = italic;
2968 fmt.cs.italic = TRUE;
2970 if (underline_set) {
2971 fmt.underline = underline;
2972 fmt.cs.underline = TRUE;
2974 if (strikethrough_set) {
2975 fmt.strikethrough = strikethrough;
2976 fmt.cs.strikethrough = TRUE;
2981 ? TEXT_POSITION_NORMAL
2982 : ( ( position == 1 )
2983 ? TEXT_POSITION_SUPERSCRIPT
2984 : TEXT_POSITION_SUBSCRIPT );
2985 fmt.cs.text_position = TRUE;
2986 fmt.font_size = oldfmt.font_size;
2990 fmt.cs.color = TRUE;
2993 fmt.font = wp_get_font_index(font_name,
2998 if (font_size_set) {
2999 fmt.cs.font_size = TRUE;
3000 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3002 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3003 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3005 gtk_widget_destroy (dialog);
3007 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3011 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3013 ModestMsgEditWindowPrivate *priv;
3015 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3016 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3018 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3020 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3021 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3025 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3027 ModestMsgEditWindowPrivate *priv;
3029 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3030 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3032 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3034 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3035 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3040 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3042 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3044 priv->can_undo = can_undo;
3048 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3050 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3052 priv->can_redo = can_redo;
3056 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3058 ModestMsgEditWindowPrivate *priv;
3059 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3060 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3062 return priv->can_undo;
3066 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3068 ModestMsgEditWindowPrivate *priv;
3069 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3070 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3072 return priv->can_redo;
3077 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3080 GtkTextIter match_start, match_end;
3082 if (image_id == NULL)
3085 gtk_text_buffer_get_start_iter (buffer, &iter);
3087 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3088 GSList *tags = gtk_text_iter_get_tags (&match_start);
3090 for (node = tags; node != NULL; node = g_slist_next (node)) {
3091 GtkTextTag *tag = (GtkTextTag *) node->data;
3092 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3093 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3094 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3096 offset = gtk_text_iter_get_offset (&match_start);
3097 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3098 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3102 gtk_text_iter_forward_char (&iter);
3107 message_is_empty (ModestMsgEditWindow *window)
3109 ModestMsgEditWindowPrivate *priv = NULL;
3111 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3112 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3114 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3115 * so we can ignore markup.
3117 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3120 count = gtk_text_buffer_get_char_count (buf);
3126 msg_body_focus (GtkWidget *focus,
3127 GdkEventFocus *event,
3131 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3132 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3133 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3138 recpt_field_changed (GtkTextBuffer *buffer,
3139 ModestMsgEditWindow *editor)
3141 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3142 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3146 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3148 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3149 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3153 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3156 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3157 GtkTextBuffer *buffer;
3159 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3160 gtk_text_buffer_set_modified (buffer, modified);
3161 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3162 gtk_text_buffer_set_modified (buffer, modified);
3163 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3164 gtk_text_buffer_set_modified (buffer, modified);
3165 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3169 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3171 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3172 const char *account_name;
3173 GtkTextBuffer *buffer;
3175 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3176 if (gtk_text_buffer_get_modified (buffer))
3178 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3179 if (gtk_text_buffer_get_modified (buffer))
3181 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3182 if (gtk_text_buffer_get_modified (buffer))
3184 if (gtk_text_buffer_get_modified (priv->text_buffer))
3186 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3187 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3198 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3200 ModestMsgEditWindowPrivate *priv = NULL;
3202 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3203 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3205 /* check if there's no recipient added */
3206 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3207 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3208 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3209 /* no recipient contents, then select contacts */
3210 modest_msg_edit_window_open_addressbook (window, NULL);
3214 g_object_ref (window);
3215 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3216 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3217 g_object_unref (window);
3220 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3221 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3222 g_object_unref (window);
3225 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3226 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3227 g_object_unref (window);
3231 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3232 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3233 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3234 g_object_unref (window);
3241 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3242 ModestMsgEditWindow *window)
3244 modest_msg_edit_window_offer_attach_file (window);
3248 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3250 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3252 return priv->clipboard_text;
3256 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3258 ModestMsgEditWindow *window)
3260 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3261 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3264 /* It could happen that the window was already closed */
3265 if (!GTK_WIDGET_VISIBLE (window))
3268 g_object_ref (window);
3269 text = gtk_clipboard_wait_for_text (selection_clipboard);
3271 if (priv->clipboard_text != NULL) {
3272 g_free (priv->clipboard_text);
3274 priv->clipboard_text = text;
3276 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3278 g_object_unref (window);
3281 static gboolean clipboard_owner_change_idle (gpointer userdata)
3283 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3284 ModestMsgEditWindowPrivate *priv;
3286 gdk_threads_enter ();
3287 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3288 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3290 priv->clipboard_owner_idle = 0;
3291 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3292 gdk_threads_leave ();
3298 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3300 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3301 if (priv->clipboard_owner_idle == 0) {
3302 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3303 clipboard_owner_change_idle,
3304 g_object_ref (window),
3310 subject_field_move_cursor (GtkEntry *entry,
3311 GtkMovementStep step,
3316 /* It could happen that the window was already closed */
3317 if (!GTK_WIDGET_VISIBLE (window))
3320 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3324 update_window_title (ModestMsgEditWindow *window)
3326 ModestMsgEditWindowPrivate *priv = NULL;
3327 const gchar *subject;
3329 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3330 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3331 if (subject == NULL || subject[0] == '\0')
3332 subject = _("mail_va_new_email");
3334 gtk_window_set_title (GTK_WINDOW (window), subject);
3339 subject_field_changed (GtkEditable *editable,
3340 ModestMsgEditWindow *window)
3342 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3343 update_window_title (window);
3344 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3345 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3346 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3350 subject_field_insert_text (GtkEditable *editable,
3352 gint new_text_length,
3354 ModestMsgEditWindow *window)
3356 GString *result = g_string_new ("");
3358 gint result_len = 0;
3359 const gchar *entry_text = NULL;
3362 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3363 old_length = g_utf8_strlen (entry_text, -1);
3365 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3366 gunichar c = g_utf8_get_char_validated (current, 8);
3367 /* Invalid unichar, stop */
3373 result = g_string_append_unichar (result, c);
3377 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3378 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3381 /* Prevent endless recursion */
3382 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3383 g_signal_emit_by_name (editable, "insert-text",
3384 (gpointer) result->str, (gpointer) result->len,
3385 (gpointer) position, (gpointer) window);
3386 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3390 if (result_len + old_length > 1000) {
3391 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3392 _CS("ckdg_ib_maximum_characters_reached"));
3394 g_string_free (result, TRUE);
3398 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3401 ModestMsgEditWindowPrivate *priv = NULL;
3403 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3404 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3406 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3409 gtk_widget_show_all (priv->find_toolbar);
3410 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3412 gtk_widget_hide_all (priv->find_toolbar);
3413 gtk_widget_grab_focus (priv->msg_body);
3418 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3420 GtkTextIter *match_start,
3421 GtkTextIter *match_end)
3423 GtkTextIter end_iter;
3424 gchar *str_casefold;
3427 gchar *range_casefold;
3430 gboolean result = FALSE;
3437 gtk_text_iter_forward_to_end (&end_iter);
3439 str_casefold = g_utf8_casefold (str, -1);
3440 str_chars_n = strlen (str);
3442 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3443 range_casefold = g_utf8_casefold (range_text, -1);
3444 range_chars_n = strlen (range_casefold);
3446 if (range_chars_n < str_chars_n) {
3447 g_free (str_casefold);
3448 g_free (range_text);
3449 g_free (range_casefold);
3453 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3454 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3455 if (!g_utf8_collate (range_subtext, str_casefold)) {
3456 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3458 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3459 match_start, match_end, NULL);
3460 g_free (found_text);
3462 g_free (range_subtext);
3466 g_free (str_casefold);
3467 g_free (range_text);
3468 g_free (range_casefold);
3475 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3476 ModestMsgEditWindow *window)
3478 gchar *current_search = NULL;
3479 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3481 GtkTextIter selection_start, selection_end;
3482 GtkTextIter match_start, match_end;
3483 gboolean continue_search = FALSE;
3485 if (message_is_empty (window)) {
3486 g_free (priv->last_search);
3487 priv->last_search = NULL;
3488 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3492 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3493 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3494 g_free (current_search);
3495 g_free (priv->last_search);
3496 priv->last_search = NULL;
3497 /* Information banner about empty search */
3498 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3502 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3503 continue_search = TRUE;
3505 g_free (priv->last_search);
3506 priv->last_search = g_strdup (current_search);
3509 if (continue_search) {
3510 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3511 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3512 &match_start, &match_end);
3514 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3516 GtkTextIter buffer_start;
3517 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3518 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3519 &match_start, &match_end);
3521 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3524 /* Mark as selected the string found in search */
3526 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3527 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3528 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3530 g_free (priv->last_search);
3531 priv->last_search = NULL;
3533 g_free (current_search);
3537 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3539 ModestMsgEditWindowPrivate *priv;
3541 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3546 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3549 ModestMsgEditWindowPrivate *priv;
3551 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3556 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3557 ModestMsgEditWindow *window)
3559 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3563 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3566 ModestMsgEditWindowPrivate *priv;
3567 TnyHeader *header = NULL;
3569 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3570 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3572 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3573 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3575 if (priv->draft_msg != NULL) {
3576 g_object_unref (priv->draft_msg);
3579 if (draft != NULL) {
3580 g_object_ref (draft);
3581 header = tny_msg_get_header (draft);
3582 if (priv->msg_uid) {
3583 g_free (priv->msg_uid);
3584 priv->msg_uid = NULL;
3586 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3587 if (GTK_WIDGET_REALIZED (window)) {
3588 if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3589 gtk_widget_destroy (GTK_WIDGET (window));
3595 priv->draft_msg = draft;
3599 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3600 GtkTextIter *start, GtkTextIter *end,
3603 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3604 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3607 if (tag == NULL) return;
3608 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3609 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3610 replace_with_images (window, priv->images);
3615 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3618 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3620 g_return_if_fail (TNY_IS_MIME_PART (part));
3621 tny_list_prepend (priv->attachments, (GObject *) part);
3622 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3623 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3624 gtk_widget_show_all (priv->attachments_caption);
3625 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3629 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3631 ModestMsgEditWindowPrivate *priv;
3633 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3634 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3636 return priv->msg_uid;
3640 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3641 ModestMsgEditWindowWidgetType widget_type)
3643 ModestMsgEditWindowPrivate *priv;
3645 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3646 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3648 switch (widget_type) {
3649 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3650 return priv->msg_body;
3652 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3653 return priv->to_field;
3655 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3656 return priv->cc_field;
3658 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3659 return priv->bcc_field;
3661 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3662 return priv->subject_field;
3664 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3665 return priv->attachments_view;
3673 remove_tags (WPTextBuffer *buffer)
3675 GtkTextIter start, end;
3677 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3678 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3680 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3684 on_account_removed (TnyAccountStore *account_store,
3685 TnyAccount *account,
3688 /* Do nothing if it's a store account, because we use the
3689 transport to send the messages */
3690 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3691 const gchar *parent_acc = NULL;
3692 const gchar *our_acc = NULL;
3694 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3695 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3696 /* Close this window if I'm showing a message of the removed account */
3697 if (strcmp (parent_acc, our_acc) == 0)
3698 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3703 from_field_changed (HildonPickerButton *button,
3704 ModestMsgEditWindow *self)
3706 ModestMsgEditWindowPrivate *priv;
3707 gboolean has_old_signature, has_new_signature;
3709 GtkTextIter match_start, match_end;
3710 ModestAccountMgr *mgr;
3712 gchar *full_signature;
3714 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3716 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3717 mgr = modest_runtime_get_account_mgr ();
3718 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3719 if (has_old_signature) {
3720 full_signature = g_strconcat ("\n--\n", signature, NULL);
3721 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3722 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3724 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3725 &match_start, &match_end, NULL)) {
3728 g_free (full_signature);
3732 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3733 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3734 if (has_new_signature) {
3735 full_signature = g_strconcat ("\n--\n", signature, NULL);
3736 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3737 g_free (full_signature);
3742 typedef struct _MessageSettingsHelper {
3743 ModestMsgEditWindow *window;
3744 GSList *priority_group;
3745 GSList *format_group;
3746 GtkToggleButton *current_priority;
3747 GtkToggleButton *current_format;
3748 } MessageSettingsHelper;
3751 on_priority_toggle (GtkToggleButton *button,
3752 MessageSettingsHelper *helper)
3755 ModestMsgEditWindowPrivate *priv;
3757 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3758 if (gtk_toggle_button_get_active (button)) {
3760 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3761 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3762 if ((node_button != button) &&
3763 gtk_toggle_button_get_active (node_button)) {
3764 gtk_toggle_button_set_active (node_button, FALSE);
3767 helper->current_priority = button;
3769 gboolean found = FALSE;
3770 /* If no one is active, activate it again */
3771 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3772 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3773 if (gtk_toggle_button_get_active (node_button)) {
3779 gtk_toggle_button_set_active (button, TRUE);
3785 on_format_toggle (GtkToggleButton *button,
3786 MessageSettingsHelper *helper)
3789 ModestMsgEditWindowPrivate *priv;
3791 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3792 if (gtk_toggle_button_get_active (button)) {
3794 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3795 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3796 if ((node_button != button) &&
3797 gtk_toggle_button_get_active (node_button)) {
3798 gtk_toggle_button_set_active (node_button, FALSE);
3801 helper->current_format = button;
3803 gboolean found = FALSE;
3804 /* If no one is active, activate it again */
3805 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3806 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3807 if (gtk_toggle_button_get_active (node_button)) {
3813 gtk_toggle_button_set_active (button, TRUE);
3820 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3825 GtkWidget *priority_hbox;
3826 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3827 GtkWidget *captioned;
3828 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3829 GtkWidget *format_hbox;
3830 GtkWidget *html_toggle, *text_toggle;
3831 ModestMsgEditWindowPrivate *priv;
3832 MessageSettingsHelper helper = {0,};
3834 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3835 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3836 helper.window = window;
3837 helper.priority_group = NULL;
3838 helper.format_group = NULL;
3840 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3841 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3843 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3844 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3845 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3846 vbox = gtk_vbox_new (FALSE, 0);
3847 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3848 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3849 gtk_container_add (GTK_CONTAINER (align), vbox);
3850 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3851 gtk_widget_show (align);
3852 gtk_widget_show (vbox);
3854 /* Priority toggles */
3855 priority_hbox = gtk_hbox_new (TRUE, 0);
3856 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3857 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3858 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3859 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3860 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3861 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3862 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3863 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3864 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3865 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3866 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3867 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3868 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3869 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3870 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3871 gtk_widget_show_all (priority_hbox);
3872 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3873 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3874 gtk_widget_show (captioned);
3875 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3877 /* format toggles */
3878 format_hbox = gtk_hbox_new (TRUE, 0);
3879 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3880 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3881 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3882 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3883 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3884 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3885 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3886 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3887 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3888 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3889 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3890 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3891 gtk_widget_show_all (format_hbox);
3892 gtk_widget_show (format_hbox);
3893 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3896 g_object_unref (title_sizegroup);
3897 g_object_unref (value_sizegroup);
3899 /* Set current values */
3900 switch (priv->priority_flags) {
3901 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3902 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3903 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3905 case TNY_HEADER_FLAG_LOW_PRIORITY:
3906 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3907 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3910 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3911 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3915 switch (modest_msg_edit_window_get_format (window)) {
3916 case MODEST_MSG_EDIT_FORMAT_TEXT:
3917 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3918 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3920 case MODEST_MSG_EDIT_FORMAT_HTML:
3922 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3923 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3927 /* Signal connects */
3928 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3929 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3930 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3931 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3932 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3934 /* Save settings if the user clicked on done */
3935 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3936 TnyHeaderFlags flags;
3937 ModestMsgEditFormat old_format, new_format;
3939 /* Set priority flags */
3940 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3941 if (priv->priority_flags != flags)
3942 modest_msg_edit_window_set_priority_flags (window, flags);
3944 /* Set edit format */
3945 old_format = modest_msg_edit_window_get_format (window);
3946 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3947 if (old_format != new_format) {
3948 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3949 modest_msg_edit_window_set_file_format (window, file_format);
3953 gtk_widget_destroy (dialog);
3954 g_slist_free (helper.priority_group);
3958 on_message_settings (GtkAction *action,
3959 ModestMsgEditWindow *window)
3961 modest_msg_edit_window_show_msg_settings_dialog (window);
3965 on_cc_button_toggled (HildonCheckButton *button,
3966 ModestMsgEditWindow *window)
3968 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3970 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3971 hildon_check_button_get_active (button));
3975 on_bcc_button_toggled (HildonCheckButton *button,
3976 ModestMsgEditWindow *window)
3978 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3980 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3981 hildon_check_button_get_active (button));
3985 setup_menu (ModestMsgEditWindow *self)
3987 ModestMsgEditWindowPrivate *priv = NULL;
3989 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3991 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3993 /* Settings menu buttons */
3994 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3995 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3997 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3998 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3999 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4001 priv->cc_button = hildon_check_button_new (0);
4002 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4003 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4005 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4007 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4008 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4009 priv->bcc_button = hildon_check_button_new (0);
4010 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4011 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4013 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4015 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4016 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4018 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4019 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4020 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4021 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4022 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4023 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4024 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4025 APP_MENU_CALLBACK (on_message_settings),
4027 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4028 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),