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_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);
1426 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1428 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1429 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1430 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1431 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1432 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1433 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1434 gtk_widget_set_sensitive (arrow, FALSE);
1435 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1436 fonts_menu = gtk_menu_new ();
1437 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1438 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1441 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1443 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1444 0, wp_get_font_name (font_index),
1447 if (font_index == DEFAULT_FONT)
1448 priv->current_face_index = font_index;
1450 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1451 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1452 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1453 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1454 priv->font_face_toolitem = tool_item;
1456 /* Set expand and homogeneous for remaining items */
1457 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1458 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1459 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1460 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1461 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1462 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1463 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1464 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1465 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1467 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1468 will not show the tool items added to the placeholders) */
1469 gtk_widget_show_all (parent_priv->toolbar);
1471 /* Set the no show all *after* showing all items. We do not
1472 want the toolbar to be shown with a show all because it
1473 could go agains the gconf setting regarding showing or not
1474 the toolbar of the editor window */
1475 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1481 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1484 ModestWindowPrivate *parent_priv;
1485 ModestMsgEditWindowPrivate *priv;
1486 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1487 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1488 ModestWindowMgr *mgr = NULL;
1490 g_return_val_if_fail (msg, NULL);
1491 g_return_val_if_fail (account_name, NULL);
1493 mgr = modest_runtime_get_window_mgr ();
1495 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1497 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1498 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1500 /* Menubar. Update the state of some toggles */
1501 priv->from_field_protos = get_transports ();
1502 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1503 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1504 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1505 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1507 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1508 hildon_touch_selector_get_current_text
1509 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1510 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1511 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1514 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1516 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1518 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1520 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1522 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1523 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1524 /* Add common dimming rules */
1525 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1526 modest_msg_edit_window_toolbar_dimming_entries,
1527 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1528 MODEST_WINDOW (obj));
1529 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1530 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1531 MODEST_WINDOW (obj));
1532 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1533 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1534 MODEST_WINDOW (obj));
1535 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1536 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1537 MODEST_WINDOW (obj));
1538 /* Insert dimming rules group for this window */
1539 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1540 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1542 /* Setup app menu */
1543 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1545 /* Checks the dimming rules */
1546 g_object_unref (toolbar_rules_group);
1547 g_object_unref (clipboard_rules_group);
1548 gtk_widget_hide (priv->priority_icon);
1549 gtk_widget_queue_resize (priv->subject_box);
1550 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1552 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1554 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1555 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1556 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1557 priv->update_caption_visibility = TRUE;
1559 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1561 /* Track account-removed signal, this window should be closed
1562 in the case we're creating a mail associated to the account
1564 priv->account_removed_handler_id =
1565 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1567 G_CALLBACK(on_account_removed),
1570 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1572 return (ModestWindow*) obj;
1576 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1578 GString **string_buffer = (GString **) user_data;
1580 *string_buffer = g_string_append (*string_buffer, buffer);
1586 * @result: A new string which should be freed with g_free().
1589 get_formatted_data (ModestMsgEditWindow *edit_window)
1591 ModestMsgEditWindowPrivate *priv;
1592 GString *string_buffer = g_string_new ("");
1594 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1596 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1598 modest_text_utils_hyperlinkify (string_buffer);
1600 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1602 return g_string_free (string_buffer, FALSE);
1607 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1610 const gchar *account_name;
1611 ModestMsgEditWindowPrivate *priv;
1612 TnyIterator *att_iter;
1614 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1616 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1618 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1619 g_return_val_if_fail (account_name, NULL);
1622 /* don't free these (except from) */
1623 data = g_slice_new0 (MsgData);
1624 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1626 data->account_name = g_strdup (account_name);
1627 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1628 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1629 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1630 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1631 if (priv->draft_msg) {
1632 data->draft_msg = g_object_ref (priv->draft_msg);
1633 } else if (priv->outbox_msg) {
1634 data->draft_msg = g_object_ref (priv->outbox_msg);
1636 data->draft_msg = NULL;
1639 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1641 gtk_text_buffer_get_bounds (buf, &b, &e);
1642 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1644 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1645 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1647 data->html_body = NULL;
1649 /* deep-copy the data */
1650 att_iter = tny_list_create_iterator (priv->attachments);
1651 data->attachments = NULL;
1652 while (!tny_iterator_is_done (att_iter)) {
1653 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1654 if (!(TNY_IS_MIME_PART(part))) {
1655 g_warning ("strange data in attachment list");
1656 g_object_unref (part);
1657 tny_iterator_next (att_iter);
1660 data->attachments = g_list_append (data->attachments,
1662 tny_iterator_next (att_iter);
1664 g_object_unref (att_iter);
1666 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1667 att_iter = tny_list_create_iterator (priv->images);
1668 data->images = NULL;
1669 while (!tny_iterator_is_done (att_iter)) {
1670 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1672 if (!(TNY_IS_MIME_PART(part))) {
1673 g_warning ("strange data in attachment list");
1674 g_object_unref (part);
1675 tny_iterator_next (att_iter);
1678 cid = tny_mime_part_get_content_id (part);
1680 gchar *image_tag_id;
1681 GtkTextTag *image_tag;
1683 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1684 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1685 g_free (image_tag_id);
1687 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1689 ((gtk_text_iter_has_tag (&iter, image_tag))||
1690 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1691 data->images = g_list_append (data->images,
1692 g_object_ref (part));
1694 g_object_unref (part);
1695 tny_iterator_next (att_iter);
1697 g_object_unref (att_iter);
1699 data->priority_flags = priv->priority_flags;
1706 unref_gobject (GObject *obj, gpointer data)
1708 if (!G_IS_OBJECT(obj))
1710 g_object_unref (obj);
1714 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1717 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1725 g_free (data->from);
1726 g_free (data->subject);
1727 g_free (data->plain_body);
1728 g_free (data->html_body);
1729 g_free (data->account_name);
1731 if (data->draft_msg != NULL) {
1732 g_object_unref (data->draft_msg);
1733 data->draft_msg = NULL;
1736 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1737 g_list_free (data->attachments);
1738 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1739 g_list_free (data->images);
1741 g_slice_free (MsgData, data);
1745 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1747 guint64 *parts_size)
1749 ModestMsgEditWindowPrivate *priv;
1751 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1753 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1755 /* TODO: add images */
1756 *parts_size += priv->images_size;
1757 *parts_count += priv->images_count;
1762 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1765 ModestMsgEditWindowPrivate *priv = NULL;
1766 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1768 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1770 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1772 return MODEST_MSG_EDIT_FORMAT_HTML;
1774 return MODEST_MSG_EDIT_FORMAT_TEXT;
1778 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1779 ModestMsgEditFormat format)
1781 ModestMsgEditWindowPrivate *priv;
1783 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1784 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1787 case MODEST_MSG_EDIT_FORMAT_HTML:
1788 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1790 case MODEST_MSG_EDIT_FORMAT_TEXT:
1791 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1794 g_return_if_reached ();
1798 ModestMsgEditFormatState *
1799 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1801 ModestMsgEditFormatState *format_state = NULL;
1802 ModestMsgEditWindowPrivate *priv;
1803 WPTextBufferFormat *buffer_format;
1805 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1807 buffer_format = g_new0 (WPTextBufferFormat, 1);
1808 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1810 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1812 format_state = g_new0 (ModestMsgEditFormatState, 1);
1813 format_state->bold = buffer_format->bold&0x1;
1814 format_state->italics = buffer_format->italic&0x1;
1815 format_state->bullet = buffer_format->bullet&0x1;
1816 format_state->color = buffer_format->color;
1817 format_state->font_size = buffer_format->font_size;
1818 format_state->font_family = wp_get_font_name (buffer_format->font);
1819 format_state->justification = buffer_format->justification;
1820 g_free (buffer_format);
1822 return format_state;
1827 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1828 const ModestMsgEditFormatState *format_state)
1830 ModestMsgEditWindowPrivate *priv;
1831 WPTextBufferFormat *buffer_format;
1832 WPTextBufferFormat *current_format;
1834 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1835 g_return_if_fail (format_state != NULL);
1837 buffer_format = g_new0 (WPTextBufferFormat, 1);
1838 current_format = g_new0 (WPTextBufferFormat, 1);
1840 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1841 gtk_widget_grab_focus (priv->msg_body);
1842 buffer_format->bold = (format_state->bold != FALSE);
1843 buffer_format->italic = (format_state->italics != FALSE);
1844 buffer_format->color = format_state->color;
1845 buffer_format->font_size = format_state->font_size;
1846 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1847 buffer_format->justification = format_state->justification;
1848 buffer_format->bullet = format_state->bullet;
1850 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1852 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1853 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1854 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1855 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1856 buffer_format->cs.font = (buffer_format->font != current_format->font);
1857 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1858 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1860 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1861 if (buffer_format->cs.bold) {
1862 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1863 GINT_TO_POINTER (buffer_format->bold&0x1));
1865 if (buffer_format->cs.italic) {
1866 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1867 GINT_TO_POINTER (buffer_format->italic&0x1));
1869 if (buffer_format->cs.color) {
1870 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1871 GINT_TO_POINTER (&(buffer_format->color)));
1873 if (buffer_format->cs.font_size) {
1874 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1875 GINT_TO_POINTER (buffer_format->font_size));
1877 if (buffer_format->cs.justification) {
1878 switch (buffer_format->justification) {
1879 case GTK_JUSTIFY_LEFT:
1880 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1881 GINT_TO_POINTER(TRUE));
1883 case GTK_JUSTIFY_CENTER:
1884 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1885 GINT_TO_POINTER(TRUE));
1887 case GTK_JUSTIFY_RIGHT:
1888 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1889 GINT_TO_POINTER(TRUE));
1896 if (buffer_format->cs.font) {
1897 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1898 GINT_TO_POINTER (buffer_format->font));
1900 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1901 if (buffer_format->cs.bullet) {
1902 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1903 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1905 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1907 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1909 g_free (buffer_format);
1910 g_free (current_format);
1912 /* Check dimming rules */
1913 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1914 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1918 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1920 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1922 ModestWindowPrivate *parent_priv;
1923 ModestMsgEditWindowPrivate *priv;
1925 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1926 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1928 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1929 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1930 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1931 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1933 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1934 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1935 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1938 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1940 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1941 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1943 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1944 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1946 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1947 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1950 switch (buffer_format->justification)
1952 case GTK_JUSTIFY_LEFT:
1953 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1955 case GTK_JUSTIFY_CENTER:
1956 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1958 case GTK_JUSTIFY_RIGHT:
1959 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1966 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1968 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1969 G_CALLBACK (modest_msg_edit_window_color_button_change),
1971 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1972 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1973 G_CALLBACK (modest_msg_edit_window_color_button_change),
1976 if (priv->current_size_index != buffer_format->font_size) {
1980 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1981 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1985 priv->current_size_index = buffer_format->font_size;
1987 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
1988 markup = g_strconcat ("<span font_family='Sans'>",
1989 size_text, "</span>", NULL);
1991 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1995 gtk_tree_path_free (path);
1998 if (priv->current_face_index != buffer_format->font) {
2002 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2003 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2007 priv->current_face_index = buffer_format->font;
2008 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2009 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2010 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2017 g_free (buffer_format);
2021 #ifdef MODEST_HILDON_VERSION_0
2023 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2026 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2027 ModestMsgEditWindowPrivate *priv;
2028 GtkWidget *dialog = NULL;
2030 GdkColor *new_color = NULL;
2032 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2033 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2035 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2036 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2037 g_free (buffer_format);
2039 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2040 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2041 if (new_color != NULL) {
2042 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2043 (gpointer) new_color);
2046 gtk_widget_destroy (dialog);
2051 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2054 ModestMsgEditWindowPrivate *priv;
2055 GtkWidget *dialog = NULL;
2057 GdkColor *old_color = NULL;
2058 const GdkColor *new_color = NULL;
2060 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2061 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2063 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2064 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2066 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2067 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2068 if (new_color != NULL)
2069 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2071 gtk_widget_destroy (dialog);
2077 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2080 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2081 ModestMsgEditWindowPrivate *priv;
2082 GtkWidget *dialog = NULL;
2084 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2085 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2087 dialog = hildon_color_chooser_new ();
2088 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2089 g_free (buffer_format);
2091 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2093 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2094 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2097 gtk_widget_destroy (dialog);
2102 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2105 ModestMsgEditWindowPrivate *priv;
2106 GtkWidget *dialog = NULL;
2107 GdkColor *old_color = NULL;
2109 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2110 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2112 dialog = hildon_color_chooser_new ();
2113 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2115 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2117 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2118 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2120 gtk_widget_destroy (dialog);
2123 #endif /*!MODEST_HILDON_VERSION_0*/
2128 create_stream_for_uri (const gchar* uri)
2133 TnyStream *result = NULL;
2135 GnomeVFSHandle *handle = NULL;
2136 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2137 if (test == GNOME_VFS_OK) {
2138 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2139 /* Streams over OBEX (Bluetooth) are not seekable but
2140 * we expect them to be (we might need to read them
2141 * several times). So if this is a Bluetooth URI just
2142 * read the whole file into memory (this is not a fast
2143 * protocol so we can assume that these files are not
2144 * going to be very big) */
2145 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2146 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2147 TnyStream *memstream = tny_camel_mem_stream_new ();
2148 tny_stream_write_to_stream (vfssstream, memstream);
2149 g_object_unref (vfssstream);
2152 result = vfssstream;
2160 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2163 ModestMsgEditWindowPrivate *priv;
2164 GtkWidget *dialog = NULL;
2166 GSList *uris = NULL;
2167 GSList *uri_node = NULL;
2169 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2171 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2172 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2173 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2175 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2177 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2178 GTK_WINDOW (dialog), GTK_WINDOW (window));
2180 response = gtk_dialog_run (GTK_DIALOG (dialog));
2182 case GTK_RESPONSE_OK:
2183 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2188 gtk_widget_destroy (dialog);
2190 g_object_ref (window);
2191 /* The operation could take some time so allow the dialog to be closed */
2192 while (gtk_events_pending ())
2193 gtk_main_iteration ();
2195 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2197 GnomeVFSHandle *handle = NULL;
2198 GnomeVFSResult result;
2199 GtkTextIter position;
2200 GtkTextMark *insert_mark;
2202 uri = (const gchar *) uri_node->data;
2203 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2204 if (result == GNOME_VFS_OK) {
2206 GnomeVFSFileInfo *info;
2207 gchar *filename, *basename, *escaped_filename;
2208 TnyMimePart *mime_part;
2210 const gchar *mime_type = NULL;
2211 GnomeVFSURI *vfs_uri;
2212 guint64 stream_size;
2214 gnome_vfs_close (handle);
2215 vfs_uri = gnome_vfs_uri_new (uri);
2217 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2218 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2219 g_free (escaped_filename);
2220 gnome_vfs_uri_unref (vfs_uri);
2221 info = gnome_vfs_file_info_new ();
2223 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2224 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2226 mime_type = gnome_vfs_file_info_get_mime_type (info);
2228 mime_part = tny_platform_factory_new_mime_part
2229 (modest_runtime_get_platform_factory ());
2231 TnyStream *stream = create_stream_for_uri (uri);
2233 if (stream == NULL) {
2235 modest_platform_information_banner (NULL, NULL,
2236 _FM("sfil_ib_opening_not_allowed"));
2238 g_object_unref (mime_part);
2239 gnome_vfs_file_info_unref (info);
2243 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2245 content_id = g_strdup_printf ("%d", priv->next_cid);
2246 tny_mime_part_set_content_id (mime_part, content_id);
2247 g_free (content_id);
2250 basename = g_path_get_basename (filename);
2251 tny_mime_part_set_filename (mime_part, basename);
2254 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2256 if (pixbuf != NULL) {
2257 priv->images_size += stream_size;
2258 priv->images_count ++;
2259 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2260 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2261 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2262 tny_mime_part_get_content_id (mime_part), pixbuf);
2263 g_object_unref (pixbuf);
2265 tny_list_prepend (priv->images, (GObject *) mime_part);
2266 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2268 modest_platform_information_banner (NULL, NULL,
2269 _("mail_ib_file_operation_failed"));
2273 g_object_unref (mime_part);
2274 gnome_vfs_file_info_unref (info);
2278 g_object_unref (window);
2282 on_attach_file_response (GtkDialog *dialog,
2286 GSList *uris = NULL;
2288 GnomeVFSFileSize total_size, allowed_size;
2289 ModestMsgEditWindow *window;
2290 ModestMsgEditWindowPrivate *priv;
2295 case GTK_RESPONSE_OK:
2296 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2302 window = MODEST_MSG_EDIT_WINDOW (user_data);
2303 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2305 /* allowed size is the maximum size - what's already there */
2306 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2307 &att_num, &att_size);
2308 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2311 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2313 const gchar *uri = (const gchar *) uri_node->data;
2316 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2318 if (total_size > allowed_size) {
2319 g_warning ("%s: total size: %u",
2320 __FUNCTION__, (unsigned int)total_size);
2323 allowed_size -= total_size;
2325 g_slist_foreach (uris, (GFunc) g_free, NULL);
2326 g_slist_free (uris);
2328 gtk_widget_destroy (GTK_WIDGET (dialog));
2332 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2334 GtkWidget *dialog = NULL;
2335 ModestMsgEditWindowPrivate *priv;
2337 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2339 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2341 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2344 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2345 GTK_FILE_CHOOSER_ACTION_OPEN);
2346 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2347 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2348 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2349 GTK_WINDOW (dialog), GTK_WINDOW (window));
2351 /* Connect to response & show */
2352 g_signal_connect (dialog, "response",
2353 G_CALLBACK (on_attach_file_response), window);
2354 gtk_widget_show (dialog);
2359 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2361 GnomeVFSFileSize allowed_size)
2364 GnomeVFSHandle *handle = NULL;
2365 ModestMsgEditWindowPrivate *priv;
2366 GnomeVFSResult result;
2367 GnomeVFSFileSize size = 0;
2368 g_return_val_if_fail (window, 0);
2369 g_return_val_if_fail (uri, 0);
2371 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2373 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2374 if (result == GNOME_VFS_OK) {
2375 TnyMimePart *mime_part;
2377 const gchar *mime_type = NULL;
2379 gchar *escaped_filename;
2382 GnomeVFSFileInfo *info;
2383 GnomeVFSURI *vfs_uri;
2385 gnome_vfs_close (handle);
2386 vfs_uri = gnome_vfs_uri_new (uri);
2389 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2390 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2391 g_free (escaped_filename);
2392 gnome_vfs_uri_unref (vfs_uri);
2394 info = gnome_vfs_file_info_new ();
2396 if (gnome_vfs_get_file_info (uri,
2398 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2400 mime_type = gnome_vfs_file_info_get_mime_type (info);
2401 mime_part = tny_platform_factory_new_mime_part
2402 (modest_runtime_get_platform_factory ());
2404 /* try to get the attachment's size; this may fail for weird
2405 * file systems, like obex, upnp... */
2406 if (allowed_size != 0 &&
2407 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2409 if (size > allowed_size) {
2410 modest_platform_information_banner (NULL, NULL,
2411 _FM("sfil_ib_opening_not_allowed"));
2416 g_warning ("%s: could not get attachment size", __FUNCTION__);
2418 stream = create_stream_for_uri (uri);
2420 if (stream == NULL) {
2422 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2424 g_object_unref (mime_part);
2426 gnome_vfs_file_info_unref (info);
2430 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2431 g_object_unref (stream);
2433 content_id = g_strdup_printf ("%d", priv->next_cid);
2434 tny_mime_part_set_content_id (mime_part, content_id);
2435 g_free (content_id);
2438 basename = g_path_get_basename (filename);
2439 tny_mime_part_set_filename (mime_part, basename);
2442 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2443 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2445 info->size == 0, info->size);
2446 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2447 gtk_widget_show_all (priv->attachments_caption);
2448 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2450 g_object_unref (mime_part);
2451 gnome_vfs_file_info_unref (info);
2458 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2461 ModestMsgEditWindowPrivate *priv;
2464 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2465 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2467 if (att_list == NULL) {
2468 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2469 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2470 g_object_unref (att_list);
2475 g_object_ref (att_list);
2478 if (tny_list_get_length (att_list) == 0) {
2479 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2481 gboolean dialog_response;
2482 gchar *message = NULL;
2483 gchar *filename = NULL;
2485 if (tny_list_get_length (att_list) == 1) {
2487 iter = tny_list_create_iterator (att_list);
2488 part = (TnyMimePart *) tny_iterator_get_current (iter);
2489 g_object_unref (iter);
2490 if (TNY_IS_MSG (part)) {
2491 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2493 filename = tny_header_dup_subject (header);
2494 g_object_unref (header);
2496 if (filename == NULL) {
2497 filename = g_strdup (_("mail_va_no_subject"));
2500 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2502 g_object_unref (part);
2504 filename = g_strdup ("");
2506 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2507 "emev_nc_delete_attachments",
2508 tny_list_get_length (att_list)), filename);
2511 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2515 if (dialog_response != GTK_RESPONSE_OK) {
2516 g_object_unref (att_list);
2520 for (iter = tny_list_create_iterator (att_list);
2521 !tny_iterator_is_done (iter);
2522 tny_iterator_next (iter)) {
2523 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2524 const gchar *att_id;
2525 tny_list_remove (priv->attachments, (GObject *) mime_part);
2527 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2529 if (tny_list_get_length (priv->attachments) == 0)
2530 gtk_widget_hide (priv->attachments_caption);
2531 att_id = tny_mime_part_get_content_id (mime_part);
2533 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2535 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2536 g_object_unref (mime_part);
2538 g_object_unref (iter);
2541 g_object_unref (att_list);
2543 /* if the last attachment has been removed, focus the Subject: field */
2544 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2545 gtk_widget_grab_focus (priv->subject_field);
2549 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2552 ModestMsgEditWindowPrivate *priv;
2553 GdkColor *new_color;
2554 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2556 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2557 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2560 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2562 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2564 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2566 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2571 font_size_clicked (GtkToolButton *button,
2572 ModestMsgEditWindow *window)
2574 ModestMsgEditWindowPrivate *priv;
2575 GtkWidget *selector, *dialog;
2577 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2579 selector = hildon_touch_selector_new ();
2580 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2581 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2583 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2584 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2585 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2587 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2591 WPTextBufferFormat format;
2593 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2595 memset (&format, 0, sizeof (format));
2596 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2598 format.cs.font_size = TRUE;
2599 format.cs.text_position = TRUE;
2600 format.cs.font = TRUE;
2601 format.font_size = new_index;
2602 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2604 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2605 GINT_TO_POINTER (new_index)))
2606 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2608 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2609 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2610 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2611 size_text, "</span>", NULL);
2613 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2617 gtk_widget_destroy (dialog);
2619 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2624 font_face_clicked (GtkToolButton *button,
2625 ModestMsgEditWindow *window)
2627 ModestMsgEditWindowPrivate *priv;
2628 GtkWidget *selector, *dialog;
2629 GtkCellRenderer *renderer;
2631 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2633 selector = hildon_touch_selector_new ();
2634 renderer = gtk_cell_renderer_text_new ();
2635 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2636 renderer, "family", 0, "text", 0, NULL);
2637 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2639 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2640 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2641 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2643 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2644 gint new_font_index;
2648 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2649 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2650 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2654 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2656 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2657 GINT_TO_POINTER(new_font_index)))
2658 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2660 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2661 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2663 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2667 gtk_tree_path_free (path);
2670 gtk_widget_destroy (dialog);
2672 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2677 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2680 ModestMsgEditWindowPrivate *priv = NULL;
2681 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2683 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2684 if (!priv->update_caption_visibility)
2687 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2689 gtk_widget_show (priv->cc_caption);
2691 gtk_widget_hide (priv->cc_caption);
2693 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2697 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2700 ModestMsgEditWindowPrivate *priv = NULL;
2701 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2703 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2704 if (!priv->update_caption_visibility)
2707 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2709 gtk_widget_show (priv->bcc_caption);
2711 gtk_widget_hide (priv->bcc_caption);
2713 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2717 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2718 ModestRecptEditor *editor)
2720 ModestMsgEditWindowPrivate *priv;
2722 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2723 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2725 /* we check for low-mem; in that case, show a warning, and don't allow
2726 * for the addressbook
2728 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2731 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2733 if (editor == NULL) {
2734 GtkWidget *view_focus;
2735 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2737 /* This code should be kept in sync with ModestRecptEditor. The
2738 textview inside the recpt editor is the one that really gets the
2739 focus. As it's inside a scrolled window, and this one inside the
2740 hbox recpt editor inherits from, we'll need to go up in the
2741 hierarchy to know if the text view is part of the recpt editor
2742 or if it's a different text entry */
2744 if (gtk_widget_get_parent (view_focus)) {
2745 GtkWidget *first_parent;
2747 first_parent = gtk_widget_get_parent (view_focus);
2748 if (gtk_widget_get_parent (first_parent) &&
2749 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2750 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2755 editor = MODEST_RECPT_EDITOR (priv->to_field);
2759 modest_address_book_select_addresses (editor);
2764 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2766 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2768 modest_msg_edit_window_open_addressbook (window, NULL);
2772 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2773 gboolean show_toolbar)
2775 ModestWindowPrivate *parent_priv;
2777 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2778 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2780 /* We can not just use the code of
2781 modest_msg_edit_window_setup_toolbar because it has a
2782 mixture of both initialization and creation code. */
2784 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2786 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2790 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2791 TnyHeaderFlags priority_flags)
2793 ModestMsgEditWindowPrivate *priv;
2794 ModestWindowPrivate *parent_priv;
2796 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2799 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2801 if (priv->priority_flags != priority_flags) {
2802 GtkAction *priority_action = NULL;
2804 priv->priority_flags = priority_flags;
2806 switch (priority_flags) {
2807 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2808 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2809 MODEST_HEADER_ICON_HIGH,
2810 HILDON_ICON_SIZE_SMALL);
2811 gtk_widget_show (priv->priority_icon);
2812 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2813 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2815 case TNY_HEADER_FLAG_LOW_PRIORITY:
2816 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2817 MODEST_HEADER_ICON_LOW,
2818 HILDON_ICON_SIZE_SMALL);
2819 gtk_widget_show (priv->priority_icon);
2820 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2821 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2824 gtk_widget_hide (priv->priority_icon);
2825 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2826 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2829 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2830 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2832 gtk_widget_queue_resize (priv->subject_box);
2836 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2839 ModestMsgEditWindowPrivate *priv;
2840 ModestWindowPrivate *parent_priv;
2841 gint current_format;
2843 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2845 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2846 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2848 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2849 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2851 if (current_format != file_format) {
2852 switch (file_format) {
2853 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2854 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2855 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2857 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2861 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2862 response = gtk_dialog_run (GTK_DIALOG (dialog));
2863 gtk_widget_destroy (dialog);
2864 if (response == GTK_RESPONSE_OK) {
2865 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2867 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2868 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2873 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2874 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2875 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2880 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2883 ModestMsgEditWindowPrivate *priv;
2884 WPTextBufferFormat oldfmt, fmt;
2885 gint old_position = 0;
2889 GdkColor *color = NULL;
2890 gboolean bold, bold_set, italic, italic_set;
2891 gboolean underline, underline_set;
2892 gboolean strikethrough, strikethrough_set;
2893 gboolean position_set;
2894 gboolean font_size_set, font_set, color_set;
2897 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2898 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2900 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2901 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2902 GTK_WINDOW(dialog), GTK_WINDOW (window));
2904 /* First we get the currently selected font information */
2905 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2907 switch (oldfmt.text_position) {
2908 case TEXT_POSITION_NORMAL:
2911 case TEXT_POSITION_SUPERSCRIPT:
2919 g_object_set (G_OBJECT (dialog),
2920 "bold", oldfmt.bold != FALSE,
2921 "bold-set", !oldfmt.cs.bold,
2922 "underline", oldfmt.underline != FALSE,
2923 "underline-set", !oldfmt.cs.underline,
2924 "italic", oldfmt.italic != FALSE,
2925 "italic-set", !oldfmt.cs.italic,
2926 "strikethrough", oldfmt.strikethrough != FALSE,
2927 "strikethrough-set", !oldfmt.cs.strikethrough,
2928 "color", &oldfmt.color,
2929 "color-set", !oldfmt.cs.color,
2930 "size", wp_font_size[oldfmt.font_size],
2931 "size-set", !oldfmt.cs.font_size,
2932 "position", old_position,
2933 "position-set", !oldfmt.cs.text_position,
2934 "family", wp_get_font_name (oldfmt.font),
2935 "family-set", !oldfmt.cs.font,
2938 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2939 GTK_WINDOW (dialog), GTK_WINDOW (window));
2940 gtk_widget_show_all (dialog);
2941 priv->font_dialog = dialog;
2942 response = gtk_dialog_run (GTK_DIALOG (dialog));
2943 priv->font_dialog = NULL;
2944 if (response == GTK_RESPONSE_OK) {
2946 g_object_get( dialog,
2948 "bold-set", &bold_set,
2949 "underline", &underline,
2950 "underline-set", &underline_set,
2952 "italic-set", &italic_set,
2953 "strikethrough", &strikethrough,
2954 "strikethrough-set", &strikethrough_set,
2956 "color-set", &color_set,
2958 "size-set", &font_size_set,
2959 "family", &font_name,
2960 "family-set", &font_set,
2961 "position", &position,
2962 "position-set", &position_set,
2967 if (response == GTK_RESPONSE_OK) {
2968 memset(&fmt, 0, sizeof(fmt));
2974 fmt.italic = italic;
2975 fmt.cs.italic = TRUE;
2977 if (underline_set) {
2978 fmt.underline = underline;
2979 fmt.cs.underline = TRUE;
2981 if (strikethrough_set) {
2982 fmt.strikethrough = strikethrough;
2983 fmt.cs.strikethrough = TRUE;
2988 ? TEXT_POSITION_NORMAL
2989 : ( ( position == 1 )
2990 ? TEXT_POSITION_SUPERSCRIPT
2991 : TEXT_POSITION_SUBSCRIPT );
2992 fmt.cs.text_position = TRUE;
2993 fmt.font_size = oldfmt.font_size;
2997 fmt.cs.color = TRUE;
3000 fmt.font = wp_get_font_index(font_name,
3005 if (font_size_set) {
3006 fmt.cs.font_size = TRUE;
3007 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3009 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3010 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3012 gtk_widget_destroy (dialog);
3014 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3018 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3020 ModestMsgEditWindowPrivate *priv;
3022 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3023 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3025 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3027 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3028 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3032 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3034 ModestMsgEditWindowPrivate *priv;
3036 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3037 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3039 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3041 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3042 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3047 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3049 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3051 priv->can_undo = can_undo;
3055 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3057 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3059 priv->can_redo = can_redo;
3063 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3065 ModestMsgEditWindowPrivate *priv;
3066 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3067 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3069 return priv->can_undo;
3073 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3075 ModestMsgEditWindowPrivate *priv;
3076 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3077 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3079 return priv->can_redo;
3084 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3087 GtkTextIter match_start, match_end;
3089 if (image_id == NULL)
3092 gtk_text_buffer_get_start_iter (buffer, &iter);
3094 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3095 GSList *tags = gtk_text_iter_get_tags (&match_start);
3097 for (node = tags; node != NULL; node = g_slist_next (node)) {
3098 GtkTextTag *tag = (GtkTextTag *) node->data;
3099 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3100 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3101 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3103 offset = gtk_text_iter_get_offset (&match_start);
3104 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3105 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3109 gtk_text_iter_forward_char (&iter);
3114 message_is_empty (ModestMsgEditWindow *window)
3116 ModestMsgEditWindowPrivate *priv = NULL;
3118 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3119 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3121 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3122 * so we can ignore markup.
3124 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3127 count = gtk_text_buffer_get_char_count (buf);
3133 msg_body_focus (GtkWidget *focus,
3134 GdkEventFocus *event,
3138 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3139 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3140 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3145 recpt_field_changed (GtkTextBuffer *buffer,
3146 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 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3155 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3156 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3160 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3163 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3164 GtkTextBuffer *buffer;
3166 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3167 gtk_text_buffer_set_modified (buffer, modified);
3168 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3169 gtk_text_buffer_set_modified (buffer, modified);
3170 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3171 gtk_text_buffer_set_modified (buffer, modified);
3172 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3176 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3178 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3179 const char *account_name;
3180 GtkTextBuffer *buffer;
3182 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3183 if (gtk_text_buffer_get_modified (buffer))
3185 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3186 if (gtk_text_buffer_get_modified (buffer))
3188 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3189 if (gtk_text_buffer_get_modified (buffer))
3191 if (gtk_text_buffer_get_modified (priv->text_buffer))
3193 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3194 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3205 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3207 ModestMsgEditWindowPrivate *priv = NULL;
3209 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3210 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3212 /* check if there's no recipient added */
3213 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3214 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3215 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3216 /* no recipient contents, then select contacts */
3217 modest_msg_edit_window_open_addressbook (window, NULL);
3221 g_object_ref (window);
3222 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3223 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3224 g_object_unref (window);
3227 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3228 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3229 g_object_unref (window);
3232 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3233 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3234 g_object_unref (window);
3238 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3239 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3240 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3241 g_object_unref (window);
3248 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3249 ModestMsgEditWindow *window)
3251 modest_msg_edit_window_offer_attach_file (window);
3255 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3257 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3259 return priv->clipboard_text;
3263 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3265 ModestMsgEditWindow *window)
3267 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3268 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3271 /* It could happen that the window was already closed */
3272 if (!GTK_WIDGET_VISIBLE (window))
3275 g_object_ref (window);
3276 text = gtk_clipboard_wait_for_text (selection_clipboard);
3278 if (priv->clipboard_text != NULL) {
3279 g_free (priv->clipboard_text);
3281 priv->clipboard_text = text;
3283 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3285 g_object_unref (window);
3288 static gboolean clipboard_owner_change_idle (gpointer userdata)
3290 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3291 ModestMsgEditWindowPrivate *priv;
3293 gdk_threads_enter ();
3294 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3295 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3297 priv->clipboard_owner_idle = 0;
3298 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3299 gdk_threads_leave ();
3305 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3307 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3308 if (priv->clipboard_owner_idle == 0) {
3309 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3310 clipboard_owner_change_idle,
3311 g_object_ref (window),
3317 subject_field_move_cursor (GtkEntry *entry,
3318 GtkMovementStep step,
3323 /* It could happen that the window was already closed */
3324 if (!GTK_WIDGET_VISIBLE (window))
3327 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3331 update_window_title (ModestMsgEditWindow *window)
3333 ModestMsgEditWindowPrivate *priv = NULL;
3334 const gchar *subject;
3336 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3337 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3338 if (subject == NULL || subject[0] == '\0')
3339 subject = _("mail_va_new_email");
3341 gtk_window_set_title (GTK_WINDOW (window), subject);
3346 subject_field_changed (GtkEditable *editable,
3347 ModestMsgEditWindow *window)
3349 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3350 update_window_title (window);
3351 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3352 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3353 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3357 subject_field_insert_text (GtkEditable *editable,
3359 gint new_text_length,
3361 ModestMsgEditWindow *window)
3363 GString *result = g_string_new ("");
3365 gint result_len = 0;
3366 const gchar *entry_text = NULL;
3369 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3370 old_length = g_utf8_strlen (entry_text, -1);
3372 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3373 gunichar c = g_utf8_get_char_validated (current, 8);
3374 /* Invalid unichar, stop */
3380 result = g_string_append_unichar (result, c);
3384 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3385 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3388 /* Prevent endless recursion */
3389 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3390 g_signal_emit_by_name (editable, "insert-text",
3391 (gpointer) result->str, (gpointer) result->len,
3392 (gpointer) position, (gpointer) window);
3393 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3397 if (result_len + old_length > 1000) {
3398 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3399 _CS("ckdg_ib_maximum_characters_reached"));
3401 g_string_free (result, TRUE);
3405 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3408 ModestMsgEditWindowPrivate *priv = NULL;
3410 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3411 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3413 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3416 gtk_widget_show_all (priv->find_toolbar);
3417 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3419 gtk_widget_hide_all (priv->find_toolbar);
3420 gtk_widget_grab_focus (priv->msg_body);
3425 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3427 GtkTextIter *match_start,
3428 GtkTextIter *match_end)
3430 GtkTextIter end_iter;
3431 gchar *str_casefold;
3434 gchar *range_casefold;
3437 gboolean result = FALSE;
3444 gtk_text_iter_forward_to_end (&end_iter);
3446 str_casefold = g_utf8_casefold (str, -1);
3447 str_chars_n = strlen (str);
3449 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3450 range_casefold = g_utf8_casefold (range_text, -1);
3451 range_chars_n = strlen (range_casefold);
3453 if (range_chars_n < str_chars_n) {
3454 g_free (str_casefold);
3455 g_free (range_text);
3456 g_free (range_casefold);
3460 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3461 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3462 if (!g_utf8_collate (range_subtext, str_casefold)) {
3463 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3465 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3466 match_start, match_end, NULL);
3467 g_free (found_text);
3469 g_free (range_subtext);
3473 g_free (str_casefold);
3474 g_free (range_text);
3475 g_free (range_casefold);
3482 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3483 ModestMsgEditWindow *window)
3485 gchar *current_search = NULL;
3486 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3488 GtkTextIter selection_start, selection_end;
3489 GtkTextIter match_start, match_end;
3490 gboolean continue_search = FALSE;
3492 if (message_is_empty (window)) {
3493 g_free (priv->last_search);
3494 priv->last_search = NULL;
3495 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3499 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3500 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3501 g_free (current_search);
3502 g_free (priv->last_search);
3503 priv->last_search = NULL;
3504 /* Information banner about empty search */
3505 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3509 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3510 continue_search = TRUE;
3512 g_free (priv->last_search);
3513 priv->last_search = g_strdup (current_search);
3516 if (continue_search) {
3517 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3518 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3519 &match_start, &match_end);
3521 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3523 GtkTextIter buffer_start;
3524 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3525 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3526 &match_start, &match_end);
3528 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3531 /* Mark as selected the string found in search */
3533 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3534 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3535 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3537 g_free (priv->last_search);
3538 priv->last_search = NULL;
3540 g_free (current_search);
3544 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3546 ModestMsgEditWindowPrivate *priv;
3548 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3553 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3556 ModestMsgEditWindowPrivate *priv;
3558 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3563 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3564 ModestMsgEditWindow *window)
3566 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3570 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3573 ModestMsgEditWindowPrivate *priv;
3574 TnyHeader *header = NULL;
3576 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3577 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3579 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3580 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3582 if (priv->draft_msg != NULL) {
3583 g_object_unref (priv->draft_msg);
3586 if (draft != NULL) {
3587 g_object_ref (draft);
3588 header = tny_msg_get_header (draft);
3589 if (priv->msg_uid) {
3590 g_free (priv->msg_uid);
3591 priv->msg_uid = NULL;
3593 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3594 if (GTK_WIDGET_REALIZED (window)) {
3595 if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3596 gtk_widget_destroy (GTK_WIDGET (window));
3602 priv->draft_msg = draft;
3606 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3607 GtkTextIter *start, GtkTextIter *end,
3610 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3611 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3614 if (tag == NULL) return;
3615 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3616 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3617 replace_with_images (window, priv->images);
3622 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3625 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3627 g_return_if_fail (TNY_IS_MIME_PART (part));
3628 tny_list_prepend (priv->attachments, (GObject *) part);
3629 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3630 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3631 gtk_widget_show_all (priv->attachments_caption);
3632 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3636 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3638 ModestMsgEditWindowPrivate *priv;
3640 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3641 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3643 return priv->msg_uid;
3647 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3648 ModestMsgEditWindowWidgetType widget_type)
3650 ModestMsgEditWindowPrivate *priv;
3652 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3653 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3655 switch (widget_type) {
3656 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3657 return priv->msg_body;
3659 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3660 return priv->to_field;
3662 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3663 return priv->cc_field;
3665 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3666 return priv->bcc_field;
3668 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3669 return priv->subject_field;
3671 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3672 return priv->attachments_view;
3680 remove_tags (WPTextBuffer *buffer)
3682 GtkTextIter start, end;
3684 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3685 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3687 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3691 on_account_removed (TnyAccountStore *account_store,
3692 TnyAccount *account,
3695 /* Do nothing if it's a store account, because we use the
3696 transport to send the messages */
3697 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3698 const gchar *parent_acc = NULL;
3699 const gchar *our_acc = NULL;
3701 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3702 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3703 /* Close this window if I'm showing a message of the removed account */
3704 if (strcmp (parent_acc, our_acc) == 0)
3705 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3710 from_field_changed (HildonPickerButton *button,
3711 ModestMsgEditWindow *self)
3713 ModestMsgEditWindowPrivate *priv;
3714 gboolean has_old_signature, has_new_signature;
3716 GtkTextIter match_start, match_end;
3717 ModestAccountMgr *mgr;
3719 gchar *full_signature;
3721 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3723 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3724 mgr = modest_runtime_get_account_mgr ();
3725 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3726 if (has_old_signature) {
3727 full_signature = g_strconcat ("\n--\n", signature, NULL);
3728 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3729 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3731 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3732 &match_start, &match_end, NULL)) {
3735 g_free (full_signature);
3739 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3740 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3741 if (has_new_signature) {
3742 full_signature = g_strconcat ("\n--\n", signature, NULL);
3743 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3744 g_free (full_signature);
3749 typedef struct _MessageSettingsHelper {
3750 ModestMsgEditWindow *window;
3751 GSList *priority_group;
3752 GSList *format_group;
3753 GtkToggleButton *current_priority;
3754 GtkToggleButton *current_format;
3755 } MessageSettingsHelper;
3758 on_priority_toggle (GtkToggleButton *button,
3759 MessageSettingsHelper *helper)
3762 ModestMsgEditWindowPrivate *priv;
3764 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3765 if (gtk_toggle_button_get_active (button)) {
3767 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3768 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3769 if ((node_button != button) &&
3770 gtk_toggle_button_get_active (node_button)) {
3771 gtk_toggle_button_set_active (node_button, FALSE);
3774 helper->current_priority = button;
3776 gboolean found = FALSE;
3777 /* If no one is active, activate it again */
3778 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3779 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3780 if (gtk_toggle_button_get_active (node_button)) {
3786 gtk_toggle_button_set_active (button, TRUE);
3792 on_format_toggle (GtkToggleButton *button,
3793 MessageSettingsHelper *helper)
3796 ModestMsgEditWindowPrivate *priv;
3798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3799 if (gtk_toggle_button_get_active (button)) {
3801 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3802 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3803 if ((node_button != button) &&
3804 gtk_toggle_button_get_active (node_button)) {
3805 gtk_toggle_button_set_active (node_button, FALSE);
3808 helper->current_format = button;
3810 gboolean found = FALSE;
3811 /* If no one is active, activate it again */
3812 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3813 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3814 if (gtk_toggle_button_get_active (node_button)) {
3820 gtk_toggle_button_set_active (button, TRUE);
3827 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3832 GtkWidget *priority_hbox;
3833 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3834 GtkWidget *captioned;
3835 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3836 GtkWidget *format_hbox;
3837 GtkWidget *html_toggle, *text_toggle;
3838 ModestMsgEditWindowPrivate *priv;
3839 MessageSettingsHelper helper = {0,};
3841 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3842 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3843 helper.window = window;
3844 helper.priority_group = NULL;
3845 helper.format_group = NULL;
3847 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3848 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3850 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3851 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3852 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3853 vbox = gtk_vbox_new (FALSE, 0);
3854 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3855 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3856 gtk_container_add (GTK_CONTAINER (align), vbox);
3857 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3858 gtk_widget_show (align);
3859 gtk_widget_show (vbox);
3861 /* Priority toggles */
3862 priority_hbox = gtk_hbox_new (TRUE, 0);
3863 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3864 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3865 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3866 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3867 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3868 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3869 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3870 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3871 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3872 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3873 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3874 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3875 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3876 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3877 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3878 gtk_widget_show_all (priority_hbox);
3879 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3880 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3881 gtk_widget_show (captioned);
3882 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3884 /* format toggles */
3885 format_hbox = gtk_hbox_new (TRUE, 0);
3886 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3887 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3888 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3889 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3890 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3891 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3892 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3893 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3894 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3895 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3896 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3897 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3898 gtk_widget_show_all (format_hbox);
3899 gtk_widget_show (format_hbox);
3900 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3903 g_object_unref (title_sizegroup);
3904 g_object_unref (value_sizegroup);
3906 /* Set current values */
3907 switch (priv->priority_flags) {
3908 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3909 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3910 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3912 case TNY_HEADER_FLAG_LOW_PRIORITY:
3913 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3914 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3917 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3918 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3922 switch (modest_msg_edit_window_get_format (window)) {
3923 case MODEST_MSG_EDIT_FORMAT_TEXT:
3924 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3925 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3927 case MODEST_MSG_EDIT_FORMAT_HTML:
3929 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3930 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3934 /* Signal connects */
3935 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3936 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3937 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3938 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3939 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3941 /* Save settings if the user clicked on done */
3942 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3943 TnyHeaderFlags flags;
3944 ModestMsgEditFormat old_format, new_format;
3946 /* Set priority flags */
3947 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3948 if (priv->priority_flags != flags)
3949 modest_msg_edit_window_set_priority_flags (window, flags);
3951 /* Set edit format */
3952 old_format = modest_msg_edit_window_get_format (window);
3953 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3954 if (old_format != new_format) {
3955 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3956 modest_msg_edit_window_set_file_format (window, file_format);
3960 gtk_widget_destroy (dialog);
3961 g_slist_free (helper.priority_group);
3965 on_message_settings (GtkAction *action,
3966 ModestMsgEditWindow *window)
3968 modest_msg_edit_window_show_msg_settings_dialog (window);
3972 on_cc_button_toggled (HildonCheckButton *button,
3973 ModestMsgEditWindow *window)
3975 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3977 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3978 hildon_check_button_get_active (button));
3982 on_bcc_button_toggled (HildonCheckButton *button,
3983 ModestMsgEditWindow *window)
3985 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3987 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3988 hildon_check_button_get_active (button));
3992 setup_menu (ModestMsgEditWindow *self)
3994 ModestMsgEditWindowPrivate *priv = NULL;
3996 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3998 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4000 /* Settings menu buttons */
4001 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4002 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4004 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4005 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4006 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4008 priv->cc_button = hildon_check_button_new (0);
4009 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4010 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4012 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4014 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4015 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4016 priv->bcc_button = hildon_check_button_new (0);
4017 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4018 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4020 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4022 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4023 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4025 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4026 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4027 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4028 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4029 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4030 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4031 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4032 APP_MENU_CALLBACK (on_message_settings),
4034 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4035 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),