1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38 #include <tny-camel-mem-stream.h>
42 #include <modest-account-mgr.h>
43 #include <modest-account-mgr-helpers.h>
45 #include <widgets/modest-msg-edit-window.h>
46 #include <modest-selector-picker.h>
47 #include <widgets/modest-recpt-editor.h>
48 #include <widgets/modest-attachments-view.h>
50 #include <modest-runtime.h>
52 #include "modest-platform.h"
53 #include "modest-icon-names.h"
54 #include "modest-widget-memory.h"
55 #include "modest-window-priv.h"
56 #include "modest-mail-operation.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-tny-folder.h"
60 #include "modest-tny-account.h"
61 #include "modest-address-book.h"
62 #include "modest-text-utils.h"
63 #include <tny-simple-list.h>
64 #include <modest-wp-text-view.h>
65 #include <wptextbuffer.h>
66 #include <hildon/hildon-pannable-area.h>
67 #include <hildon/hildon-touch-selector.h>
68 #include <hildon/hildon-picker-dialog.h>
69 #include "modest-msg-edit-window-ui-dimming.h"
71 #include "modest-hildon-includes.h"
72 #ifdef MODEST_HAVE_HILDON0_WIDGETS
73 #include <hildon-widgets/hildon-color-chooser.h>
75 #include "widgets/modest-msg-edit-window-ui.h"
76 #ifdef MODEST_HAVE_HILDON0_WIDGETS
77 #include <libgnomevfs/gnome-vfs-mime-utils.h>
79 #include <libgnomevfs/gnome-vfs-mime.h>
81 #include <modest-utils.h>
82 #include "modest-maemo-utils.h"
83 #include <modest-ui-constants.h>
86 #define DEFAULT_FONT_SIZE 3
87 #define DEFAULT_FONT 2
88 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
89 #define DEFAULT_MAIN_VBOX_SPACING 6
90 #define SUBJECT_MAX_LENGTH 1000
91 #define IMAGE_MAX_WIDTH 560
92 #define DEFAULT_FONT_SCALE 1.5
93 #define ATTACHMENT_BUTTON_WIDTH 118
95 static gboolean is_wp_text_buffer_started = FALSE;
97 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
98 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
99 static void modest_msg_edit_window_finalize (GObject *obj);
101 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
102 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
103 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
105 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
106 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
107 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
108 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
109 GtkTextIter *start, GtkTextIter *end,
111 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
112 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
113 static void subject_field_insert_text (GtkEditable *editable,
115 gint new_text_length,
117 ModestMsgEditWindow *window);
118 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
122 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
123 ModestRecptEditor *editor);
124 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
125 ModestMsgEditWindow *window);
127 /* ModestWindow methods implementation */
128 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
129 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
130 gboolean show_toolbar);
131 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
133 ModestMsgEditWindow *window);
134 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
135 static void subject_field_move_cursor (GtkEntry *entry,
136 GtkMovementStep step,
140 static void update_window_title (ModestMsgEditWindow *window);
143 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
144 ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
149 GtkTextIter *match_start,
150 GtkTextIter *match_end);
152 static void remove_tags (WPTextBuffer *buffer);
154 static void on_account_removed (TnyAccountStore *account_store,
158 static void init_window (ModestMsgEditWindow *obj);
160 gboolean scroll_drag_timeout (gpointer userdata);
161 static void correct_scroll (ModestMsgEditWindow *w);
162 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
163 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
164 ModestMsgEditWindow *userdata);
165 static void text_buffer_mark_set (GtkTextBuffer *buffer,
168 ModestMsgEditWindow *userdata);
169 static void on_message_settings (GtkAction *action,
170 ModestMsgEditWindow *window);
171 static void setup_menu (ModestMsgEditWindow *self);
173 static void from_field_changed (HildonPickerButton *button,
174 ModestMsgEditWindow *self);
175 static void font_size_clicked (GtkToolButton *button,
176 ModestMsgEditWindow *window);
177 static void font_face_clicked (GtkToolButton *button,
178 ModestMsgEditWindow *window);
179 static void DEBUG_BUFFER (WPTextBuffer *buffer)
183 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
185 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
186 while (!gtk_text_iter_is_end (&iter)) {
187 GString *output = g_string_new ("");
188 GSList *toggled_tags;
191 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
192 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
193 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
194 GtkTextTag *tag = (GtkTextTag *) node->data;
196 g_object_get (G_OBJECT (tag), "name", &name, NULL);
197 output = g_string_append (output, name);
198 g_string_append (output, " ");
200 output = g_string_append (output, "] OPENED [ ");
201 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
202 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
203 GtkTextTag *tag = (GtkTextTag *) node->data;
205 g_object_get (G_OBJECT (tag), "name", &name, NULL);
206 output = g_string_append (output, name);
207 g_string_append (output, " ");
209 output = g_string_append (output, "]\n");
210 g_message ("%s", output->str);
211 g_string_free (output, TRUE);
212 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
214 g_message ("END BUFFER");
218 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
219 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
223 /* static gboolean */
224 /* on_key_pressed (GtkWidget *self, */
225 /* GdkEventKey *event, */
226 /* gpointer user_data); */
228 /* list my signals */
235 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
236 struct _ModestMsgEditWindowPrivate {
238 GtkWidget *header_box;
240 ModestPairList *from_field_protos;
241 GtkWidget *from_field;
242 gchar *last_from_account;
243 gchar *original_account_name;
250 GtkWidget *bcc_field;
251 GtkWidget *subject_field;
252 GtkWidget *attachments_view;
253 GtkWidget *priority_icon;
254 GtkWidget *subject_box;
255 GtkWidget *add_attachment_button;
257 GtkWidget *cc_caption;
258 GtkWidget *bcc_caption;
259 gboolean update_caption_visibility;
260 GtkWidget *attachments_caption;
262 GtkTextBuffer *text_buffer;
264 GtkWidget *font_size_toolitem;
265 GtkWidget *font_face_toolitem;
266 GtkWidget *font_color_button;
267 GtkWidget *font_color_toolitem;
268 GSList *font_items_group;
269 GtkTreeModel *faces_model;
270 gint current_face_index;
271 GtkWidget *font_tool_button_label;
272 GtkTreeModel *sizes_model;
273 gint current_size_index;
274 GtkWidget *size_tool_button_label;
276 GtkWidget *find_toolbar;
279 GtkWidget *font_dialog;
282 guint correct_scroll_idle;
283 guint scroll_drag_timeout_id;
287 TnyList *attachments;
292 TnyHeaderFlags priority_flags;
294 gboolean can_undo, can_redo;
295 gulong clipboard_change_handler_id;
296 gulong default_clipboard_change_handler_id;
297 gulong account_removed_handler_id;
298 guint clipboard_owner_idle;
299 gchar *clipboard_text;
308 GtkWidget *cc_button;
309 GtkWidget *bcc_button;
312 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
313 MODEST_TYPE_MSG_EDIT_WINDOW, \
314 ModestMsgEditWindowPrivate))
316 static GtkWindowClass *parent_class = NULL;
318 /* uncomment the following if you have defined any signals */
319 /* static guint signals[LAST_SIGNAL] = {0}; */
322 modest_msg_edit_window_get_type (void)
324 static GType my_type = 0;
326 static const GTypeInfo my_info = {
327 sizeof(ModestMsgEditWindowClass),
328 NULL, /* base init */
329 NULL, /* base finalize */
330 (GClassInitFunc) modest_msg_edit_window_class_init,
331 NULL, /* class finalize */
332 NULL, /* class data */
333 sizeof(ModestMsgEditWindow),
335 (GInstanceInitFunc) modest_msg_edit_window_init,
338 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
339 "ModestMsgEditWindow",
347 save_state (ModestWindow *self)
349 modest_widget_memory_save (modest_runtime_get_conf(),
350 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
355 restore_settings (ModestMsgEditWindow *self)
357 ModestConf *conf = NULL;
359 conf = modest_runtime_get_conf ();
361 /* Dim at start clipboard actions */
362 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
367 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
369 GObjectClass *gobject_class;
370 ModestWindowClass *modest_window_class;
371 gobject_class = (GObjectClass*) klass;
372 modest_window_class = (ModestWindowClass*) klass;
374 parent_class = g_type_class_peek_parent (klass);
375 gobject_class->finalize = modest_msg_edit_window_finalize;
377 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
378 modest_window_class->save_state_func = save_state;
379 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
381 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
385 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
387 ModestMsgEditWindowPrivate *priv;
388 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
390 priv->msg_body = NULL;
391 priv->from_field = NULL;
392 priv->to_field = NULL;
393 priv->cc_field = NULL;
394 priv->bcc_field = NULL;
395 priv->subject_field = NULL;
396 priv->attachments = TNY_LIST (tny_simple_list_new ());
397 priv->images = TNY_LIST (tny_simple_list_new ());
398 priv->images_size = 0;
399 priv->images_count = 0;
402 priv->cc_caption = NULL;
403 priv->bcc_caption = NULL;
404 priv->update_caption_visibility = FALSE;
406 priv->priority_flags = 0;
408 priv->find_toolbar = NULL;
409 priv->last_search = NULL;
411 priv->draft_msg = NULL;
412 priv->outbox_msg = NULL;
413 priv->msg_uid = NULL;
415 priv->can_undo = FALSE;
416 priv->can_redo = FALSE;
417 priv->clipboard_change_handler_id = 0;
418 priv->default_clipboard_change_handler_id = 0;
419 priv->account_removed_handler_id = 0;
420 priv->clipboard_owner_idle = 0;
421 priv->clipboard_text = NULL;
424 priv->scroll_drag_timeout_id = 0;
425 priv->correct_scroll_idle = 0;
426 priv->last_upper = 0.0;
428 priv->font_dialog = NULL;
429 priv->app_menu = NULL;
431 priv->references = NULL;
432 priv->in_reply_to = NULL;
434 if (!is_wp_text_buffer_started) {
435 is_wp_text_buffer_started = TRUE;
436 wp_text_buffer_library_init ();
441 hildon_program_add_window (hildon_program_get_instance(),
447 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
449 static ModestPairList*
450 get_transports (void)
452 GSList *transports = NULL;
454 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
455 GSList *accounts = modest_account_mgr_account_names (account_mgr,
456 TRUE /* only enabled accounts. */);
458 GSList *cursor = accounts;
460 gchar *account_name = cursor->data;
461 gchar *from_string = NULL;
463 from_string = modest_account_mgr_get_from_string (account_mgr,
467 if (from_string && account_name) {
468 gchar *name = account_name;
469 ModestPair *pair = modest_pair_new ((gpointer) name,
470 (gpointer) from_string , TRUE);
471 transports = g_slist_prepend (transports, pair);
474 cursor = cursor->next;
476 g_slist_free (accounts); /* only free the accounts, not the elements,
477 * because they are used in the pairlist */
481 static void window_focus (GtkWindow *window,
485 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
489 scroll_drag_timeout (gpointer userdata)
491 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
492 ModestMsgEditWindowPrivate *priv;
494 /* It could happen that the window was already closed */
495 if (!GTK_WIDGET_VISIBLE (win))
498 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
500 correct_scroll_without_drag_check (win, TRUE);
502 priv->scroll_drag_timeout_id = 0;
508 correct_scroll_without_drag_check_idle (gpointer userdata)
510 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
511 ModestMsgEditWindowPrivate *priv;
513 GdkRectangle rectangle;
514 gint offset_min, offset_max;
518 /* It could happen that the window was already closed */
519 if (!GTK_WIDGET_VISIBLE (w))
522 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
524 insert = gtk_text_buffer_get_insert (priv->text_buffer);
525 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
527 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
528 offset_min = priv->msg_body->allocation.y + rectangle.y;
529 offset_max = offset_min + rectangle.height;
531 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
532 offset_min = MAX (offset_min - 48, 0);
533 offset_max = MIN (offset_max + 48, vadj->upper);
535 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
537 priv->correct_scroll_idle = 0;
542 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
544 ModestMsgEditWindowPrivate *priv;
546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
548 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
551 if (priv->correct_scroll_idle > 0) {
555 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
556 (GSourceFunc) correct_scroll_without_drag_check_idle,
562 correct_scroll (ModestMsgEditWindow *w)
564 ModestMsgEditWindowPrivate *priv;
566 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
567 if (gtk_grab_get_current () == priv->msg_body) {
568 if (priv->scroll_drag_timeout_id == 0) {
569 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
571 (GSourceFunc) scroll_drag_timeout,
578 correct_scroll_without_drag_check (w, TRUE);
582 text_buffer_end_user_action (GtkTextBuffer *buffer,
583 ModestMsgEditWindow *userdata)
586 correct_scroll (userdata);
590 text_buffer_mark_set (GtkTextBuffer *buffer,
593 ModestMsgEditWindow *userdata)
595 gtk_text_buffer_begin_user_action (buffer);
596 gtk_text_buffer_end_user_action (buffer);
600 cut_clipboard_check (GtkTextView *text_view,
603 GtkTextBuffer *buffer;
605 buffer = gtk_text_view_get_buffer (text_view);
606 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
607 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
612 copy_clipboard_check (GtkTextView *text_view,
615 GtkTextBuffer *buffer;
617 buffer = gtk_text_view_get_buffer (text_view);
618 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
619 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
624 attachment_deleted (ModestAttachmentsView *attachments_view,
627 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
632 connect_signals (ModestMsgEditWindow *obj)
634 ModestMsgEditWindowPrivate *priv;
636 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
638 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
639 G_CALLBACK (text_buffer_refresh_attributes), obj);
640 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
641 G_CALLBACK (text_buffer_can_undo), obj);
642 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
643 G_CALLBACK (text_buffer_can_redo), obj);
644 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
645 G_CALLBACK (body_changed), obj);
646 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
647 G_CALLBACK (body_changed), obj);
648 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
649 G_CALLBACK (text_buffer_end_user_action), obj);
650 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
651 G_CALLBACK (text_buffer_mark_set), obj);
652 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
653 G_CALLBACK (text_buffer_apply_tag), obj);
654 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
655 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
656 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
657 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
658 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
659 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
661 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
662 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
663 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
664 G_CALLBACK (from_field_changed), obj);
666 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
667 G_CALLBACK (msg_body_focus), obj);
668 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
669 G_CALLBACK (msg_body_focus), obj);
670 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
671 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
672 "changed", G_CALLBACK (recpt_field_changed), obj);
673 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
674 "changed", G_CALLBACK (recpt_field_changed), obj);
675 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
676 "changed", G_CALLBACK (recpt_field_changed), obj);
677 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
678 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
679 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
681 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
682 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
684 priv->clipboard_change_handler_id =
685 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
686 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
687 priv->default_clipboard_change_handler_id =
688 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
689 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
691 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
692 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
693 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
697 init_wp_text_view_style ()
699 static gboolean initialized = FALSE;
702 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
708 init_window (ModestMsgEditWindow *obj)
710 GtkWidget *to_caption, *subject_caption;
711 GtkWidget *main_vbox;
712 GtkWidget *add_attachment_align;
713 ModestMsgEditWindowPrivate *priv;
714 GtkActionGroup *action_group;
715 ModestWindowPrivate *parent_priv;
716 GdkPixbuf *window_icon = NULL;
717 GError *error = NULL;
719 GtkSizeGroup *title_size_group;
720 GtkSizeGroup *value_size_group;
721 GtkWidget *attachment_icon;
722 GtkWidget *window_box;
723 GtkWidget *window_align;
724 #if (GTK_MINOR_VERSION >= 10)
725 GdkAtom deserialize_type;
728 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
729 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
731 parent_priv->ui_manager = gtk_ui_manager_new();
732 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
733 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
735 /* Add common actions */
736 gtk_action_group_add_actions (action_group,
737 modest_msg_edit_action_entries,
738 G_N_ELEMENTS (modest_msg_edit_action_entries),
740 gtk_action_group_add_actions (action_group,
741 hildon2_msg_edit_action_entries,
742 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
744 gtk_action_group_add_toggle_actions (action_group,
745 modest_msg_edit_toggle_action_entries,
746 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
748 gtk_action_group_add_radio_actions (action_group,
749 modest_msg_edit_alignment_radio_action_entries,
750 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
752 G_CALLBACK (modest_ui_actions_on_change_justify),
754 gtk_action_group_add_radio_actions (action_group,
755 modest_msg_edit_priority_action_entries,
756 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
758 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
760 gtk_action_group_add_radio_actions (action_group,
761 modest_msg_edit_file_format_action_entries,
762 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
763 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
764 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
766 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
767 g_object_unref (action_group);
769 /* Load the UI definition */
770 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
773 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
774 g_clear_error (&error);
777 /* Add accelerators */
778 gtk_window_add_accel_group (GTK_WINDOW (obj),
779 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
781 parent_priv->menubar = NULL;
783 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
784 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
786 /* Note: This ModestPairList* must exist for as long as the picker
787 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
788 * so it can't know how to manage its memory. */
789 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
790 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
792 modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group,
793 _("mail_va_from"), priv->from_field);
795 priv->to_field = modest_recpt_editor_new ();
796 priv->cc_field = modest_recpt_editor_new ();
797 priv->bcc_field = modest_recpt_editor_new ();
798 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
799 priv->priority_icon = gtk_image_new ();
800 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
801 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
802 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
803 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
804 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
805 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
806 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
807 priv->add_attachment_button = hildon_button_new (MODEST_EDITABLE_SIZE, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
808 gtk_widget_set_size_request (priv->add_attachment_button, ATTACHMENT_BUTTON_WIDTH, -1);
809 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
810 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
811 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
812 hildon_button_set_image (HILDON_BUTTON (priv->add_attachment_button), attachment_icon);
813 add_attachment_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
814 gtk_alignment_set_padding (GTK_ALIGNMENT (add_attachment_align), 0, 0, MODEST_MARGIN_DEFAULT, 0);
815 gtk_container_add (GTK_CONTAINER (add_attachment_align), priv->add_attachment_button);
816 gtk_box_pack_start (GTK_BOX (priv->subject_box), add_attachment_align, FALSE, FALSE, 0);
817 priv->attachments_view = modest_attachments_view_new (NULL);
818 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
819 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
821 priv->header_box = gtk_vbox_new (FALSE, 0);
823 to_caption = modest_maemo_utils_create_captioned_with_size_type
824 (title_size_group, value_size_group,
825 _("mail_va_to"), FALSE, priv->to_field,
826 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
827 priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type
828 (title_size_group, value_size_group,
829 _("mail_va_cc"), FALSE, priv->cc_field,
830 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
831 priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
832 (title_size_group, value_size_group,
833 _("mail_va_hotfix1"), FALSE, priv->bcc_field,
834 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
835 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
836 _("mail_va_subject"), FALSE, priv->subject_box);
837 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
838 _("mail_va_attachment"),
840 priv->attachments_view,
841 HILDON_SIZE_AUTO_WIDTH |
842 HILDON_SIZE_AUTO_HEIGHT);
843 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
844 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
845 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
846 g_object_unref (title_size_group);
847 g_object_unref (value_size_group);
849 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
850 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
851 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
852 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
853 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
854 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
855 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
857 init_wp_text_view_style ();
859 priv->msg_body = modest_wp_text_view_new ();
862 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
863 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
864 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
865 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
866 #if (GTK_MINOR_VERSION >= 10)
867 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
868 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
870 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
871 deserialize_type, TRUE);
873 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
875 priv->find_toolbar = hildon_find_toolbar_new (NULL);
876 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
878 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
880 priv->pannable = hildon_pannable_area_new ();
882 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
883 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
884 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
886 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
887 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
888 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
890 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
891 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
893 window_box = gtk_vbox_new (FALSE, 0);
894 gtk_container_add (GTK_CONTAINER(obj), window_box);
896 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
898 /* Set window icon */
899 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
901 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
902 g_object_unref (window_icon);
907 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
909 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
911 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
912 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
913 priv->clipboard_change_handler_id))
914 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
915 priv->clipboard_change_handler_id);
916 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
917 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
918 priv->default_clipboard_change_handler_id))
919 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
920 priv->default_clipboard_change_handler_id);
922 if (priv->account_removed_handler_id &&
923 g_signal_handler_is_connected (modest_runtime_get_account_store (),
924 priv->account_removed_handler_id))
925 g_signal_handler_disconnect(modest_runtime_get_account_store (),
926 priv->account_removed_handler_id);
930 modest_msg_edit_window_finalize (GObject *obj)
932 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
934 /* Sanity check: shouldn't be needed, the window mgr should
935 call this function before */
936 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
938 if (priv->font_dialog != NULL) {
939 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
942 if (priv->clipboard_text != NULL) {
943 g_free (priv->clipboard_text);
944 priv->clipboard_text = NULL;
947 if (priv->draft_msg != NULL) {
948 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
949 if (TNY_IS_HEADER (header)) {
950 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
951 modest_window_mgr_unregister_header (mgr, header);
953 g_object_unref (priv->draft_msg);
954 priv->draft_msg = NULL;
956 if (priv->outbox_msg != NULL) {
957 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
958 if (TNY_IS_HEADER (header)) {
959 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
960 modest_window_mgr_unregister_header (mgr, header);
962 g_object_unref (priv->outbox_msg);
963 priv->outbox_msg = NULL;
965 if (priv->correct_scroll_idle > 0) {
966 g_source_remove (priv->correct_scroll_idle);
967 priv->correct_scroll_idle = 0;
969 if (priv->scroll_drag_timeout_id > 0) {
970 g_source_remove (priv->scroll_drag_timeout_id);
971 priv->scroll_drag_timeout_id = 0;
973 if (priv->clipboard_owner_idle > 0) {
974 g_source_remove (priv->clipboard_owner_idle);
975 priv->clipboard_owner_idle = 0;
977 if (priv->original_account_name)
978 g_free (priv->original_account_name);
979 g_free (priv->msg_uid);
980 g_free (priv->last_search);
981 g_free (priv->references);
982 g_free (priv->in_reply_to);
983 g_object_unref (priv->faces_model);
984 g_object_unref (priv->sizes_model);
985 g_object_unref (priv->attachments);
986 g_object_unref (priv->images);
988 /* This had to stay alive for as long as the picker that used it: */
989 modest_pair_list_free (priv->from_field_protos);
991 G_OBJECT_CLASS(parent_class)->finalize (obj);
995 pixbuf_size_prepared (GdkPixbufLoader *loader,
998 ModestMsgEditWindow *self)
1000 gint new_height, new_width;
1003 new_height = height;
1007 if (width > IMAGE_MAX_WIDTH) {
1008 new_height = height * IMAGE_MAX_WIDTH / width;
1009 new_width = IMAGE_MAX_WIDTH;
1012 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1016 pixbuf_from_stream (TnyStream *stream,
1017 const gchar *mime_type,
1018 guint64 *stream_size,
1019 ModestMsgEditWindow *self)
1021 GdkPixbufLoader *loader;
1024 GError *error = NULL;
1028 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1030 if (loader == NULL) {
1035 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1037 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1039 tny_stream_reset (TNY_STREAM (stream));
1040 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1041 unsigned char read_buffer[128];
1043 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1045 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1048 /* Allow some UI responsiveness */
1049 while (gtk_events_pending ())
1050 gtk_main_iteration ();
1052 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1054 gdk_pixbuf_loader_close (loader, &error);
1057 g_error_free (error);
1058 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1060 g_object_ref (pixbuf);
1061 g_object_unref (loader);
1066 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1067 GdkPixbuf *new_pixbuf;
1069 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1070 gdk_pixbuf_get_width (pixbuf);
1071 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1072 g_object_unref (pixbuf);
1073 pixbuf = new_pixbuf;
1077 *stream_size = size;
1083 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1085 ModestMsgEditWindowPrivate *priv;
1088 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1090 g_object_ref (self);
1091 for (iter = tny_list_create_iterator (attachments);
1092 !tny_iterator_is_done (iter);
1093 tny_iterator_next (iter)) {
1094 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1095 const gchar *cid = tny_mime_part_get_content_id (part);
1096 const gchar *mime_type = tny_mime_part_get_content_type (part);
1097 if ((cid != NULL)&&(mime_type != NULL)) {
1098 guint64 stream_size;
1099 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1100 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1103 g_object_unref (stream);
1105 if (pixbuf != NULL) {
1106 priv->images_count ++;
1107 priv->images_size += stream_size;
1108 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1109 g_object_unref (pixbuf);
1112 g_object_unref (part);
1114 g_object_unref (iter);
1115 g_object_unref (self);
1119 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1121 TnyMimePart *parent = NULL;
1122 const gchar *content_type = NULL;
1123 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1125 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1127 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1128 parent = g_object_ref (msg);
1129 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1130 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1133 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1134 iter = tny_list_create_iterator (parts);
1135 while (!tny_iterator_is_done (iter)) {
1137 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1138 content_type = tny_mime_part_get_content_type (part);
1139 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1143 g_object_unref (part);
1145 tny_iterator_next (iter);
1147 g_object_unref (iter);
1148 g_object_unref (parts);
1151 if (parent != NULL) {
1152 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1155 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1156 iter = tny_list_create_iterator (parts);
1157 while (!tny_iterator_is_done (iter)) {
1159 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1160 content_type = tny_mime_part_get_content_type (part);
1161 if (content_type && g_str_has_prefix (content_type, "image/")) {
1162 tny_list_prepend (priv->images, (GObject *) part);
1164 g_object_unref (part);
1165 tny_iterator_next (iter);
1167 g_object_unref (iter);
1168 g_object_unref (parts);
1169 g_object_unref (parent);
1174 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1177 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1179 for (iter = tny_list_create_iterator (attachments) ;
1180 !tny_iterator_is_done (iter);
1181 tny_iterator_next (iter)) {
1182 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1183 const gchar *cid = tny_mime_part_get_content_id (part);
1185 char *invalid = NULL;
1186 gint int_cid = strtol (cid, &invalid, 10);
1187 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1188 priv->next_cid = int_cid + 1;
1191 g_object_unref (part);
1193 g_object_unref (iter);
1197 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1200 gchar *to, *cc, *bcc, *subject;
1202 ModestMsgEditWindowPrivate *priv;
1203 ModestWindowPrivate *parent_priv;
1205 TnyHeaderFlags priority_flags;
1206 TnyFolder *msg_folder;
1207 gboolean is_html = FALSE;
1208 gboolean field_view_set;
1210 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1211 g_return_if_fail (TNY_IS_MSG (msg));
1213 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1214 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1216 header = tny_msg_get_header (msg);
1217 to = tny_header_dup_to (header);
1218 cc = tny_header_dup_cc (header);
1219 bcc = tny_header_dup_bcc (header);
1220 subject = tny_header_dup_subject (header);
1222 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1223 priority_flags = tny_header_get_priority (header);
1226 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1228 field_view_set = TRUE;
1230 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1231 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1232 gtk_widget_show (priv->cc_caption);
1233 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1234 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1235 gtk_widget_hide (priv->cc_caption);
1236 field_view_set = FALSE;
1238 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1240 field_view_set = TRUE;
1242 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1243 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1244 gtk_widget_show (priv->bcc_caption);
1245 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1246 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1247 gtk_widget_hide (priv->bcc_caption);
1248 field_view_set = FALSE;
1250 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1254 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1255 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1258 update_window_title (self);
1260 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1261 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1263 if ((body == NULL)||(body[0] == '\0')) {
1265 body = modest_text_utils_convert_to_html ("");
1268 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1269 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1272 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1275 /* Add attachments to the view */
1276 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1277 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1278 if (tny_list_get_length (priv->attachments) == 0) {
1279 gtk_widget_hide (priv->attachments_caption);
1281 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1282 gtk_widget_show_all (priv->attachments_caption);
1284 get_related_images (self, msg);
1285 update_next_cid (self, priv->attachments);
1286 update_next_cid (self, priv->images);
1287 replace_with_images (self, priv->images);
1289 if (preserve_is_rich && !is_html) {
1290 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1291 /* Get the default format required from configuration */
1292 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1293 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1296 /* Set the default focus depending on having already a To: field or not */
1297 if ((!to)||(*to == '\0')) {
1298 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1300 gtk_widget_grab_focus (priv->msg_body);
1303 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1305 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1306 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1308 modest_msg_edit_window_set_modified (self, FALSE);
1310 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1311 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1312 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1313 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1315 if (priv->msg_uid) {
1316 g_free (priv->msg_uid);
1317 priv->msg_uid = NULL;
1320 /* we should set a reference to the incoming message if it is a draft */
1321 msg_folder = tny_msg_get_folder (msg);
1323 if (modest_tny_folder_is_local_folder (msg_folder)) {
1324 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1325 if (type == TNY_FOLDER_TYPE_INVALID)
1326 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1328 if (type == TNY_FOLDER_TYPE_DRAFTS)
1329 priv->draft_msg = g_object_ref(msg);
1330 if (type == TNY_FOLDER_TYPE_OUTBOX)
1331 priv->outbox_msg = g_object_ref(msg);
1332 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1334 g_object_unref (msg_folder);
1345 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1347 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1348 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1349 GtkWidget *placeholder;
1350 GtkWidget *tool_item;
1355 GtkWidget *sizes_menu;
1356 GtkWidget *fonts_menu;
1362 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1363 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1364 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1365 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1367 /* Font color placeholder */
1368 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1369 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1372 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1373 priv->font_color_button = hildon_color_button_new ();
1374 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1375 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1376 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1377 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1378 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1379 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1380 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1381 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1383 G_CALLBACK (modest_msg_edit_window_color_button_change),
1386 /* Font size and face placeholder */
1387 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1388 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1390 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1391 priv->size_tool_button_label = gtk_label_new (NULL);
1392 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1393 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1394 size_text, "</span>", NULL);
1395 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1396 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1398 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1399 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1400 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1401 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1402 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1403 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1404 gtk_widget_set_sensitive (arrow, FALSE);
1405 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1406 sizes_menu = gtk_menu_new ();
1407 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1408 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1411 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1412 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1414 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1418 if (wp_font_size[size_index] == 12)
1419 priv->current_size_index = size_index;
1423 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1424 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1425 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1426 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1427 priv->font_size_toolitem = tool_item;
1430 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1431 priv->font_tool_button_label = gtk_label_new (NULL);
1432 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1433 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1434 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1436 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1437 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1438 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1439 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1440 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1441 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1442 gtk_widget_set_sensitive (arrow, FALSE);
1443 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1444 fonts_menu = gtk_menu_new ();
1445 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1446 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1449 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1451 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1452 0, wp_get_font_name (font_index),
1455 if (font_index == DEFAULT_FONT)
1456 priv->current_face_index = font_index;
1458 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1459 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1460 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1461 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1462 priv->font_face_toolitem = tool_item;
1464 /* Set expand and homogeneous for remaining items */
1465 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1466 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1467 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1468 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1469 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1470 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1471 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1472 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1473 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1475 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1476 will not show the tool items added to the placeholders) */
1477 gtk_widget_show_all (parent_priv->toolbar);
1479 /* Set the no show all *after* showing all items. We do not
1480 want the toolbar to be shown with a show all because it
1481 could go agains the gconf setting regarding showing or not
1482 the toolbar of the editor window */
1483 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1489 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1492 ModestWindowPrivate *parent_priv;
1493 ModestMsgEditWindowPrivate *priv;
1494 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1495 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1496 ModestWindowMgr *mgr = NULL;
1498 g_return_val_if_fail (msg, NULL);
1499 g_return_val_if_fail (account_name, NULL);
1501 mgr = modest_runtime_get_window_mgr ();
1503 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1505 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1506 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1508 /* Menubar. Update the state of some toggles */
1509 priv->from_field_protos = get_transports ();
1510 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1511 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1512 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1513 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1515 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1516 hildon_touch_selector_get_current_text
1517 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1518 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1519 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1522 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1524 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1526 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1528 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1530 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1531 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1532 /* Add common dimming rules */
1533 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1534 modest_msg_edit_window_toolbar_dimming_entries,
1535 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1536 MODEST_WINDOW (obj));
1537 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1538 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1539 MODEST_WINDOW (obj));
1540 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1541 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1542 MODEST_WINDOW (obj));
1543 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1544 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1545 MODEST_WINDOW (obj));
1546 /* Insert dimming rules group for this window */
1547 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1548 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1550 /* Setup app menu */
1551 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1553 /* Checks the dimming rules */
1554 g_object_unref (toolbar_rules_group);
1555 g_object_unref (clipboard_rules_group);
1556 gtk_widget_hide (priv->priority_icon);
1557 gtk_widget_queue_resize (priv->subject_box);
1558 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1560 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1562 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1563 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1564 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1565 priv->update_caption_visibility = TRUE;
1567 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1569 /* Track account-removed signal, this window should be closed
1570 in the case we're creating a mail associated to the account
1572 priv->account_removed_handler_id =
1573 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1575 G_CALLBACK(on_account_removed),
1578 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1580 return (ModestWindow*) obj;
1584 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1586 GString **string_buffer = (GString **) user_data;
1588 *string_buffer = g_string_append (*string_buffer, buffer);
1594 * @result: A new string which should be freed with g_free().
1597 get_formatted_data (ModestMsgEditWindow *edit_window)
1599 ModestMsgEditWindowPrivate *priv;
1600 GString *string_buffer = g_string_new ("");
1602 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1604 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1606 modest_text_utils_hyperlinkify (string_buffer);
1608 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1610 return g_string_free (string_buffer, FALSE);
1615 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1618 const gchar *account_name;
1619 ModestMsgEditWindowPrivate *priv;
1620 TnyIterator *att_iter;
1622 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1624 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1626 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1627 g_return_val_if_fail (account_name, NULL);
1630 /* don't free these (except from) */
1631 data = g_slice_new0 (MsgData);
1632 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1634 data->account_name = g_strdup (account_name);
1635 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1636 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1637 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1638 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1639 data->references = g_strdup (priv->references);
1640 data->in_reply_to = g_strdup (priv->in_reply_to);
1641 if (priv->draft_msg) {
1642 data->draft_msg = g_object_ref (priv->draft_msg);
1643 } else if (priv->outbox_msg) {
1644 data->draft_msg = g_object_ref (priv->outbox_msg);
1646 data->draft_msg = NULL;
1649 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1651 gtk_text_buffer_get_bounds (buf, &b, &e);
1652 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1654 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1655 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1657 data->html_body = NULL;
1659 /* deep-copy the data */
1660 att_iter = tny_list_create_iterator (priv->attachments);
1661 data->attachments = NULL;
1662 while (!tny_iterator_is_done (att_iter)) {
1663 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1664 if (!(TNY_IS_MIME_PART(part))) {
1665 g_warning ("strange data in attachment list");
1666 g_object_unref (part);
1667 tny_iterator_next (att_iter);
1670 data->attachments = g_list_append (data->attachments,
1672 tny_iterator_next (att_iter);
1674 g_object_unref (att_iter);
1676 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1677 att_iter = tny_list_create_iterator (priv->images);
1678 data->images = NULL;
1679 while (!tny_iterator_is_done (att_iter)) {
1680 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1682 if (!(TNY_IS_MIME_PART(part))) {
1683 g_warning ("strange data in attachment list");
1684 g_object_unref (part);
1685 tny_iterator_next (att_iter);
1688 cid = tny_mime_part_get_content_id (part);
1690 gchar *image_tag_id;
1691 GtkTextTag *image_tag;
1693 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1694 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1695 g_free (image_tag_id);
1697 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1699 ((gtk_text_iter_has_tag (&iter, image_tag))||
1700 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1701 data->images = g_list_append (data->images,
1702 g_object_ref (part));
1704 g_object_unref (part);
1705 tny_iterator_next (att_iter);
1707 g_object_unref (att_iter);
1709 data->priority_flags = priv->priority_flags;
1716 unref_gobject (GObject *obj, gpointer data)
1718 if (!G_IS_OBJECT(obj))
1720 g_object_unref (obj);
1724 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1727 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1735 g_free (data->from);
1736 g_free (data->subject);
1737 g_free (data->plain_body);
1738 g_free (data->html_body);
1739 g_free (data->account_name);
1740 g_free (data->references);
1741 g_free (data->in_reply_to);
1743 if (data->draft_msg != NULL) {
1744 g_object_unref (data->draft_msg);
1745 data->draft_msg = NULL;
1748 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1749 g_list_free (data->attachments);
1750 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1751 g_list_free (data->images);
1753 g_slice_free (MsgData, data);
1757 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1759 guint64 *parts_size)
1761 ModestMsgEditWindowPrivate *priv;
1763 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1765 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1767 /* TODO: add images */
1768 *parts_size += priv->images_size;
1769 *parts_count += priv->images_count;
1774 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1777 ModestMsgEditWindowPrivate *priv = NULL;
1778 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1780 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1782 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1784 return MODEST_MSG_EDIT_FORMAT_HTML;
1786 return MODEST_MSG_EDIT_FORMAT_TEXT;
1790 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1791 ModestMsgEditFormat format)
1793 ModestMsgEditWindowPrivate *priv;
1795 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1796 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1799 case MODEST_MSG_EDIT_FORMAT_HTML:
1800 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1802 case MODEST_MSG_EDIT_FORMAT_TEXT:
1803 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1806 g_return_if_reached ();
1810 ModestMsgEditFormatState *
1811 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1813 ModestMsgEditFormatState *format_state = NULL;
1814 ModestMsgEditWindowPrivate *priv;
1815 WPTextBufferFormat *buffer_format;
1817 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1819 buffer_format = g_new0 (WPTextBufferFormat, 1);
1820 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1822 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1824 format_state = g_new0 (ModestMsgEditFormatState, 1);
1825 format_state->bold = buffer_format->bold&0x1;
1826 format_state->italics = buffer_format->italic&0x1;
1827 format_state->bullet = buffer_format->bullet&0x1;
1828 format_state->color = buffer_format->color;
1829 format_state->font_size = buffer_format->font_size;
1830 format_state->font_family = wp_get_font_name (buffer_format->font);
1831 format_state->justification = buffer_format->justification;
1832 g_free (buffer_format);
1834 return format_state;
1839 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1840 const ModestMsgEditFormatState *format_state)
1842 ModestMsgEditWindowPrivate *priv;
1843 WPTextBufferFormat *buffer_format;
1844 WPTextBufferFormat *current_format;
1846 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1847 g_return_if_fail (format_state != NULL);
1849 buffer_format = g_new0 (WPTextBufferFormat, 1);
1850 current_format = g_new0 (WPTextBufferFormat, 1);
1852 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1853 gtk_widget_grab_focus (priv->msg_body);
1854 buffer_format->bold = (format_state->bold != FALSE);
1855 buffer_format->italic = (format_state->italics != FALSE);
1856 buffer_format->color = format_state->color;
1857 buffer_format->font_size = format_state->font_size;
1858 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1859 buffer_format->justification = format_state->justification;
1860 buffer_format->bullet = format_state->bullet;
1862 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1864 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1865 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1866 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1867 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1868 buffer_format->cs.font = (buffer_format->font != current_format->font);
1869 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1870 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1872 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1873 if (buffer_format->cs.bold) {
1874 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1875 GINT_TO_POINTER (buffer_format->bold&0x1));
1877 if (buffer_format->cs.italic) {
1878 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1879 GINT_TO_POINTER (buffer_format->italic&0x1));
1881 if (buffer_format->cs.color) {
1882 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1883 GINT_TO_POINTER (&(buffer_format->color)));
1885 if (buffer_format->cs.font_size) {
1886 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1887 GINT_TO_POINTER (buffer_format->font_size));
1889 if (buffer_format->cs.justification) {
1890 switch (buffer_format->justification) {
1891 case GTK_JUSTIFY_LEFT:
1892 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1893 GINT_TO_POINTER(TRUE));
1895 case GTK_JUSTIFY_CENTER:
1896 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1897 GINT_TO_POINTER(TRUE));
1899 case GTK_JUSTIFY_RIGHT:
1900 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1901 GINT_TO_POINTER(TRUE));
1908 if (buffer_format->cs.font) {
1909 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1910 GINT_TO_POINTER (buffer_format->font));
1912 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1913 if (buffer_format->cs.bullet) {
1914 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1915 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1917 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1919 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1921 g_free (buffer_format);
1922 g_free (current_format);
1924 /* Check dimming rules */
1925 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1926 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1930 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1932 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1934 ModestWindowPrivate *parent_priv;
1935 ModestMsgEditWindowPrivate *priv;
1937 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1938 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1940 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1941 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1942 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1943 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1945 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1946 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1947 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1950 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1952 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1953 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1955 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1956 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1958 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1959 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1962 switch (buffer_format->justification)
1964 case GTK_JUSTIFY_LEFT:
1965 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1967 case GTK_JUSTIFY_CENTER:
1968 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1970 case GTK_JUSTIFY_RIGHT:
1971 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1978 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1980 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1981 G_CALLBACK (modest_msg_edit_window_color_button_change),
1983 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1984 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1985 G_CALLBACK (modest_msg_edit_window_color_button_change),
1988 if (priv->current_size_index != buffer_format->font_size) {
1992 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1993 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1997 priv->current_size_index = buffer_format->font_size;
1999 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2000 markup = g_strconcat ("<span font_family='Sans'>",
2001 size_text, "</span>", NULL);
2003 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2007 gtk_tree_path_free (path);
2010 if (priv->current_face_index != buffer_format->font) {
2014 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2015 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2019 priv->current_face_index = buffer_format->font;
2020 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2021 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2022 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2029 g_free (buffer_format);
2033 #ifdef MODEST_HILDON_VERSION_0
2035 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2038 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2039 ModestMsgEditWindowPrivate *priv;
2040 GtkWidget *dialog = NULL;
2042 GdkColor *new_color = NULL;
2044 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2045 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2047 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2048 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2049 g_free (buffer_format);
2051 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2052 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2053 if (new_color != NULL) {
2054 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2055 (gpointer) new_color);
2058 gtk_widget_destroy (dialog);
2063 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2066 ModestMsgEditWindowPrivate *priv;
2067 GtkWidget *dialog = NULL;
2069 GdkColor *old_color = NULL;
2070 const GdkColor *new_color = NULL;
2072 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2073 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2075 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2076 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2078 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2079 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2080 if (new_color != NULL)
2081 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2083 gtk_widget_destroy (dialog);
2089 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2092 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2093 ModestMsgEditWindowPrivate *priv;
2094 GtkWidget *dialog = NULL;
2096 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2097 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2099 dialog = hildon_color_chooser_new ();
2100 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2101 g_free (buffer_format);
2103 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2105 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2106 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2109 gtk_widget_destroy (dialog);
2114 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2117 ModestMsgEditWindowPrivate *priv;
2118 GtkWidget *dialog = NULL;
2119 GdkColor *old_color = NULL;
2121 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2122 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2124 dialog = hildon_color_chooser_new ();
2125 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2127 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2129 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2130 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2132 gtk_widget_destroy (dialog);
2135 #endif /*!MODEST_HILDON_VERSION_0*/
2140 create_stream_for_uri (const gchar* uri)
2145 TnyStream *result = NULL;
2147 GnomeVFSHandle *handle = NULL;
2148 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2149 if (test == GNOME_VFS_OK) {
2150 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2151 /* Streams over OBEX (Bluetooth) are not seekable but
2152 * we expect them to be (we might need to read them
2153 * several times). So if this is a Bluetooth URI just
2154 * read the whole file into memory (this is not a fast
2155 * protocol so we can assume that these files are not
2156 * going to be very big) */
2157 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2158 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2159 TnyStream *memstream = tny_camel_mem_stream_new ();
2160 tny_stream_write_to_stream (vfssstream, memstream);
2161 g_object_unref (vfssstream);
2164 result = vfssstream;
2172 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2175 ModestMsgEditWindowPrivate *priv;
2176 GtkWidget *dialog = NULL;
2178 GSList *uris = NULL;
2179 GSList *uri_node = NULL;
2181 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2183 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2184 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2185 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2187 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2189 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2190 GTK_WINDOW (dialog), GTK_WINDOW (window));
2192 response = gtk_dialog_run (GTK_DIALOG (dialog));
2194 case GTK_RESPONSE_OK:
2195 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2200 gtk_widget_destroy (dialog);
2202 g_object_ref (window);
2203 /* The operation could take some time so allow the dialog to be closed */
2204 while (gtk_events_pending ())
2205 gtk_main_iteration ();
2207 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2209 GnomeVFSHandle *handle = NULL;
2210 GnomeVFSResult result;
2211 GtkTextIter position;
2212 GtkTextMark *insert_mark;
2214 uri = (const gchar *) uri_node->data;
2215 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2216 if (result == GNOME_VFS_OK) {
2218 GnomeVFSFileInfo *info;
2219 gchar *filename, *basename, *escaped_filename;
2220 TnyMimePart *mime_part;
2222 const gchar *mime_type = NULL;
2223 GnomeVFSURI *vfs_uri;
2224 guint64 stream_size;
2226 gnome_vfs_close (handle);
2227 vfs_uri = gnome_vfs_uri_new (uri);
2229 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2230 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2231 g_free (escaped_filename);
2232 gnome_vfs_uri_unref (vfs_uri);
2233 info = gnome_vfs_file_info_new ();
2235 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2236 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2238 mime_type = gnome_vfs_file_info_get_mime_type (info);
2240 mime_part = tny_platform_factory_new_mime_part
2241 (modest_runtime_get_platform_factory ());
2243 TnyStream *stream = create_stream_for_uri (uri);
2245 if (stream == NULL) {
2247 modest_platform_information_banner (NULL, NULL,
2248 _FM("sfil_ib_opening_not_allowed"));
2250 g_object_unref (mime_part);
2251 gnome_vfs_file_info_unref (info);
2255 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2257 content_id = g_strdup_printf ("%d", priv->next_cid);
2258 tny_mime_part_set_content_id (mime_part, content_id);
2259 g_free (content_id);
2262 basename = g_path_get_basename (filename);
2263 tny_mime_part_set_filename (mime_part, basename);
2266 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2268 if (pixbuf != NULL) {
2269 priv->images_size += stream_size;
2270 priv->images_count ++;
2271 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2272 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2273 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2274 tny_mime_part_get_content_id (mime_part), pixbuf);
2275 g_object_unref (pixbuf);
2277 tny_list_prepend (priv->images, (GObject *) mime_part);
2278 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2280 modest_platform_information_banner (NULL, NULL,
2281 _("mail_ib_file_operation_failed"));
2285 g_object_unref (mime_part);
2286 gnome_vfs_file_info_unref (info);
2290 g_object_unref (window);
2294 on_attach_file_response (GtkDialog *dialog,
2298 GSList *uris = NULL;
2300 GnomeVFSFileSize total_size, allowed_size;
2301 ModestMsgEditWindow *window;
2302 ModestMsgEditWindowPrivate *priv;
2307 case GTK_RESPONSE_OK:
2308 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2314 window = MODEST_MSG_EDIT_WINDOW (user_data);
2315 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2317 /* allowed size is the maximum size - what's already there */
2318 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2319 &att_num, &att_size);
2320 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2323 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2325 const gchar *uri = (const gchar *) uri_node->data;
2328 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2330 if (total_size > allowed_size) {
2331 g_warning ("%s: total size: %u",
2332 __FUNCTION__, (unsigned int)total_size);
2335 allowed_size -= total_size;
2337 g_slist_foreach (uris, (GFunc) g_free, NULL);
2338 g_slist_free (uris);
2340 gtk_widget_destroy (GTK_WIDGET (dialog));
2344 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2346 GtkWidget *dialog = NULL;
2347 ModestMsgEditWindowPrivate *priv;
2349 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2351 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2353 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2356 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2357 GTK_FILE_CHOOSER_ACTION_OPEN);
2358 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2359 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2360 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2361 GTK_WINDOW (dialog), GTK_WINDOW (window));
2363 /* Connect to response & show */
2364 g_signal_connect (dialog, "response",
2365 G_CALLBACK (on_attach_file_response), window);
2366 gtk_widget_show (dialog);
2371 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2373 GnomeVFSFileSize allowed_size)
2376 GnomeVFSHandle *handle = NULL;
2377 ModestMsgEditWindowPrivate *priv;
2378 GnomeVFSResult result;
2379 GnomeVFSFileSize size = 0;
2380 g_return_val_if_fail (window, 0);
2381 g_return_val_if_fail (uri, 0);
2383 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2385 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2386 if (result == GNOME_VFS_OK) {
2387 TnyMimePart *mime_part;
2389 const gchar *mime_type = NULL;
2391 gchar *escaped_filename;
2394 GnomeVFSFileInfo *info;
2395 GnomeVFSURI *vfs_uri;
2397 gnome_vfs_close (handle);
2398 vfs_uri = gnome_vfs_uri_new (uri);
2401 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2402 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2403 g_free (escaped_filename);
2404 gnome_vfs_uri_unref (vfs_uri);
2406 info = gnome_vfs_file_info_new ();
2408 if (gnome_vfs_get_file_info (uri,
2410 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2412 mime_type = gnome_vfs_file_info_get_mime_type (info);
2413 mime_part = tny_platform_factory_new_mime_part
2414 (modest_runtime_get_platform_factory ());
2416 /* try to get the attachment's size; this may fail for weird
2417 * file systems, like obex, upnp... */
2418 if (allowed_size != 0 &&
2419 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2421 if (size > allowed_size) {
2422 modest_platform_information_banner (NULL, NULL,
2423 _FM("sfil_ib_opening_not_allowed"));
2428 g_warning ("%s: could not get attachment size", __FUNCTION__);
2430 stream = create_stream_for_uri (uri);
2432 if (stream == NULL) {
2434 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2436 g_object_unref (mime_part);
2438 gnome_vfs_file_info_unref (info);
2442 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2443 g_object_unref (stream);
2445 content_id = g_strdup_printf ("%d", priv->next_cid);
2446 tny_mime_part_set_content_id (mime_part, content_id);
2447 g_free (content_id);
2450 basename = g_path_get_basename (filename);
2451 tny_mime_part_set_filename (mime_part, basename);
2454 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2455 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2457 info->size == 0, info->size);
2458 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2459 gtk_widget_show_all (priv->attachments_caption);
2460 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2462 g_object_unref (mime_part);
2463 gnome_vfs_file_info_unref (info);
2470 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2473 ModestMsgEditWindowPrivate *priv;
2476 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2477 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2479 if (att_list == NULL) {
2480 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2481 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2482 g_object_unref (att_list);
2487 g_object_ref (att_list);
2490 if (tny_list_get_length (att_list) == 0) {
2491 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2493 gboolean dialog_response;
2494 gchar *message = NULL;
2495 gchar *filename = NULL;
2497 if (tny_list_get_length (att_list) == 1) {
2499 iter = tny_list_create_iterator (att_list);
2500 part = (TnyMimePart *) tny_iterator_get_current (iter);
2501 g_object_unref (iter);
2502 if (TNY_IS_MSG (part)) {
2503 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2505 filename = tny_header_dup_subject (header);
2506 g_object_unref (header);
2508 if (filename == NULL) {
2509 filename = g_strdup (_("mail_va_no_subject"));
2512 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2514 g_object_unref (part);
2516 filename = g_strdup ("");
2518 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2519 "emev_nc_delete_attachments",
2520 tny_list_get_length (att_list)), filename);
2523 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2527 if (dialog_response != GTK_RESPONSE_OK) {
2528 g_object_unref (att_list);
2532 for (iter = tny_list_create_iterator (att_list);
2533 !tny_iterator_is_done (iter);
2534 tny_iterator_next (iter)) {
2535 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2536 const gchar *att_id;
2537 tny_list_remove (priv->attachments, (GObject *) mime_part);
2539 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2541 if (tny_list_get_length (priv->attachments) == 0)
2542 gtk_widget_hide (priv->attachments_caption);
2543 att_id = tny_mime_part_get_content_id (mime_part);
2545 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2547 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2548 g_object_unref (mime_part);
2550 g_object_unref (iter);
2553 g_object_unref (att_list);
2555 /* if the last attachment has been removed, focus the Subject: field */
2556 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2557 gtk_widget_grab_focus (priv->subject_field);
2561 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2564 ModestMsgEditWindowPrivate *priv;
2565 GdkColor *new_color;
2566 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2568 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2569 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2572 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2574 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2576 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2578 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2583 font_size_clicked (GtkToolButton *button,
2584 ModestMsgEditWindow *window)
2586 ModestMsgEditWindowPrivate *priv;
2587 GtkWidget *selector, *dialog;
2589 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2591 selector = hildon_touch_selector_new ();
2592 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2593 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2595 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2596 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2597 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2599 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2603 WPTextBufferFormat format;
2605 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2607 memset (&format, 0, sizeof (format));
2608 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2610 format.cs.font_size = TRUE;
2611 format.cs.text_position = TRUE;
2612 format.cs.font = TRUE;
2613 format.font_size = new_index;
2614 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2616 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2617 GINT_TO_POINTER (new_index)))
2618 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2620 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2621 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2622 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2623 size_text, "</span>", NULL);
2625 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2629 gtk_widget_destroy (dialog);
2631 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2636 font_face_clicked (GtkToolButton *button,
2637 ModestMsgEditWindow *window)
2639 ModestMsgEditWindowPrivate *priv;
2640 GtkWidget *selector, *dialog;
2641 GtkCellRenderer *renderer;
2643 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2645 selector = hildon_touch_selector_new ();
2646 renderer = gtk_cell_renderer_text_new ();
2647 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2648 renderer, "family", 0, "text", 0, NULL);
2649 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2651 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2652 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2653 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2655 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2656 gint new_font_index;
2660 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2661 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2662 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2666 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2668 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2669 GINT_TO_POINTER(new_font_index)))
2670 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2672 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2673 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2675 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2679 gtk_tree_path_free (path);
2682 gtk_widget_destroy (dialog);
2684 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2689 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2692 ModestMsgEditWindowPrivate *priv = NULL;
2693 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2695 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2696 if (!priv->update_caption_visibility)
2699 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2701 gtk_widget_show (priv->cc_caption);
2703 gtk_widget_hide (priv->cc_caption);
2705 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2709 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2712 ModestMsgEditWindowPrivate *priv = NULL;
2713 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2715 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2716 if (!priv->update_caption_visibility)
2719 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2721 gtk_widget_show (priv->bcc_caption);
2723 gtk_widget_hide (priv->bcc_caption);
2725 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2729 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2730 ModestRecptEditor *editor)
2732 ModestMsgEditWindowPrivate *priv;
2734 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2735 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2737 /* we check for low-mem; in that case, show a warning, and don't allow
2738 * for the addressbook
2740 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2743 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2745 if (editor == NULL) {
2746 GtkWidget *view_focus;
2747 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2749 /* This code should be kept in sync with ModestRecptEditor. The
2750 textview inside the recpt editor is the one that really gets the
2751 focus. As it's inside a scrolled window, and this one inside the
2752 hbox recpt editor inherits from, we'll need to go up in the
2753 hierarchy to know if the text view is part of the recpt editor
2754 or if it's a different text entry */
2756 if (gtk_widget_get_parent (view_focus)) {
2757 GtkWidget *first_parent;
2759 first_parent = gtk_widget_get_parent (view_focus);
2760 if (gtk_widget_get_parent (first_parent) &&
2761 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2762 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2767 editor = MODEST_RECPT_EDITOR (priv->to_field);
2771 modest_address_book_select_addresses (editor);
2776 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2778 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2780 modest_msg_edit_window_open_addressbook (window, NULL);
2784 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2785 gboolean show_toolbar)
2787 ModestWindowPrivate *parent_priv;
2789 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2790 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2792 /* We can not just use the code of
2793 modest_msg_edit_window_setup_toolbar because it has a
2794 mixture of both initialization and creation code. */
2796 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2798 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2802 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2803 TnyHeaderFlags priority_flags)
2805 ModestMsgEditWindowPrivate *priv;
2806 ModestWindowPrivate *parent_priv;
2808 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2810 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2811 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2813 if (priv->priority_flags != priority_flags) {
2814 GtkAction *priority_action = NULL;
2816 priv->priority_flags = priority_flags;
2818 switch (priority_flags) {
2819 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2820 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2821 MODEST_HEADER_ICON_HIGH,
2822 HILDON_ICON_SIZE_SMALL);
2823 gtk_widget_show (priv->priority_icon);
2824 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2825 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2827 case TNY_HEADER_FLAG_LOW_PRIORITY:
2828 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2829 MODEST_HEADER_ICON_LOW,
2830 HILDON_ICON_SIZE_SMALL);
2831 gtk_widget_show (priv->priority_icon);
2832 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2833 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2836 gtk_widget_hide (priv->priority_icon);
2837 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2838 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2841 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2842 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2844 gtk_widget_queue_resize (priv->subject_box);
2848 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2851 ModestMsgEditWindowPrivate *priv;
2852 ModestWindowPrivate *parent_priv;
2853 gint current_format;
2855 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2857 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2858 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2860 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2861 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2863 if (current_format != file_format) {
2864 switch (file_format) {
2865 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2866 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2867 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2869 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2873 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2874 response = gtk_dialog_run (GTK_DIALOG (dialog));
2875 gtk_widget_destroy (dialog);
2876 if (response == GTK_RESPONSE_OK) {
2877 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2879 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2880 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2885 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2886 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2887 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2892 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2895 ModestMsgEditWindowPrivate *priv;
2896 WPTextBufferFormat oldfmt, fmt;
2897 gint old_position = 0;
2901 GdkColor *color = NULL;
2902 gboolean bold, bold_set, italic, italic_set;
2903 gboolean underline, underline_set;
2904 gboolean strikethrough, strikethrough_set;
2905 gboolean position_set;
2906 gboolean font_size_set, font_set, color_set;
2909 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2910 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2912 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2913 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2914 GTK_WINDOW(dialog), GTK_WINDOW (window));
2916 /* First we get the currently selected font information */
2917 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2919 switch (oldfmt.text_position) {
2920 case TEXT_POSITION_NORMAL:
2923 case TEXT_POSITION_SUPERSCRIPT:
2931 g_object_set (G_OBJECT (dialog),
2932 "bold", oldfmt.bold != FALSE,
2933 "bold-set", !oldfmt.cs.bold,
2934 "underline", oldfmt.underline != FALSE,
2935 "underline-set", !oldfmt.cs.underline,
2936 "italic", oldfmt.italic != FALSE,
2937 "italic-set", !oldfmt.cs.italic,
2938 "strikethrough", oldfmt.strikethrough != FALSE,
2939 "strikethrough-set", !oldfmt.cs.strikethrough,
2940 "color", &oldfmt.color,
2941 "color-set", !oldfmt.cs.color,
2942 "size", wp_font_size[oldfmt.font_size],
2943 "size-set", !oldfmt.cs.font_size,
2944 "position", old_position,
2945 "position-set", !oldfmt.cs.text_position,
2946 "family", wp_get_font_name (oldfmt.font),
2947 "family-set", !oldfmt.cs.font,
2950 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2951 GTK_WINDOW (dialog), GTK_WINDOW (window));
2952 gtk_widget_show_all (dialog);
2953 priv->font_dialog = dialog;
2954 response = gtk_dialog_run (GTK_DIALOG (dialog));
2955 priv->font_dialog = NULL;
2956 if (response == GTK_RESPONSE_OK) {
2958 g_object_get( dialog,
2960 "bold-set", &bold_set,
2961 "underline", &underline,
2962 "underline-set", &underline_set,
2964 "italic-set", &italic_set,
2965 "strikethrough", &strikethrough,
2966 "strikethrough-set", &strikethrough_set,
2968 "color-set", &color_set,
2970 "size-set", &font_size_set,
2971 "family", &font_name,
2972 "family-set", &font_set,
2973 "position", &position,
2974 "position-set", &position_set,
2979 if (response == GTK_RESPONSE_OK) {
2980 memset(&fmt, 0, sizeof(fmt));
2986 fmt.italic = italic;
2987 fmt.cs.italic = TRUE;
2989 if (underline_set) {
2990 fmt.underline = underline;
2991 fmt.cs.underline = TRUE;
2993 if (strikethrough_set) {
2994 fmt.strikethrough = strikethrough;
2995 fmt.cs.strikethrough = TRUE;
3000 ? TEXT_POSITION_NORMAL
3001 : ( ( position == 1 )
3002 ? TEXT_POSITION_SUPERSCRIPT
3003 : TEXT_POSITION_SUBSCRIPT );
3004 fmt.cs.text_position = TRUE;
3005 fmt.font_size = oldfmt.font_size;
3009 fmt.cs.color = TRUE;
3012 fmt.font = wp_get_font_index(font_name,
3017 if (font_size_set) {
3018 fmt.cs.font_size = TRUE;
3019 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3021 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3022 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3024 gtk_widget_destroy (dialog);
3026 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3030 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3032 ModestMsgEditWindowPrivate *priv;
3034 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3035 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3037 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3039 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3040 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3044 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3046 ModestMsgEditWindowPrivate *priv;
3048 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3049 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3051 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3053 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3054 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3059 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3061 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3063 priv->can_undo = can_undo;
3067 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3069 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3071 priv->can_redo = can_redo;
3075 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3077 ModestMsgEditWindowPrivate *priv;
3078 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3079 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3081 return priv->can_undo;
3085 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3087 ModestMsgEditWindowPrivate *priv;
3088 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3089 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3091 return priv->can_redo;
3096 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3099 GtkTextIter match_start, match_end;
3101 if (image_id == NULL)
3104 gtk_text_buffer_get_start_iter (buffer, &iter);
3106 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3107 GSList *tags = gtk_text_iter_get_tags (&match_start);
3109 for (node = tags; node != NULL; node = g_slist_next (node)) {
3110 GtkTextTag *tag = (GtkTextTag *) node->data;
3111 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3112 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3113 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3115 offset = gtk_text_iter_get_offset (&match_start);
3116 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3117 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3121 gtk_text_iter_forward_char (&iter);
3126 message_is_empty (ModestMsgEditWindow *window)
3128 ModestMsgEditWindowPrivate *priv = NULL;
3130 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3131 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3133 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3134 * so we can ignore markup.
3136 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3139 count = gtk_text_buffer_get_char_count (buf);
3145 msg_body_focus (GtkWidget *focus,
3146 GdkEventFocus *event,
3150 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3151 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3152 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3157 recpt_field_changed (GtkTextBuffer *buffer,
3158 ModestMsgEditWindow *editor)
3160 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3161 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3165 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3167 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3168 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3172 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3175 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3176 GtkTextBuffer *buffer;
3178 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3179 gtk_text_buffer_set_modified (buffer, modified);
3180 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3181 gtk_text_buffer_set_modified (buffer, modified);
3182 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3183 gtk_text_buffer_set_modified (buffer, modified);
3184 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3188 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3190 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3191 const char *account_name;
3192 GtkTextBuffer *buffer;
3194 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3195 if (gtk_text_buffer_get_modified (buffer))
3197 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3198 if (gtk_text_buffer_get_modified (buffer))
3200 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3201 if (gtk_text_buffer_get_modified (buffer))
3203 if (gtk_text_buffer_get_modified (priv->text_buffer))
3205 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3206 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3217 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3219 ModestMsgEditWindowPrivate *priv = NULL;
3221 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3222 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3224 /* check if there's no recipient added */
3225 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3226 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3227 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3228 /* no recipient contents, then select contacts */
3229 modest_msg_edit_window_open_addressbook (window, NULL);
3233 g_object_ref (window);
3234 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3235 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3236 g_object_unref (window);
3239 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3240 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3241 g_object_unref (window);
3244 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3245 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3246 g_object_unref (window);
3250 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3251 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3252 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3253 g_object_unref (window);
3260 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3261 ModestMsgEditWindow *window)
3263 modest_msg_edit_window_offer_attach_file (window);
3267 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3269 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3271 return priv->clipboard_text;
3275 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3277 ModestMsgEditWindow *window)
3279 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3280 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3283 /* It could happen that the window was already closed */
3284 if (!GTK_WIDGET_VISIBLE (window))
3287 g_object_ref (window);
3288 text = gtk_clipboard_wait_for_text (selection_clipboard);
3290 if (priv->clipboard_text != NULL) {
3291 g_free (priv->clipboard_text);
3293 priv->clipboard_text = text;
3295 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3297 g_object_unref (window);
3300 static gboolean clipboard_owner_change_idle (gpointer userdata)
3302 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3303 ModestMsgEditWindowPrivate *priv;
3305 gdk_threads_enter ();
3306 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3307 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3309 priv->clipboard_owner_idle = 0;
3310 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3311 gdk_threads_leave ();
3317 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3319 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3320 if (priv->clipboard_owner_idle == 0) {
3321 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3322 clipboard_owner_change_idle,
3323 g_object_ref (window),
3329 subject_field_move_cursor (GtkEntry *entry,
3330 GtkMovementStep step,
3335 /* It could happen that the window was already closed */
3336 if (!GTK_WIDGET_VISIBLE (window))
3339 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3343 update_window_title (ModestMsgEditWindow *window)
3345 ModestMsgEditWindowPrivate *priv = NULL;
3346 const gchar *subject;
3348 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3349 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3350 if (subject == NULL || subject[0] == '\0')
3351 subject = _("mail_va_new_email");
3353 gtk_window_set_title (GTK_WINDOW (window), subject);
3358 subject_field_changed (GtkEditable *editable,
3359 ModestMsgEditWindow *window)
3361 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3362 update_window_title (window);
3363 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3364 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3365 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3369 subject_field_insert_text (GtkEditable *editable,
3371 gint new_text_length,
3373 ModestMsgEditWindow *window)
3375 GString *result = g_string_new ("");
3377 gint result_len = 0;
3378 const gchar *entry_text = NULL;
3381 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3382 old_length = g_utf8_strlen (entry_text, -1);
3384 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3385 gunichar c = g_utf8_get_char_validated (current, 8);
3386 /* Invalid unichar, stop */
3392 result = g_string_append_unichar (result, c);
3396 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3397 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3400 /* Prevent endless recursion */
3401 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3402 g_signal_emit_by_name (editable, "insert-text",
3403 (gpointer) result->str, (gpointer) result->len,
3404 (gpointer) position, (gpointer) window);
3405 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3409 if (result_len + old_length > 1000) {
3410 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3411 _CS("ckdg_ib_maximum_characters_reached"));
3413 g_string_free (result, TRUE);
3417 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3420 ModestMsgEditWindowPrivate *priv = NULL;
3422 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3423 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3425 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3428 gtk_widget_show_all (priv->find_toolbar);
3429 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3431 gtk_widget_hide_all (priv->find_toolbar);
3432 gtk_widget_grab_focus (priv->msg_body);
3437 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3439 GtkTextIter *match_start,
3440 GtkTextIter *match_end)
3442 GtkTextIter end_iter;
3443 gchar *str_casefold;
3446 gchar *range_casefold;
3449 gboolean result = FALSE;
3456 gtk_text_iter_forward_to_end (&end_iter);
3458 str_casefold = g_utf8_casefold (str, -1);
3459 str_chars_n = strlen (str);
3461 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3462 range_casefold = g_utf8_casefold (range_text, -1);
3463 range_chars_n = strlen (range_casefold);
3465 if (range_chars_n < str_chars_n) {
3466 g_free (str_casefold);
3467 g_free (range_text);
3468 g_free (range_casefold);
3472 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3473 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3474 if (!g_utf8_collate (range_subtext, str_casefold)) {
3475 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3477 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3478 match_start, match_end, NULL)) {
3479 g_warning ("Matched string with collate, but not matched in model");
3481 g_free (found_text);
3483 g_free (range_subtext);
3487 g_free (str_casefold);
3488 g_free (range_text);
3489 g_free (range_casefold);
3496 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3497 ModestMsgEditWindow *window)
3499 gchar *current_search = NULL;
3500 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3502 GtkTextIter selection_start, selection_end;
3503 GtkTextIter match_start, match_end;
3504 gboolean continue_search = FALSE;
3506 if (message_is_empty (window)) {
3507 g_free (priv->last_search);
3508 priv->last_search = NULL;
3509 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3513 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3514 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3515 g_free (current_search);
3516 g_free (priv->last_search);
3517 priv->last_search = NULL;
3518 /* Information banner about empty search */
3519 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3523 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3524 continue_search = TRUE;
3526 g_free (priv->last_search);
3527 priv->last_search = g_strdup (current_search);
3530 if (continue_search) {
3531 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3532 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3533 &match_start, &match_end);
3535 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3537 GtkTextIter buffer_start;
3538 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3539 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3540 &match_start, &match_end);
3542 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3545 /* Mark as selected the string found in search */
3547 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3548 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3549 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3551 g_free (priv->last_search);
3552 priv->last_search = NULL;
3554 g_free (current_search);
3558 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3560 ModestMsgEditWindowPrivate *priv;
3562 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3567 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3570 ModestMsgEditWindowPrivate *priv;
3572 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3577 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3578 ModestMsgEditWindow *window)
3580 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3584 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3587 ModestMsgEditWindowPrivate *priv;
3588 TnyHeader *header = NULL;
3590 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3591 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3593 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3595 if (priv->draft_msg != NULL) {
3596 g_object_unref (priv->draft_msg);
3599 if (draft != NULL) {
3600 g_object_ref (draft);
3601 header = tny_msg_get_header (draft);
3602 if (priv->msg_uid) {
3603 g_free (priv->msg_uid);
3604 priv->msg_uid = NULL;
3606 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3609 priv->draft_msg = draft;
3613 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3614 GtkTextIter *start, GtkTextIter *end,
3617 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3618 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3621 if (tag == NULL) return;
3622 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3623 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3624 replace_with_images (window, priv->images);
3629 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3632 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3634 g_return_if_fail (TNY_IS_MIME_PART (part));
3635 tny_list_prepend (priv->attachments, (GObject *) part);
3636 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3637 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3638 gtk_widget_show_all (priv->attachments_caption);
3639 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3643 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3645 ModestMsgEditWindowPrivate *priv;
3647 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3648 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3650 return priv->msg_uid;
3654 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3655 ModestMsgEditWindowWidgetType widget_type)
3657 ModestMsgEditWindowPrivate *priv;
3659 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3660 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3662 switch (widget_type) {
3663 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3664 return priv->msg_body;
3666 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3667 return priv->to_field;
3669 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3670 return priv->cc_field;
3672 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3673 return priv->bcc_field;
3675 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3676 return priv->subject_field;
3678 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3679 return priv->attachments_view;
3687 remove_tags (WPTextBuffer *buffer)
3689 GtkTextIter start, end;
3691 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3692 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3694 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3698 on_account_removed (TnyAccountStore *account_store,
3699 TnyAccount *account,
3702 /* Do nothing if it's a store account, because we use the
3703 transport to send the messages */
3704 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3705 const gchar *parent_acc = NULL;
3706 const gchar *our_acc = NULL;
3708 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3709 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3710 /* Close this window if I'm showing a message of the removed account */
3711 if (strcmp (parent_acc, our_acc) == 0)
3712 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3717 from_field_changed (HildonPickerButton *button,
3718 ModestMsgEditWindow *self)
3720 ModestMsgEditWindowPrivate *priv;
3721 gboolean has_old_signature, has_new_signature;
3723 GtkTextIter match_start, match_end;
3724 ModestAccountMgr *mgr;
3726 gchar *full_signature;
3728 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3730 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3731 mgr = modest_runtime_get_account_mgr ();
3732 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3733 if (has_old_signature) {
3734 full_signature = g_strconcat ("\n--\n", signature, NULL);
3735 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3736 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3738 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3739 &match_start, &match_end, NULL)) {
3742 g_free (full_signature);
3746 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3747 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3748 if (has_new_signature) {
3749 full_signature = g_strconcat ("\n--\n", signature, NULL);
3750 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3751 g_free (full_signature);
3756 typedef struct _MessageSettingsHelper {
3757 ModestMsgEditWindow *window;
3758 GSList *priority_group;
3759 GSList *format_group;
3760 GtkToggleButton *current_priority;
3761 GtkToggleButton *current_format;
3762 } MessageSettingsHelper;
3765 on_priority_toggle (GtkToggleButton *button,
3766 MessageSettingsHelper *helper)
3769 ModestMsgEditWindowPrivate *priv;
3771 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3772 if (gtk_toggle_button_get_active (button)) {
3774 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3775 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3776 if ((node_button != button) &&
3777 gtk_toggle_button_get_active (node_button)) {
3778 gtk_toggle_button_set_active (node_button, FALSE);
3781 helper->current_priority = button;
3783 gboolean found = FALSE;
3784 /* If no one is active, activate it again */
3785 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3786 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3787 if (gtk_toggle_button_get_active (node_button)) {
3793 gtk_toggle_button_set_active (button, TRUE);
3799 on_format_toggle (GtkToggleButton *button,
3800 MessageSettingsHelper *helper)
3803 ModestMsgEditWindowPrivate *priv;
3805 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3806 if (gtk_toggle_button_get_active (button)) {
3808 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3809 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3810 if ((node_button != button) &&
3811 gtk_toggle_button_get_active (node_button)) {
3812 gtk_toggle_button_set_active (node_button, FALSE);
3815 helper->current_format = button;
3817 gboolean found = FALSE;
3818 /* If no one is active, activate it again */
3819 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3820 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3821 if (gtk_toggle_button_get_active (node_button)) {
3827 gtk_toggle_button_set_active (button, TRUE);
3834 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3839 GtkWidget *priority_hbox;
3840 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3841 GtkWidget *captioned;
3842 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3843 GtkWidget *format_hbox;
3844 GtkWidget *html_toggle, *text_toggle;
3845 ModestMsgEditWindowPrivate *priv;
3846 MessageSettingsHelper helper = {0,};
3848 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3849 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3850 helper.window = window;
3851 helper.priority_group = NULL;
3852 helper.format_group = NULL;
3854 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3855 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3857 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3858 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3859 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3860 vbox = gtk_vbox_new (FALSE, 0);
3861 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3862 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3863 gtk_container_add (GTK_CONTAINER (align), vbox);
3864 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3865 gtk_widget_show (align);
3866 gtk_widget_show (vbox);
3868 /* Priority toggles */
3869 priority_hbox = gtk_hbox_new (TRUE, 0);
3870 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3871 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3872 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3873 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3874 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3875 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3876 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3877 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3878 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3879 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3880 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3881 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3882 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3883 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3884 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3885 gtk_widget_show_all (priority_hbox);
3886 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3887 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3888 gtk_widget_show (captioned);
3889 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3891 /* format toggles */
3892 format_hbox = gtk_hbox_new (TRUE, 0);
3893 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3894 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3895 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3896 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3897 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3898 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3899 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3900 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3901 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3902 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3903 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3904 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3905 gtk_widget_show_all (format_hbox);
3906 gtk_widget_show (format_hbox);
3907 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3910 g_object_unref (title_sizegroup);
3911 g_object_unref (value_sizegroup);
3913 /* Set current values */
3914 switch (priv->priority_flags) {
3915 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3916 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3917 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3919 case TNY_HEADER_FLAG_LOW_PRIORITY:
3920 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3921 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3924 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3925 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3929 switch (modest_msg_edit_window_get_format (window)) {
3930 case MODEST_MSG_EDIT_FORMAT_TEXT:
3931 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3932 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3934 case MODEST_MSG_EDIT_FORMAT_HTML:
3936 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3937 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3941 /* Signal connects */
3942 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3943 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3944 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3945 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3946 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3948 /* Save settings if the user clicked on done */
3949 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3950 TnyHeaderFlags flags;
3951 ModestMsgEditFormat old_format, new_format;
3953 /* Set priority flags */
3954 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3955 if (priv->priority_flags != flags)
3956 modest_msg_edit_window_set_priority_flags (window, flags);
3958 /* Set edit format */
3959 old_format = modest_msg_edit_window_get_format (window);
3960 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3961 if (old_format != new_format) {
3962 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3963 modest_msg_edit_window_set_file_format (window, file_format);
3967 gtk_widget_destroy (dialog);
3968 g_slist_free (helper.priority_group);
3972 on_message_settings (GtkAction *action,
3973 ModestMsgEditWindow *window)
3975 modest_msg_edit_window_show_msg_settings_dialog (window);
3979 on_cc_button_toggled (HildonCheckButton *button,
3980 ModestMsgEditWindow *window)
3982 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3984 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3985 hildon_check_button_get_active (button));
3989 on_bcc_button_toggled (HildonCheckButton *button,
3990 ModestMsgEditWindow *window)
3992 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3994 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3995 hildon_check_button_get_active (button));
3999 setup_menu (ModestMsgEditWindow *self)
4001 ModestMsgEditWindowPrivate *priv = NULL;
4003 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4005 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4007 /* Settings menu buttons */
4008 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4009 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4011 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4012 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4013 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4015 priv->cc_button = hildon_check_button_new (0);
4016 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4017 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4019 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4021 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4022 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4023 priv->bcc_button = hildon_check_button_new (0);
4024 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4025 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4027 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4029 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4030 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4032 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4033 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4034 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4035 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4036 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4037 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4038 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4039 APP_MENU_CALLBACK (on_message_settings),
4041 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4042 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),