1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38 #include <tny-camel-mem-stream.h>
42 #include <modest-account-mgr.h>
43 #include <modest-account-mgr-helpers.h>
45 #include <widgets/modest-msg-edit-window.h>
46 #include <modest-selector-picker.h>
47 #include <widgets/modest-recpt-editor.h>
48 #include <widgets/modest-attachments-view.h>
50 #include <modest-runtime.h>
52 #include "modest-platform.h"
53 #include "modest-icon-names.h"
54 #include "modest-widget-memory.h"
55 #include "modest-window-priv.h"
56 #include "modest-mail-operation.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-tny-folder.h"
60 #include "modest-tny-account.h"
61 #include "modest-address-book.h"
62 #include "modest-text-utils.h"
63 #include <tny-simple-list.h>
64 #include <modest-wp-text-view.h>
65 #include <wptextbuffer.h>
66 #include <hildon/hildon-pannable-area.h>
67 #include <hildon/hildon-touch-selector.h>
68 #include <hildon/hildon-picker-dialog.h>
69 #include "modest-msg-edit-window-ui-dimming.h"
71 #include "modest-hildon-includes.h"
72 #ifdef MODEST_HAVE_HILDON0_WIDGETS
73 #include <hildon-widgets/hildon-color-chooser.h>
75 #include "widgets/modest-msg-edit-window-ui.h"
76 #ifdef MODEST_HAVE_HILDON0_WIDGETS
77 #include <libgnomevfs/gnome-vfs-mime-utils.h>
79 #include <libgnomevfs/gnome-vfs-mime.h>
81 #include <modest-utils.h>
82 #include "modest-maemo-utils.h"
83 #include <modest-ui-constants.h>
86 #define DEFAULT_FONT_SIZE 3
87 #define DEFAULT_FONT 2
88 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
89 #define DEFAULT_MAIN_VBOX_SPACING 6
90 #define SUBJECT_MAX_LENGTH 1000
91 #define IMAGE_MAX_WIDTH 560
92 #define DEFAULT_FONT_SCALE 1.5
93 #define ATTACHMENT_BUTTON_WIDTH 118
95 static gboolean is_wp_text_buffer_started = FALSE;
97 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
98 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
99 static void modest_msg_edit_window_finalize (GObject *obj);
101 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
102 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
103 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
105 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
106 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
107 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
108 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
109 GtkTextIter *start, GtkTextIter *end,
111 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
112 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
113 static void subject_field_insert_text (GtkEditable *editable,
115 gint new_text_length,
117 ModestMsgEditWindow *window);
118 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
122 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
123 ModestRecptEditor *editor);
124 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
125 ModestMsgEditWindow *window);
127 /* ModestWindow methods implementation */
128 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
129 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
130 gboolean show_toolbar);
131 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
133 ModestMsgEditWindow *window);
134 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
135 static void subject_field_move_cursor (GtkEntry *entry,
136 GtkMovementStep step,
140 static void update_window_title (ModestMsgEditWindow *window);
143 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
144 ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
149 GtkTextIter *match_start,
150 GtkTextIter *match_end);
152 static void remove_tags (WPTextBuffer *buffer);
154 static void on_account_removed (TnyAccountStore *account_store,
158 static void init_window (ModestMsgEditWindow *obj);
160 gboolean scroll_drag_timeout (gpointer userdata);
161 static void correct_scroll (ModestMsgEditWindow *w);
162 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
163 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
164 ModestMsgEditWindow *userdata);
165 static void text_buffer_mark_set (GtkTextBuffer *buffer,
168 ModestMsgEditWindow *userdata);
169 static void on_message_settings (GtkAction *action,
170 ModestMsgEditWindow *window);
171 static void setup_menu (ModestMsgEditWindow *self);
173 static void from_field_changed (HildonPickerButton *button,
174 ModestMsgEditWindow *self);
175 static void font_size_clicked (GtkToolButton *button,
176 ModestMsgEditWindow *window);
177 static void font_face_clicked (GtkToolButton *button,
178 ModestMsgEditWindow *window);
179 static void DEBUG_BUFFER (WPTextBuffer *buffer)
183 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
185 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
186 while (!gtk_text_iter_is_end (&iter)) {
187 GString *output = g_string_new ("");
188 GSList *toggled_tags;
191 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
192 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
193 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
194 GtkTextTag *tag = (GtkTextTag *) node->data;
196 g_object_get (G_OBJECT (tag), "name", &name, NULL);
197 output = g_string_append (output, name);
198 g_string_append (output, " ");
200 output = g_string_append (output, "] OPENED [ ");
201 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
202 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
203 GtkTextTag *tag = (GtkTextTag *) node->data;
205 g_object_get (G_OBJECT (tag), "name", &name, NULL);
206 output = g_string_append (output, name);
207 g_string_append (output, " ");
209 output = g_string_append (output, "]\n");
210 g_message ("%s", output->str);
211 g_string_free (output, TRUE);
212 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
214 g_message ("END BUFFER");
218 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
219 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
223 /* static gboolean */
224 /* on_key_pressed (GtkWidget *self, */
225 /* GdkEventKey *event, */
226 /* gpointer user_data); */
228 /* list my signals */
235 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
236 struct _ModestMsgEditWindowPrivate {
238 GtkWidget *header_box;
240 ModestPairList *from_field_protos;
241 GtkWidget *from_field;
242 gchar *last_from_account;
243 gchar *original_account_name;
247 GtkWidget *bcc_field;
248 GtkWidget *subject_field;
249 GtkWidget *attachments_view;
250 GtkWidget *priority_icon;
251 GtkWidget *subject_box;
252 GtkWidget *add_attachment_button;
254 GtkWidget *cc_caption;
255 GtkWidget *bcc_caption;
256 gboolean update_caption_visibility;
257 GtkWidget *attachments_caption;
259 GtkTextBuffer *text_buffer;
261 GtkWidget *font_size_toolitem;
262 GtkWidget *font_face_toolitem;
263 GtkWidget *font_color_button;
264 GtkWidget *font_color_toolitem;
265 GSList *font_items_group;
266 GtkTreeModel *faces_model;
267 gint current_face_index;
268 GtkWidget *font_tool_button_label;
269 GtkTreeModel *sizes_model;
270 gint current_size_index;
271 GtkWidget *size_tool_button_label;
273 GtkWidget *find_toolbar;
276 GtkWidget *font_dialog;
279 guint correct_scroll_idle;
280 guint scroll_drag_timeout_id;
284 TnyList *attachments;
289 TnyHeaderFlags priority_flags;
291 gboolean can_undo, can_redo;
292 gulong clipboard_change_handler_id;
293 gulong default_clipboard_change_handler_id;
294 gulong account_removed_handler_id;
295 guint clipboard_owner_idle;
296 gchar *clipboard_text;
305 GtkWidget *cc_button;
306 GtkWidget *bcc_button;
309 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
310 MODEST_TYPE_MSG_EDIT_WINDOW, \
311 ModestMsgEditWindowPrivate))
313 static GtkWindowClass *parent_class = NULL;
315 /* uncomment the following if you have defined any signals */
316 /* static guint signals[LAST_SIGNAL] = {0}; */
319 modest_msg_edit_window_get_type (void)
321 static GType my_type = 0;
323 static const GTypeInfo my_info = {
324 sizeof(ModestMsgEditWindowClass),
325 NULL, /* base init */
326 NULL, /* base finalize */
327 (GClassInitFunc) modest_msg_edit_window_class_init,
328 NULL, /* class finalize */
329 NULL, /* class data */
330 sizeof(ModestMsgEditWindow),
332 (GInstanceInitFunc) modest_msg_edit_window_init,
335 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
336 "ModestMsgEditWindow",
344 save_state (ModestWindow *self)
346 modest_widget_memory_save (modest_runtime_get_conf(),
347 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
352 restore_settings (ModestMsgEditWindow *self)
354 ModestConf *conf = NULL;
356 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
358 conf = modest_runtime_get_conf ();
360 /* Dim at start clipboard actions */
361 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
362 gtk_action_set_sensitive (action, FALSE);
363 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
364 gtk_action_set_sensitive (action, FALSE);
365 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
366 gtk_action_set_sensitive (action, FALSE);
368 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
373 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
375 GObjectClass *gobject_class;
376 ModestWindowClass *modest_window_class;
377 gobject_class = (GObjectClass*) klass;
378 modest_window_class = (ModestWindowClass*) klass;
380 parent_class = g_type_class_peek_parent (klass);
381 gobject_class->finalize = modest_msg_edit_window_finalize;
383 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
384 modest_window_class->save_state_func = save_state;
385 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
387 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
391 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
393 ModestMsgEditWindowPrivate *priv;
394 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
396 priv->msg_body = NULL;
397 priv->from_field = NULL;
398 priv->to_field = NULL;
399 priv->cc_field = NULL;
400 priv->bcc_field = NULL;
401 priv->subject_field = NULL;
402 priv->attachments = TNY_LIST (tny_simple_list_new ());
403 priv->images = TNY_LIST (tny_simple_list_new ());
404 priv->images_size = 0;
405 priv->images_count = 0;
408 priv->cc_caption = NULL;
409 priv->bcc_caption = NULL;
410 priv->update_caption_visibility = FALSE;
412 priv->priority_flags = 0;
414 priv->find_toolbar = NULL;
415 priv->last_search = NULL;
417 priv->draft_msg = NULL;
418 priv->outbox_msg = NULL;
419 priv->msg_uid = NULL;
421 priv->can_undo = FALSE;
422 priv->can_redo = FALSE;
423 priv->clipboard_change_handler_id = 0;
424 priv->default_clipboard_change_handler_id = 0;
425 priv->account_removed_handler_id = 0;
426 priv->clipboard_owner_idle = 0;
427 priv->clipboard_text = NULL;
430 priv->scroll_drag_timeout_id = 0;
431 priv->correct_scroll_idle = 0;
432 priv->last_upper = 0.0;
434 priv->font_dialog = NULL;
435 priv->app_menu = NULL;
437 if (!is_wp_text_buffer_started) {
438 is_wp_text_buffer_started = TRUE;
439 wp_text_buffer_library_init ();
444 hildon_program_add_window (hildon_program_get_instance(),
450 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
452 static ModestPairList*
453 get_transports (void)
455 GSList *transports = NULL;
457 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
458 GSList *accounts = modest_account_mgr_account_names (account_mgr,
459 TRUE /* only enabled accounts. */);
461 GSList *cursor = accounts;
463 gchar *account_name = cursor->data;
464 gchar *from_string = NULL;
466 from_string = modest_account_mgr_get_from_string (account_mgr,
470 if (from_string && account_name) {
471 gchar *name = account_name;
472 ModestPair *pair = modest_pair_new ((gpointer) name,
473 (gpointer) from_string , TRUE);
474 transports = g_slist_prepend (transports, pair);
477 cursor = cursor->next;
479 g_slist_free (accounts); /* only free the accounts, not the elements,
480 * because they are used in the pairlist */
484 static void window_focus (GtkWindow *window,
488 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
492 scroll_drag_timeout (gpointer userdata)
494 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
495 ModestMsgEditWindowPrivate *priv;
497 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
499 correct_scroll_without_drag_check (win, TRUE);
501 priv->scroll_drag_timeout_id = 0;
507 correct_scroll_without_drag_check_idle (gpointer userdata)
509 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
510 ModestMsgEditWindowPrivate *priv;
512 GdkRectangle rectangle;
513 gint offset_min, offset_max;
517 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
519 insert = gtk_text_buffer_get_insert (priv->text_buffer);
520 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
522 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
523 offset_min = priv->msg_body->allocation.y + rectangle.y;
524 offset_max = offset_min + rectangle.height;
526 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
527 offset_min = MAX (offset_min - 48, 0);
528 offset_max = MIN (offset_max + 48, vadj->upper);
530 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
532 priv->correct_scroll_idle = 0;
537 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
539 ModestMsgEditWindowPrivate *priv;
541 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
543 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
546 if (priv->correct_scroll_idle > 0) {
550 priv->correct_scroll_idle = g_idle_add ((GSourceFunc) correct_scroll_without_drag_check_idle,
555 correct_scroll (ModestMsgEditWindow *w)
557 ModestMsgEditWindowPrivate *priv;
559 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
560 if (gtk_grab_get_current () == priv->msg_body) {
561 if (priv->scroll_drag_timeout_id == 0) {
562 priv->scroll_drag_timeout_id = g_timeout_add (500, (GSourceFunc) scroll_drag_timeout,
568 correct_scroll_without_drag_check (w, TRUE);
572 text_buffer_end_user_action (GtkTextBuffer *buffer,
573 ModestMsgEditWindow *userdata)
576 correct_scroll (userdata);
580 text_buffer_mark_set (GtkTextBuffer *buffer,
583 ModestMsgEditWindow *userdata)
585 gtk_text_buffer_begin_user_action (buffer);
586 gtk_text_buffer_end_user_action (buffer);
590 cut_clipboard_check (GtkTextView *text_view,
593 GtkTextBuffer *buffer;
595 buffer = gtk_text_view_get_buffer (text_view);
596 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
597 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
602 copy_clipboard_check (GtkTextView *text_view,
605 GtkTextBuffer *buffer;
607 buffer = gtk_text_view_get_buffer (text_view);
608 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
609 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
614 attachment_deleted (ModestAttachmentsView *attachments_view,
617 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
622 connect_signals (ModestMsgEditWindow *obj)
624 ModestMsgEditWindowPrivate *priv;
626 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
628 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
629 G_CALLBACK (text_buffer_refresh_attributes), obj);
630 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
631 G_CALLBACK (text_buffer_can_undo), obj);
632 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
633 G_CALLBACK (text_buffer_can_redo), obj);
634 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
635 G_CALLBACK (body_changed), obj);
636 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
637 G_CALLBACK (body_changed), obj);
638 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
639 G_CALLBACK (text_buffer_end_user_action), obj);
640 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
641 G_CALLBACK (text_buffer_mark_set), obj);
642 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
643 G_CALLBACK (text_buffer_apply_tag), obj);
644 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
645 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
646 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
647 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
648 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
649 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
651 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
652 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
653 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
654 G_CALLBACK (from_field_changed), obj);
656 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
657 G_CALLBACK (msg_body_focus), obj);
658 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
659 G_CALLBACK (msg_body_focus), obj);
660 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
661 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
662 "changed", G_CALLBACK (recpt_field_changed), obj);
663 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
664 "changed", G_CALLBACK (recpt_field_changed), obj);
665 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
666 "changed", G_CALLBACK (recpt_field_changed), obj);
667 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
668 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
669 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
671 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
672 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
674 priv->clipboard_change_handler_id =
675 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
676 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
677 priv->default_clipboard_change_handler_id =
678 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
679 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
681 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
682 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
683 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
687 init_wp_text_view_style ()
689 static gboolean initialized = FALSE;
692 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
698 init_window (ModestMsgEditWindow *obj)
700 GtkWidget *to_caption, *subject_caption;
701 GtkWidget *main_vbox;
702 GtkWidget *add_attachment_align;
703 ModestMsgEditWindowPrivate *priv;
704 GtkActionGroup *action_group;
705 ModestWindowPrivate *parent_priv;
706 GdkPixbuf *window_icon = NULL;
707 GError *error = NULL;
709 GtkSizeGroup *title_size_group;
710 GtkSizeGroup *value_size_group;
711 GtkWidget *attachment_icon;
712 GtkWidget *window_box;
713 GtkWidget *window_align;
714 #if (GTK_MINOR_VERSION >= 10)
715 GdkAtom deserialize_type;
718 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
719 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
721 parent_priv->ui_manager = gtk_ui_manager_new();
722 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
723 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
725 /* Add common actions */
726 gtk_action_group_add_actions (action_group,
727 modest_msg_edit_action_entries,
728 G_N_ELEMENTS (modest_msg_edit_action_entries),
730 gtk_action_group_add_actions (action_group,
731 hildon2_msg_edit_action_entries,
732 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
734 gtk_action_group_add_toggle_actions (action_group,
735 modest_msg_edit_toggle_action_entries,
736 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
738 gtk_action_group_add_radio_actions (action_group,
739 modest_msg_edit_alignment_radio_action_entries,
740 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
742 G_CALLBACK (modest_ui_actions_on_change_justify),
744 gtk_action_group_add_radio_actions (action_group,
745 modest_msg_edit_priority_action_entries,
746 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
748 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
750 gtk_action_group_add_radio_actions (action_group,
751 modest_msg_edit_file_format_action_entries,
752 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
753 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
754 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
756 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
757 g_object_unref (action_group);
759 /* Load the UI definition */
760 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
763 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
764 g_clear_error (&error);
767 /* Add accelerators */
768 gtk_window_add_accel_group (GTK_WINDOW (obj),
769 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
771 parent_priv->menubar = NULL;
773 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
774 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
776 /* Note: This ModestPairList* must exist for as long as the picker
777 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
778 * so it can't know how to manage its memory. */
779 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
780 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
782 modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group,
783 _("mail_va_from"), priv->from_field);
785 priv->to_field = modest_recpt_editor_new ();
786 priv->cc_field = modest_recpt_editor_new ();
787 priv->bcc_field = modest_recpt_editor_new ();
788 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
789 priv->priority_icon = gtk_image_new ();
790 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
791 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
792 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
793 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
794 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
795 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
796 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
797 priv->add_attachment_button = hildon_button_new (MODEST_EDITABLE_SIZE, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
798 gtk_widget_set_size_request (priv->add_attachment_button, ATTACHMENT_BUTTON_WIDTH, -1);
799 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
800 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
801 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
802 hildon_button_set_image (HILDON_BUTTON (priv->add_attachment_button), attachment_icon);
803 add_attachment_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
804 gtk_alignment_set_padding (GTK_ALIGNMENT (add_attachment_align), 0, 0, MODEST_MARGIN_DEFAULT, 0);
805 gtk_container_add (GTK_CONTAINER (add_attachment_align), priv->add_attachment_button);
806 gtk_box_pack_start (GTK_BOX (priv->subject_box), add_attachment_align, FALSE, FALSE, 0);
807 priv->attachments_view = modest_attachments_view_new (NULL);
808 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
809 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
811 priv->header_box = gtk_vbox_new (FALSE, 0);
813 to_caption = modest_maemo_utils_create_captioned_with_size_type
814 (title_size_group, value_size_group,
815 _("mail_va_to"), FALSE, priv->to_field,
816 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
817 priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type
818 (title_size_group, value_size_group,
819 _("mail_va_cc"), FALSE, priv->cc_field,
820 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
821 priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
822 (title_size_group, value_size_group,
823 _("mail_va_hotfix1"), FALSE, priv->bcc_field,
824 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
825 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
826 _("mail_va_subject"), FALSE, priv->subject_box);
827 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
828 _("mail_va_attachment"),
830 priv->attachments_view,
831 HILDON_SIZE_AUTO_WIDTH |
832 HILDON_SIZE_AUTO_HEIGHT);
833 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
834 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
835 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
836 g_object_unref (title_size_group);
837 g_object_unref (value_size_group);
839 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
840 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
841 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
842 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
843 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
844 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
845 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
847 init_wp_text_view_style ();
849 priv->msg_body = modest_wp_text_view_new ();
852 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
853 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
854 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
855 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
856 #if (GTK_MINOR_VERSION >= 10)
857 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
858 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
860 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
861 deserialize_type, TRUE);
863 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
865 priv->find_toolbar = hildon_find_toolbar_new (NULL);
866 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
868 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
870 priv->pannable = hildon_pannable_area_new ();
872 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
873 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
874 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
876 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
877 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
878 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
880 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
881 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox),
882 hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable)));
883 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
885 window_box = gtk_vbox_new (FALSE, 0);
886 gtk_container_add (GTK_CONTAINER(obj), window_box);
888 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
890 /* Set window icon */
891 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
893 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
894 g_object_unref (window_icon);
899 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
901 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
903 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
904 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
905 priv->clipboard_change_handler_id))
906 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
907 priv->clipboard_change_handler_id);
908 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
909 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
910 priv->default_clipboard_change_handler_id))
911 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
912 priv->default_clipboard_change_handler_id);
914 if (priv->account_removed_handler_id &&
915 g_signal_handler_is_connected (modest_runtime_get_account_store (),
916 priv->account_removed_handler_id))
917 g_signal_handler_disconnect(modest_runtime_get_account_store (),
918 priv->account_removed_handler_id);
922 modest_msg_edit_window_finalize (GObject *obj)
924 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
926 /* Sanity check: shouldn't be needed, the window mgr should
927 call this function before */
928 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
930 if (priv->font_dialog != NULL) {
931 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
934 if (priv->clipboard_text != NULL) {
935 g_free (priv->clipboard_text);
936 priv->clipboard_text = NULL;
939 if (priv->draft_msg != NULL) {
940 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
941 if (TNY_IS_HEADER (header)) {
942 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
943 modest_window_mgr_unregister_header (mgr, header);
945 g_object_unref (priv->draft_msg);
946 priv->draft_msg = NULL;
948 if (priv->outbox_msg != NULL) {
949 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
950 if (TNY_IS_HEADER (header)) {
951 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
952 modest_window_mgr_unregister_header (mgr, header);
954 g_object_unref (priv->outbox_msg);
955 priv->outbox_msg = NULL;
957 if (priv->correct_scroll_idle > 0) {
958 g_source_remove (priv->correct_scroll_idle);
959 priv->correct_scroll_idle = 0;
961 if (priv->scroll_drag_timeout_id > 0) {
962 g_source_remove (priv->scroll_drag_timeout_id);
963 priv->scroll_drag_timeout_id = 0;
965 if (priv->clipboard_owner_idle > 0) {
966 g_source_remove (priv->clipboard_owner_idle);
967 priv->clipboard_owner_idle = 0;
969 if (priv->original_account_name)
970 g_free (priv->original_account_name);
971 g_free (priv->msg_uid);
972 g_free (priv->last_search);
973 g_object_unref (priv->faces_model);
974 g_object_unref (priv->sizes_model);
975 g_object_unref (priv->attachments);
976 g_object_unref (priv->images);
978 /* This had to stay alive for as long as the picker that used it: */
979 modest_pair_list_free (priv->from_field_protos);
981 G_OBJECT_CLASS(parent_class)->finalize (obj);
985 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type, guint64 *stream_size)
987 GdkPixbufLoader *loader;
993 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
995 if (loader == NULL) {
1001 tny_stream_reset (TNY_STREAM (stream));
1002 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1003 GError *error = NULL;
1004 unsigned char read_buffer[128];
1006 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1008 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1010 g_error_free (error);
1015 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1017 g_object_ref (pixbuf);
1018 gdk_pixbuf_loader_close (loader, NULL);
1019 g_object_unref (loader);
1024 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1025 GdkPixbuf *new_pixbuf;
1027 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1028 gdk_pixbuf_get_width (pixbuf);
1029 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1030 g_object_unref (pixbuf);
1031 pixbuf = new_pixbuf;
1035 *stream_size = size;
1041 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1043 ModestMsgEditWindowPrivate *priv;
1046 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1048 for (iter = tny_list_create_iterator (attachments);
1049 !tny_iterator_is_done (iter);
1050 tny_iterator_next (iter)) {
1051 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1052 const gchar *cid = tny_mime_part_get_content_id (part);
1053 const gchar *mime_type = tny_mime_part_get_content_type (part);
1054 if ((cid != NULL)&&(mime_type != NULL)) {
1055 guint64 stream_size;
1056 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1057 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
1060 g_object_unref (stream);
1062 if (pixbuf != NULL) {
1063 priv->images_count ++;
1064 priv->images_size += stream_size;
1065 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1066 g_object_unref (pixbuf);
1069 g_object_unref (part);
1071 g_object_unref (iter);
1075 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1077 TnyMimePart *parent = NULL;
1078 const gchar *content_type = NULL;
1079 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1081 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1083 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1084 parent = g_object_ref (msg);
1085 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1086 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1089 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1090 iter = tny_list_create_iterator (parts);
1091 while (!tny_iterator_is_done (iter)) {
1093 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1094 content_type = tny_mime_part_get_content_type (part);
1095 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1099 g_object_unref (part);
1101 tny_iterator_next (iter);
1103 g_object_unref (iter);
1104 g_object_unref (parts);
1107 if (parent != NULL) {
1108 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1111 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1112 iter = tny_list_create_iterator (parts);
1113 while (!tny_iterator_is_done (iter)) {
1115 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1116 content_type = tny_mime_part_get_content_type (part);
1117 if (content_type && g_str_has_prefix (content_type, "image/")) {
1118 tny_list_prepend (priv->images, (GObject *) part);
1120 g_object_unref (part);
1121 tny_iterator_next (iter);
1123 g_object_unref (iter);
1124 g_object_unref (parts);
1125 g_object_unref (parent);
1130 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1133 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1135 for (iter = tny_list_create_iterator (attachments) ;
1136 !tny_iterator_is_done (iter);
1137 tny_iterator_next (iter)) {
1138 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1139 const gchar *cid = tny_mime_part_get_content_id (part);
1141 char *invalid = NULL;
1142 gint int_cid = strtol (cid, &invalid, 10);
1143 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1144 priv->next_cid = int_cid + 1;
1147 g_object_unref (part);
1149 g_object_unref (iter);
1153 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1156 gchar *to, *cc, *bcc, *subject;
1158 ModestMsgEditWindowPrivate *priv;
1159 ModestWindowPrivate *parent_priv;
1161 TnyHeaderFlags priority_flags;
1162 TnyFolder *msg_folder;
1163 gboolean is_html = FALSE;
1164 gboolean field_view_set;
1166 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1167 g_return_if_fail (TNY_IS_MSG (msg));
1169 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1170 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1172 header = tny_msg_get_header (msg);
1173 to = tny_header_dup_to (header);
1174 cc = tny_header_dup_cc (header);
1175 bcc = tny_header_dup_bcc (header);
1176 subject = tny_header_dup_subject (header);
1177 priority_flags = tny_header_get_priority (header);
1180 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1182 field_view_set = TRUE;
1184 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1185 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1186 gtk_widget_show (priv->cc_caption);
1187 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1188 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1189 gtk_widget_hide (priv->cc_caption);
1190 field_view_set = FALSE;
1192 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1194 field_view_set = TRUE;
1196 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1197 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1198 gtk_widget_show (priv->bcc_caption);
1199 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1200 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1201 gtk_widget_hide (priv->bcc_caption);
1202 field_view_set = FALSE;
1204 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1208 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1209 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1212 update_window_title (self);
1214 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1215 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1217 if ((body == NULL)||(body[0] == '\0')) {
1219 body = modest_text_utils_convert_to_html ("");
1222 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1223 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1226 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1229 /* Add attachments to the view */
1230 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1231 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1232 if (tny_list_get_length (priv->attachments) == 0) {
1233 gtk_widget_hide (priv->attachments_caption);
1235 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1236 gtk_widget_show_all (priv->attachments_caption);
1238 get_related_images (self, msg);
1239 update_next_cid (self, priv->attachments);
1240 update_next_cid (self, priv->images);
1241 replace_with_images (self, priv->images);
1243 if (preserve_is_rich && !is_html) {
1244 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1245 /* Get the default format required from configuration */
1246 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1247 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1250 /* Set the default focus depending on having already a To: field or not */
1251 if ((!to)||(*to == '\0')) {
1252 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1254 gtk_widget_grab_focus (priv->msg_body);
1257 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1259 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1260 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1262 modest_msg_edit_window_set_modified (self, FALSE);
1264 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1265 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1266 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1267 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1269 if (priv->msg_uid) {
1270 g_free (priv->msg_uid);
1271 priv->msg_uid = NULL;
1274 /* we should set a reference to the incoming message if it is a draft */
1275 msg_folder = tny_msg_get_folder (msg);
1277 if (modest_tny_folder_is_local_folder (msg_folder)) {
1278 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1279 if (type == TNY_FOLDER_TYPE_INVALID)
1280 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1282 if (type == TNY_FOLDER_TYPE_DRAFTS)
1283 priv->draft_msg = g_object_ref(msg);
1284 if (type == TNY_FOLDER_TYPE_OUTBOX)
1285 priv->outbox_msg = g_object_ref(msg);
1286 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1288 g_object_unref (msg_folder);
1298 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1301 GList *item_children, *node;
1303 box = gtk_bin_get_child (GTK_BIN (item));
1304 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1305 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1307 for (node = item_children; node != NULL; node = g_list_next (node)) {
1308 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1309 if (GTK_IS_TOGGLE_BUTTON (node->data))
1310 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1311 else if (GTK_IS_BUTTON (node->data))
1312 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1314 g_list_free (item_children);
1319 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1321 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1322 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1323 GtkWidget *placeholder;
1324 GtkWidget *tool_item;
1329 GtkWidget *sizes_menu;
1330 GtkWidget *fonts_menu;
1335 ldots_len = g_unichar_to_utf8 (0x2026, ldots);
1336 ldots[ldots_len] = '\0';
1339 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1340 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1341 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1342 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1344 /* Font color placeholder */
1345 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1346 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1349 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1350 priv->font_color_button = hildon_color_button_new ();
1351 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1352 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1353 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1354 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1355 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1356 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1357 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1358 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1360 G_CALLBACK (modest_msg_edit_window_color_button_change),
1363 /* Font size and face placeholder */
1364 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1365 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1367 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1368 priv->size_tool_button_label = gtk_label_new (NULL);
1369 hildon_helper_set_logical_color (GTK_WIDGET (priv->size_tool_button_label), GTK_RC_TEXT,
1370 GTK_STATE_INSENSITIVE, "SecondaryTextColor");
1371 hildon_helper_set_logical_color (GTK_WIDGET (priv->size_tool_button_label), GTK_RC_FG,
1372 GTK_STATE_INSENSITIVE, "SecondaryTextColor");
1373 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1374 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1375 size_text, ldots, "</span>", NULL);
1376 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1378 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1379 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1380 sizes_menu = gtk_menu_new ();
1381 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1382 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1385 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1386 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1388 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1392 if (wp_font_size[size_index] == 12)
1393 priv->current_size_index = size_index;
1397 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1398 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1399 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), FALSE);
1400 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), FALSE);
1401 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1402 priv->font_size_toolitem = tool_item;
1405 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1406 priv->font_tool_button_label = gtk_label_new (NULL);
1407 hildon_helper_set_logical_color (GTK_WIDGET (priv->font_tool_button_label), GTK_RC_TEXT,
1408 GTK_STATE_INSENSITIVE, "SecondaryTextColor");
1409 hildon_helper_set_logical_color (GTK_WIDGET (priv->font_tool_button_label), GTK_RC_FG,
1410 GTK_STATE_INSENSITIVE, "SecondaryTextColor");
1411 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt",ldots,"</span>", NULL);
1412 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1414 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1415 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1416 fonts_menu = gtk_menu_new ();
1417 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1418 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1421 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1423 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1424 0, wp_get_font_name (font_index),
1427 if (font_index == DEFAULT_FONT)
1428 priv->current_face_index = font_index;
1430 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1431 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1432 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), FALSE);
1433 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), FALSE);
1434 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1435 priv->font_face_toolitem = tool_item;
1437 /* Set expand and homogeneous for remaining items */
1438 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1439 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1440 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1441 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1442 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1443 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1444 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1445 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1446 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1448 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1449 will not show the tool items added to the placeholders) */
1450 gtk_widget_show_all (parent_priv->toolbar);
1452 /* Set the no show all *after* showing all items. We do not
1453 want the toolbar to be shown with a show all because it
1454 could go agains the gconf setting regarding showing or not
1455 the toolbar of the editor window */
1456 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1462 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1465 ModestWindowPrivate *parent_priv;
1466 ModestMsgEditWindowPrivate *priv;
1467 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1468 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1469 ModestWindowMgr *mgr = NULL;
1471 g_return_val_if_fail (msg, NULL);
1472 g_return_val_if_fail (account_name, NULL);
1474 mgr = modest_runtime_get_window_mgr ();
1476 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1478 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1479 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1481 /* Menubar. Update the state of some toggles */
1482 priv->from_field_protos = get_transports ();
1483 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1484 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1485 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1486 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1488 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1489 hildon_touch_selector_get_current_text
1490 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1491 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1492 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1495 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1497 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1499 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1501 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1503 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1504 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1505 /* Add common dimming rules */
1506 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1507 modest_msg_edit_window_toolbar_dimming_entries,
1508 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1509 MODEST_WINDOW (obj));
1510 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1511 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1512 MODEST_WINDOW (obj));
1513 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1514 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1515 MODEST_WINDOW (obj));
1516 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1517 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1518 MODEST_WINDOW (obj));
1519 /* Insert dimming rules group for this window */
1520 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1521 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1523 /* Setup app menu */
1524 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1526 /* Checks the dimming rules */
1527 g_object_unref (toolbar_rules_group);
1528 g_object_unref (clipboard_rules_group);
1529 gtk_widget_hide (priv->priority_icon);
1530 gtk_widget_queue_resize (priv->subject_box);
1531 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1533 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1535 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1536 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1537 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1538 priv->update_caption_visibility = TRUE;
1540 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1542 /* Track account-removed signal, this window should be closed
1543 in the case we're creating a mail associated to the account
1545 priv->account_removed_handler_id =
1546 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1548 G_CALLBACK(on_account_removed),
1551 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1553 return (ModestWindow*) obj;
1557 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1559 GString **string_buffer = (GString **) user_data;
1561 *string_buffer = g_string_append (*string_buffer, buffer);
1567 * @result: A new string which should be freed with g_free().
1570 get_formatted_data (ModestMsgEditWindow *edit_window)
1572 ModestMsgEditWindowPrivate *priv;
1573 GString *string_buffer = g_string_new ("");
1575 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1577 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1579 modest_text_utils_hyperlinkify (string_buffer);
1581 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1583 return g_string_free (string_buffer, FALSE);
1588 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1591 const gchar *account_name;
1592 ModestMsgEditWindowPrivate *priv;
1593 TnyIterator *att_iter;
1595 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1597 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1599 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1600 g_return_val_if_fail (account_name, NULL);
1603 /* don't free these (except from) */
1604 data = g_slice_new0 (MsgData);
1605 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1607 data->account_name = g_strdup (account_name);
1608 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1609 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1610 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1611 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1612 if (priv->draft_msg) {
1613 data->draft_msg = g_object_ref (priv->draft_msg);
1614 } else if (priv->outbox_msg) {
1615 data->draft_msg = g_object_ref (priv->outbox_msg);
1617 data->draft_msg = NULL;
1620 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1622 gtk_text_buffer_get_bounds (buf, &b, &e);
1623 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1625 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1626 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1628 data->html_body = NULL;
1630 /* deep-copy the data */
1631 att_iter = tny_list_create_iterator (priv->attachments);
1632 data->attachments = NULL;
1633 while (!tny_iterator_is_done (att_iter)) {
1634 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1635 if (!(TNY_IS_MIME_PART(part))) {
1636 g_warning ("strange data in attachment list");
1637 g_object_unref (part);
1638 tny_iterator_next (att_iter);
1641 data->attachments = g_list_append (data->attachments,
1643 tny_iterator_next (att_iter);
1645 g_object_unref (att_iter);
1647 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1648 att_iter = tny_list_create_iterator (priv->images);
1649 data->images = NULL;
1650 while (!tny_iterator_is_done (att_iter)) {
1651 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1653 if (!(TNY_IS_MIME_PART(part))) {
1654 g_warning ("strange data in attachment list");
1655 g_object_unref (part);
1656 tny_iterator_next (att_iter);
1659 cid = tny_mime_part_get_content_id (part);
1661 gchar *image_tag_id;
1662 GtkTextTag *image_tag;
1664 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1665 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1666 g_free (image_tag_id);
1668 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1670 ((gtk_text_iter_has_tag (&iter, image_tag))||
1671 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1672 data->images = g_list_append (data->images,
1673 g_object_ref (part));
1675 g_object_unref (part);
1676 tny_iterator_next (att_iter);
1678 g_object_unref (att_iter);
1680 data->priority_flags = priv->priority_flags;
1687 unref_gobject (GObject *obj, gpointer data)
1689 if (!G_IS_OBJECT(obj))
1691 g_object_unref (obj);
1695 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1698 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1706 g_free (data->from);
1707 g_free (data->subject);
1708 g_free (data->plain_body);
1709 g_free (data->html_body);
1710 g_free (data->account_name);
1712 if (data->draft_msg != NULL) {
1713 g_object_unref (data->draft_msg);
1714 data->draft_msg = NULL;
1717 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1718 g_list_free (data->attachments);
1719 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1720 g_list_free (data->images);
1722 g_slice_free (MsgData, data);
1726 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1728 guint64 *parts_size)
1730 ModestMsgEditWindowPrivate *priv;
1732 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1734 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1736 /* TODO: add images */
1737 *parts_size += priv->images_size;
1738 *parts_count += priv->images_count;
1743 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1746 ModestMsgEditWindowPrivate *priv = NULL;
1747 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1749 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1751 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1753 return MODEST_MSG_EDIT_FORMAT_HTML;
1755 return MODEST_MSG_EDIT_FORMAT_TEXT;
1759 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1760 ModestMsgEditFormat format)
1762 ModestMsgEditWindowPrivate *priv;
1764 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1765 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1768 case MODEST_MSG_EDIT_FORMAT_HTML:
1769 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1771 case MODEST_MSG_EDIT_FORMAT_TEXT:
1772 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1775 g_return_if_reached ();
1779 ModestMsgEditFormatState *
1780 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1782 ModestMsgEditFormatState *format_state = NULL;
1783 ModestMsgEditWindowPrivate *priv;
1784 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1786 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1787 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1789 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1791 format_state = g_new0 (ModestMsgEditFormatState, 1);
1792 format_state->bold = buffer_format->bold&0x1;
1793 format_state->italics = buffer_format->italic&0x1;
1794 format_state->bullet = buffer_format->bullet&0x1;
1795 format_state->color = buffer_format->color;
1796 format_state->font_size = buffer_format->font_size;
1797 format_state->font_family = wp_get_font_name (buffer_format->font);
1798 format_state->justification = buffer_format->justification;
1799 g_free (buffer_format);
1801 return format_state;
1806 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1807 const ModestMsgEditFormatState *format_state)
1809 ModestMsgEditWindowPrivate *priv;
1810 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1811 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1812 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1813 g_return_if_fail (format_state != NULL);
1815 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1816 gtk_widget_grab_focus (priv->msg_body);
1817 buffer_format->bold = (format_state->bold != FALSE);
1818 buffer_format->italic = (format_state->italics != FALSE);
1819 buffer_format->color = format_state->color;
1820 buffer_format->font_size = format_state->font_size;
1821 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1822 buffer_format->justification = format_state->justification;
1823 buffer_format->bullet = format_state->bullet;
1825 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1827 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1828 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1829 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1830 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1831 buffer_format->cs.font = (buffer_format->font != current_format->font);
1832 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1833 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1835 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1836 if (buffer_format->cs.bold) {
1837 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1838 GINT_TO_POINTER (buffer_format->bold&0x1));
1840 if (buffer_format->cs.italic) {
1841 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1842 GINT_TO_POINTER (buffer_format->italic&0x1));
1844 if (buffer_format->cs.color) {
1845 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1846 GINT_TO_POINTER (&(buffer_format->color)));
1848 if (buffer_format->cs.font_size) {
1849 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1850 GINT_TO_POINTER (buffer_format->font_size));
1852 if (buffer_format->cs.justification) {
1853 switch (buffer_format->justification) {
1854 case GTK_JUSTIFY_LEFT:
1855 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1856 GINT_TO_POINTER(TRUE));
1858 case GTK_JUSTIFY_CENTER:
1859 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1860 GINT_TO_POINTER(TRUE));
1862 case GTK_JUSTIFY_RIGHT:
1863 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1864 GINT_TO_POINTER(TRUE));
1871 if (buffer_format->cs.font) {
1872 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1873 GINT_TO_POINTER (buffer_format->font));
1875 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1876 if (buffer_format->cs.bullet) {
1877 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1878 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1880 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1882 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1884 g_free (buffer_format);
1885 g_free (current_format);
1887 /* Check dimming rules */
1888 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1889 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1893 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1895 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1897 ModestWindowPrivate *parent_priv;
1898 ModestMsgEditWindowPrivate *priv;
1902 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1903 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1905 ldots_len = g_unichar_to_utf8 (0x2026, ldots);
1906 ldots[ldots_len] = '\0';
1908 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1909 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1910 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1911 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1913 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1914 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1915 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1918 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1920 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1921 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1923 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1924 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1926 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1927 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1930 switch (buffer_format->justification)
1932 case GTK_JUSTIFY_LEFT:
1933 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1935 case GTK_JUSTIFY_CENTER:
1936 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1938 case GTK_JUSTIFY_RIGHT:
1939 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1946 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1948 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1949 G_CALLBACK (modest_msg_edit_window_color_button_change),
1951 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1952 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1953 G_CALLBACK (modest_msg_edit_window_color_button_change),
1956 if (priv->current_size_index != buffer_format->font_size) {
1960 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1961 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1965 priv->current_size_index = buffer_format->font_size;
1967 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
1968 markup = g_strconcat ("<span font_family='Sans'>",
1969 size_text, ldots, "</span>", NULL);
1971 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1975 gtk_tree_path_free (path);
1978 if (priv->current_face_index != buffer_format->font) {
1982 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
1983 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
1987 priv->current_face_index = buffer_format->font;
1988 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
1989 markup = g_strconcat ("<span font_family='", face_name, "'>Tt", ldots, "</span>", NULL);
1990 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1997 g_free (buffer_format);
2001 #ifdef MODEST_HILDON_VERSION_0
2003 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2006 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2007 ModestMsgEditWindowPrivate *priv;
2008 GtkWidget *dialog = NULL;
2010 GdkColor *new_color = NULL;
2012 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2013 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2015 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2016 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2017 g_free (buffer_format);
2019 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2020 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2021 if (new_color != NULL) {
2022 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2023 (gpointer) new_color);
2026 gtk_widget_destroy (dialog);
2031 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2034 ModestMsgEditWindowPrivate *priv;
2035 GtkWidget *dialog = NULL;
2037 GdkColor *old_color = NULL;
2038 const GdkColor *new_color = NULL;
2040 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2041 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2043 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2044 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2046 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2047 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2048 if (new_color != NULL)
2049 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2051 gtk_widget_destroy (dialog);
2057 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2060 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2061 ModestMsgEditWindowPrivate *priv;
2062 GtkWidget *dialog = NULL;
2064 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2065 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2067 dialog = hildon_color_chooser_new ();
2068 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2069 g_free (buffer_format);
2071 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2073 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2074 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2077 gtk_widget_destroy (dialog);
2082 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2085 ModestMsgEditWindowPrivate *priv;
2086 GtkWidget *dialog = NULL;
2087 GdkColor *old_color = NULL;
2089 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2090 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2092 dialog = hildon_color_chooser_new ();
2093 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2095 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2097 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2098 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2100 gtk_widget_destroy (dialog);
2103 #endif /*!MODEST_HILDON_VERSION_0*/
2108 create_stream_for_uri (const gchar* uri)
2113 TnyStream *result = NULL;
2115 GnomeVFSHandle *handle = NULL;
2116 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2117 if (test == GNOME_VFS_OK) {
2118 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2119 /* Streams over OBEX (Bluetooth) are not seekable but
2120 * we expect them to be (we might need to read them
2121 * several times). So if this is a Bluetooth URI just
2122 * read the whole file into memory (this is not a fast
2123 * protocol so we can assume that these files are not
2124 * going to be very big) */
2125 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2126 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2127 TnyStream *memstream = tny_camel_mem_stream_new ();
2128 tny_stream_write_to_stream (vfssstream, memstream);
2129 g_object_unref (vfssstream);
2132 result = vfssstream;
2140 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2143 ModestMsgEditWindowPrivate *priv;
2144 GtkWidget *dialog = NULL;
2146 GSList *uris = NULL;
2147 GSList *uri_node = NULL;
2149 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2151 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2152 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2153 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2155 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2157 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2158 GTK_WINDOW (dialog), GTK_WINDOW (window));
2160 response = gtk_dialog_run (GTK_DIALOG (dialog));
2162 case GTK_RESPONSE_OK:
2163 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2168 gtk_widget_destroy (dialog);
2170 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2172 GnomeVFSHandle *handle = NULL;
2173 GnomeVFSResult result;
2174 GtkTextIter position;
2175 GtkTextMark *insert_mark;
2177 uri = (const gchar *) uri_node->data;
2178 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2179 if (result == GNOME_VFS_OK) {
2181 GnomeVFSFileInfo *info;
2182 gchar *filename, *basename, *escaped_filename;
2183 TnyMimePart *mime_part;
2185 const gchar *mime_type = NULL;
2186 GnomeVFSURI *vfs_uri;
2187 guint64 stream_size;
2189 gnome_vfs_close (handle);
2190 vfs_uri = gnome_vfs_uri_new (uri);
2192 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2193 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2194 g_free (escaped_filename);
2195 gnome_vfs_uri_unref (vfs_uri);
2196 info = gnome_vfs_file_info_new ();
2198 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2199 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2201 mime_type = gnome_vfs_file_info_get_mime_type (info);
2203 mime_part = tny_platform_factory_new_mime_part
2204 (modest_runtime_get_platform_factory ());
2206 TnyStream *stream = create_stream_for_uri (uri);
2208 if (stream == NULL) {
2210 modest_platform_information_banner (NULL, NULL,
2211 _FM("sfil_ib_opening_not_allowed"));
2213 g_object_unref (mime_part);
2214 gnome_vfs_file_info_unref (info);
2218 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2220 content_id = g_strdup_printf ("%d", priv->next_cid);
2221 tny_mime_part_set_content_id (mime_part, content_id);
2222 g_free (content_id);
2225 basename = g_path_get_basename (filename);
2226 tny_mime_part_set_filename (mime_part, basename);
2229 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2231 if (pixbuf != NULL) {
2232 priv->images_size += stream_size;
2233 priv->images_count ++;
2234 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2235 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2236 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2237 g_object_unref (pixbuf);
2240 tny_list_prepend (priv->images, (GObject *) mime_part);
2241 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2243 g_object_unref (mime_part);
2244 gnome_vfs_file_info_unref (info);
2253 on_attach_file_response (GtkDialog *dialog,
2257 GSList *uris = NULL;
2259 GnomeVFSFileSize total_size, allowed_size;
2260 ModestMsgEditWindow *window;
2261 ModestMsgEditWindowPrivate *priv;
2266 case GTK_RESPONSE_OK:
2267 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2273 window = MODEST_MSG_EDIT_WINDOW (user_data);
2274 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2276 /* allowed size is the maximum size - what's already there */
2277 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2278 &att_num, &att_size);
2279 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2282 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2284 const gchar *uri = (const gchar *) uri_node->data;
2287 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2289 if (total_size > allowed_size) {
2290 g_warning ("%s: total size: %u",
2291 __FUNCTION__, (unsigned int)total_size);
2294 allowed_size -= total_size;
2296 g_slist_foreach (uris, (GFunc) g_free, NULL);
2297 g_slist_free (uris);
2299 gtk_widget_destroy (GTK_WIDGET (dialog));
2303 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2305 GtkWidget *dialog = NULL;
2306 ModestMsgEditWindowPrivate *priv;
2308 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2310 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2312 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2315 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2316 GTK_FILE_CHOOSER_ACTION_OPEN);
2317 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2318 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2319 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2320 GTK_WINDOW (dialog), GTK_WINDOW (window));
2322 /* Connect to response & show */
2323 g_signal_connect (dialog, "response",
2324 G_CALLBACK (on_attach_file_response), window);
2325 gtk_widget_show (dialog);
2330 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2332 GnomeVFSFileSize allowed_size)
2335 GnomeVFSHandle *handle = NULL;
2336 ModestMsgEditWindowPrivate *priv;
2337 GnomeVFSResult result;
2338 GnomeVFSFileSize size = 0;
2339 g_return_val_if_fail (window, 0);
2340 g_return_val_if_fail (uri, 0);
2342 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2344 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2345 if (result == GNOME_VFS_OK) {
2346 TnyMimePart *mime_part;
2348 const gchar *mime_type = NULL;
2350 gchar *escaped_filename;
2353 GnomeVFSFileInfo *info;
2354 GnomeVFSURI *vfs_uri;
2356 gnome_vfs_close (handle);
2357 vfs_uri = gnome_vfs_uri_new (uri);
2360 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2361 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2362 g_free (escaped_filename);
2363 gnome_vfs_uri_unref (vfs_uri);
2365 info = gnome_vfs_file_info_new ();
2367 if (gnome_vfs_get_file_info (uri,
2369 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2371 mime_type = gnome_vfs_file_info_get_mime_type (info);
2372 mime_part = tny_platform_factory_new_mime_part
2373 (modest_runtime_get_platform_factory ());
2375 /* try to get the attachment's size; this may fail for weird
2376 * file systems, like obex, upnp... */
2377 if (allowed_size != 0 &&
2378 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2380 if (size > allowed_size) {
2381 modest_platform_information_banner (NULL, NULL,
2382 _FM("sfil_ib_opening_not_allowed"));
2386 g_warning ("%s: could not get attachment size", __FUNCTION__);
2388 stream = create_stream_for_uri (uri);
2390 if (stream == NULL) {
2392 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2394 g_object_unref (mime_part);
2395 gnome_vfs_file_info_unref (info);
2399 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2400 g_object_unref (stream);
2402 content_id = g_strdup_printf ("%d", priv->next_cid);
2403 tny_mime_part_set_content_id (mime_part, content_id);
2404 g_free (content_id);
2407 basename = g_path_get_basename (filename);
2408 tny_mime_part_set_filename (mime_part, basename);
2411 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2412 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2414 info->size == 0, info->size);
2415 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2416 gtk_widget_show_all (priv->attachments_caption);
2417 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2419 g_object_unref (mime_part);
2420 gnome_vfs_file_info_unref (info);
2427 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2430 ModestMsgEditWindowPrivate *priv;
2433 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2434 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2436 if (att_list == NULL) {
2437 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2438 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2439 g_object_unref (att_list);
2444 g_object_ref (att_list);
2447 if (tny_list_get_length (att_list) == 0) {
2448 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2450 gboolean dialog_response;
2451 gchar *message = NULL;
2452 gchar *filename = NULL;
2454 if (tny_list_get_length (att_list) == 1) {
2456 iter = tny_list_create_iterator (att_list);
2457 part = (TnyMimePart *) tny_iterator_get_current (iter);
2458 g_object_unref (iter);
2459 if (TNY_IS_MSG (part)) {
2460 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2462 filename = tny_header_dup_subject (header);
2463 g_object_unref (header);
2465 if (filename == NULL) {
2466 filename = g_strdup (_("mail_va_no_subject"));
2469 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2471 g_object_unref (part);
2473 filename = g_strdup ("");
2475 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2476 "emev_nc_delete_attachments",
2477 tny_list_get_length (att_list)), filename);
2480 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2484 if (dialog_response != GTK_RESPONSE_OK) {
2485 g_object_unref (att_list);
2489 for (iter = tny_list_create_iterator (att_list);
2490 !tny_iterator_is_done (iter);
2491 tny_iterator_next (iter)) {
2492 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2493 const gchar *att_id;
2494 tny_list_remove (priv->attachments, (GObject *) mime_part);
2496 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2498 if (tny_list_get_length (priv->attachments) == 0)
2499 gtk_widget_hide (priv->attachments_caption);
2500 att_id = tny_mime_part_get_content_id (mime_part);
2502 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2504 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2505 g_object_unref (mime_part);
2507 g_object_unref (iter);
2510 g_object_unref (att_list);
2512 /* if the last attachment has been removed, focus the Subject: field */
2513 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2514 gtk_widget_grab_focus (priv->subject_field);
2518 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2521 ModestMsgEditWindowPrivate *priv;
2522 GdkColor *new_color;
2523 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2525 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2526 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2529 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2531 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2533 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2535 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2540 font_size_clicked (GtkToolButton *button,
2541 ModestMsgEditWindow *window)
2543 ModestMsgEditWindowPrivate *priv;
2544 GtkWidget *selector, *dialog;
2546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2548 selector = hildon_touch_selector_new ();
2549 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2550 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2552 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2553 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2555 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2559 WPTextBufferFormat format;
2563 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2565 memset (&format, 0, sizeof (format));
2566 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2568 format.cs.font_size = TRUE;
2569 format.cs.text_position = TRUE;
2570 format.cs.font = TRUE;
2571 format.font_size = new_index;
2572 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2574 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2575 GINT_TO_POINTER (new_index)))
2576 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2578 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2579 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2580 ldots_len = g_unichar_to_utf8 (0x2026, ldots);
2581 ldots[ldots_len] = '\0';
2582 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2583 size_text, ldots, "</span>", NULL);
2585 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2589 gtk_widget_destroy (dialog);
2591 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2596 font_face_clicked (GtkToolButton *button,
2597 ModestMsgEditWindow *window)
2599 ModestMsgEditWindowPrivate *priv;
2600 GtkWidget *selector, *dialog;
2601 GtkCellRenderer *renderer;
2603 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2605 selector = hildon_touch_selector_new ();
2606 renderer = gtk_cell_renderer_text_new ();
2607 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2608 renderer, "family", 0, "text", 0, NULL);
2609 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2611 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2612 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2614 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2615 gint new_font_index;
2619 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2620 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2621 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2627 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2629 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2630 GINT_TO_POINTER(new_font_index)))
2631 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2633 ldots_len = g_unichar_to_utf8 (0x2026, ldots);
2634 ldots[ldots_len] = '\0';
2635 markup = g_strconcat ("<span font_family='", face_name, "'>Tt", ldots, "</span>", NULL);
2636 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2638 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2642 gtk_tree_path_free (path);
2645 gtk_widget_destroy (dialog);
2647 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2652 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2655 ModestMsgEditWindowPrivate *priv = NULL;
2656 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2658 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2659 if (!priv->update_caption_visibility)
2662 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2664 gtk_widget_show (priv->cc_caption);
2666 gtk_widget_hide (priv->cc_caption);
2668 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2672 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2675 ModestMsgEditWindowPrivate *priv = NULL;
2676 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2678 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2679 if (!priv->update_caption_visibility)
2682 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2684 gtk_widget_show (priv->bcc_caption);
2686 gtk_widget_hide (priv->bcc_caption);
2688 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2692 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2693 ModestRecptEditor *editor)
2695 ModestMsgEditWindowPrivate *priv;
2697 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2698 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2700 /* we check for low-mem; in that case, show a warning, and don't allow
2701 * for the addressbook
2703 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2706 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2708 if (editor == NULL) {
2709 GtkWidget *view_focus;
2710 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2712 /* This code should be kept in sync with ModestRecptEditor. The
2713 textview inside the recpt editor is the one that really gets the
2714 focus. As it's inside a scrolled window, and this one inside the
2715 hbox recpt editor inherits from, we'll need to go up in the
2716 hierarchy to know if the text view is part of the recpt editor
2717 or if it's a different text entry */
2719 if (gtk_widget_get_parent (view_focus)) {
2720 GtkWidget *first_parent;
2722 first_parent = gtk_widget_get_parent (view_focus);
2723 if (gtk_widget_get_parent (first_parent) &&
2724 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2725 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2730 editor = MODEST_RECPT_EDITOR (priv->to_field);
2734 modest_address_book_select_addresses (editor);
2739 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2741 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2743 modest_msg_edit_window_open_addressbook (window, NULL);
2747 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2748 gboolean show_toolbar)
2750 ModestWindowPrivate *parent_priv;
2752 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2753 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2755 /* We can not just use the code of
2756 modest_msg_edit_window_setup_toolbar because it has a
2757 mixture of both initialization and creation code. */
2759 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2761 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2765 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2766 TnyHeaderFlags priority_flags)
2768 ModestMsgEditWindowPrivate *priv;
2769 ModestWindowPrivate *parent_priv;
2771 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2773 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2774 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2776 if (priv->priority_flags != priority_flags) {
2777 GtkAction *priority_action = NULL;
2779 priv->priority_flags = priority_flags;
2781 switch (priority_flags) {
2782 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2783 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2784 MODEST_HEADER_ICON_HIGH,
2785 HILDON_ICON_SIZE_SMALL);
2786 gtk_widget_show (priv->priority_icon);
2787 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2788 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2790 case TNY_HEADER_FLAG_LOW_PRIORITY:
2791 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2792 MODEST_HEADER_ICON_LOW,
2793 HILDON_ICON_SIZE_SMALL);
2794 gtk_widget_show (priv->priority_icon);
2795 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2796 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2799 gtk_widget_hide (priv->priority_icon);
2800 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2801 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2804 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2805 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2807 gtk_widget_queue_resize (priv->subject_box);
2811 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2814 ModestMsgEditWindowPrivate *priv;
2815 ModestWindowPrivate *parent_priv;
2816 gint current_format;
2818 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2820 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2821 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2823 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2824 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2826 if (current_format != file_format) {
2827 switch (file_format) {
2828 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2829 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2830 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2832 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2836 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2837 response = gtk_dialog_run (GTK_DIALOG (dialog));
2838 gtk_widget_destroy (dialog);
2839 if (response == GTK_RESPONSE_OK) {
2840 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2842 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2843 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2848 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2849 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2850 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2855 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2858 ModestMsgEditWindowPrivate *priv;
2859 WPTextBufferFormat oldfmt, fmt;
2860 gint old_position = 0;
2864 GdkColor *color = NULL;
2865 gboolean bold, bold_set, italic, italic_set;
2866 gboolean underline, underline_set;
2867 gboolean strikethrough, strikethrough_set;
2868 gboolean position_set;
2869 gboolean font_size_set, font_set, color_set;
2872 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2873 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2875 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2876 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2877 GTK_WINDOW(dialog), GTK_WINDOW (window));
2879 /* First we get the currently selected font information */
2880 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2882 switch (oldfmt.text_position) {
2883 case TEXT_POSITION_NORMAL:
2886 case TEXT_POSITION_SUPERSCRIPT:
2894 g_object_set (G_OBJECT (dialog),
2895 "bold", oldfmt.bold != FALSE,
2896 "bold-set", !oldfmt.cs.bold,
2897 "underline", oldfmt.underline != FALSE,
2898 "underline-set", !oldfmt.cs.underline,
2899 "italic", oldfmt.italic != FALSE,
2900 "italic-set", !oldfmt.cs.italic,
2901 "strikethrough", oldfmt.strikethrough != FALSE,
2902 "strikethrough-set", !oldfmt.cs.strikethrough,
2903 "color", &oldfmt.color,
2904 "color-set", !oldfmt.cs.color,
2905 "size", wp_font_size[oldfmt.font_size],
2906 "size-set", !oldfmt.cs.font_size,
2907 "position", old_position,
2908 "position-set", !oldfmt.cs.text_position,
2909 "family", wp_get_font_name (oldfmt.font),
2910 "family-set", !oldfmt.cs.font,
2913 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2914 GTK_WINDOW (dialog), GTK_WINDOW (window));
2915 gtk_widget_show_all (dialog);
2916 priv->font_dialog = dialog;
2917 response = gtk_dialog_run (GTK_DIALOG (dialog));
2918 priv->font_dialog = NULL;
2919 if (response == GTK_RESPONSE_OK) {
2921 g_object_get( dialog,
2923 "bold-set", &bold_set,
2924 "underline", &underline,
2925 "underline-set", &underline_set,
2927 "italic-set", &italic_set,
2928 "strikethrough", &strikethrough,
2929 "strikethrough-set", &strikethrough_set,
2931 "color-set", &color_set,
2933 "size-set", &font_size_set,
2934 "family", &font_name,
2935 "family-set", &font_set,
2936 "position", &position,
2937 "position-set", &position_set,
2942 if (response == GTK_RESPONSE_OK) {
2943 memset(&fmt, 0, sizeof(fmt));
2949 fmt.italic = italic;
2950 fmt.cs.italic = TRUE;
2952 if (underline_set) {
2953 fmt.underline = underline;
2954 fmt.cs.underline = TRUE;
2956 if (strikethrough_set) {
2957 fmt.strikethrough = strikethrough;
2958 fmt.cs.strikethrough = TRUE;
2963 ? TEXT_POSITION_NORMAL
2964 : ( ( position == 1 )
2965 ? TEXT_POSITION_SUPERSCRIPT
2966 : TEXT_POSITION_SUBSCRIPT );
2967 fmt.cs.text_position = TRUE;
2968 fmt.font_size = oldfmt.font_size;
2972 fmt.cs.color = TRUE;
2975 fmt.font = wp_get_font_index(font_name,
2980 if (font_size_set) {
2981 fmt.cs.font_size = TRUE;
2982 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2984 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2985 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2987 gtk_widget_destroy (dialog);
2989 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2993 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2995 ModestMsgEditWindowPrivate *priv;
2997 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2998 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3000 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3002 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3003 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3007 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3009 ModestMsgEditWindowPrivate *priv;
3011 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3012 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3014 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3016 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3017 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3022 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3024 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3026 priv->can_undo = can_undo;
3030 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3032 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3034 priv->can_redo = can_redo;
3038 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3040 ModestMsgEditWindowPrivate *priv;
3041 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3042 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3044 return priv->can_undo;
3048 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3050 ModestMsgEditWindowPrivate *priv;
3051 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3052 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3054 return priv->can_redo;
3059 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3062 GtkTextIter match_start, match_end;
3064 if (image_id == NULL)
3067 gtk_text_buffer_get_start_iter (buffer, &iter);
3069 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3070 GSList *tags = gtk_text_iter_get_tags (&match_start);
3072 for (node = tags; node != NULL; node = g_slist_next (node)) {
3073 GtkTextTag *tag = (GtkTextTag *) node->data;
3074 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3075 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3076 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3078 offset = gtk_text_iter_get_offset (&match_start);
3079 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3080 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3084 gtk_text_iter_forward_char (&iter);
3089 message_is_empty (ModestMsgEditWindow *window)
3091 ModestMsgEditWindowPrivate *priv = NULL;
3093 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3094 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3096 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3097 * so we can ignore markup.
3099 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3102 count = gtk_text_buffer_get_char_count (buf);
3108 msg_body_focus (GtkWidget *focus,
3109 GdkEventFocus *event,
3113 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3114 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3115 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3120 recpt_field_changed (GtkTextBuffer *buffer,
3121 ModestMsgEditWindow *editor)
3123 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3124 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3128 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3130 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3131 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3135 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3138 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3139 GtkTextBuffer *buffer;
3141 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3142 gtk_text_buffer_set_modified (buffer, modified);
3143 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3144 gtk_text_buffer_set_modified (buffer, modified);
3145 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3146 gtk_text_buffer_set_modified (buffer, modified);
3147 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3151 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3153 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3154 const char *account_name;
3155 GtkTextBuffer *buffer;
3157 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3158 if (gtk_text_buffer_get_modified (buffer))
3160 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3161 if (gtk_text_buffer_get_modified (buffer))
3163 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3164 if (gtk_text_buffer_get_modified (buffer))
3166 if (gtk_text_buffer_get_modified (priv->text_buffer))
3168 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3169 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3180 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3182 ModestMsgEditWindowPrivate *priv = NULL;
3184 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3185 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3187 /* check if there's no recipient added */
3188 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3189 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3190 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3191 /* no recipient contents, then select contacts */
3192 modest_msg_edit_window_open_addressbook (window, NULL);
3196 g_object_ref (window);
3197 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3198 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3199 g_object_unref (window);
3202 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3203 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3204 g_object_unref (window);
3207 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3208 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3209 g_object_unref (window);
3213 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3214 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3215 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3216 g_object_unref (window);
3223 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3224 ModestMsgEditWindow *window)
3226 modest_msg_edit_window_offer_attach_file (window);
3230 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3232 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3234 return priv->clipboard_text;
3238 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3240 ModestMsgEditWindow *window)
3242 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3243 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3245 if (!GTK_WIDGET_VISIBLE (window))
3248 g_object_ref (window);
3249 text = gtk_clipboard_wait_for_text (selection_clipboard);
3251 if (priv->clipboard_text != NULL) {
3252 g_free (priv->clipboard_text);
3254 priv->clipboard_text = text;
3256 if (GTK_WIDGET_VISIBLE (window)) {
3257 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3259 g_object_unref (window);
3262 static gboolean clipboard_owner_change_idle (gpointer userdata)
3264 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3265 ModestMsgEditWindowPrivate *priv;
3267 gdk_threads_enter ();
3268 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3269 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3271 priv->clipboard_owner_idle = 0;
3272 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3273 gdk_threads_leave ();
3279 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3281 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3282 if (priv->clipboard_owner_idle == 0) {
3283 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3288 subject_field_move_cursor (GtkEntry *entry,
3289 GtkMovementStep step,
3294 if (!GTK_WIDGET_VISIBLE (window))
3297 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3301 update_window_title (ModestMsgEditWindow *window)
3303 ModestMsgEditWindowPrivate *priv = NULL;
3304 const gchar *subject;
3306 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3307 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3308 if (subject == NULL || subject[0] == '\0')
3309 subject = _("mail_va_new_email");
3311 gtk_window_set_title (GTK_WINDOW (window), subject);
3316 subject_field_changed (GtkEditable *editable,
3317 ModestMsgEditWindow *window)
3319 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3320 update_window_title (window);
3321 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3322 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3323 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3327 subject_field_insert_text (GtkEditable *editable,
3329 gint new_text_length,
3331 ModestMsgEditWindow *window)
3333 GString *result = g_string_new ("");
3335 gint result_len = 0;
3336 const gchar *entry_text = NULL;
3339 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3340 old_length = g_utf8_strlen (entry_text, -1);
3342 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3343 gunichar c = g_utf8_get_char_validated (current, 8);
3344 /* Invalid unichar, stop */
3350 result = g_string_append_unichar (result, c);
3354 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3355 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3358 /* Prevent endless recursion */
3359 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3360 g_signal_emit_by_name (editable, "insert-text",
3361 (gpointer) result->str, (gpointer) result->len,
3362 (gpointer) position, (gpointer) window);
3363 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3367 if (result_len + old_length > 1000) {
3368 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3369 _CS("ckdg_ib_maximum_characters_reached"));
3371 g_string_free (result, TRUE);
3375 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3378 ModestMsgEditWindowPrivate *priv = NULL;
3380 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3381 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3383 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3386 gtk_widget_show_all (priv->find_toolbar);
3387 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3389 gtk_widget_hide_all (priv->find_toolbar);
3390 gtk_widget_grab_focus (priv->msg_body);
3395 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3397 GtkTextIter *match_start,
3398 GtkTextIter *match_end)
3400 GtkTextIter end_iter;
3401 gchar *str_casefold;
3404 gchar *range_casefold;
3407 gboolean result = FALSE;
3414 gtk_text_iter_forward_to_end (&end_iter);
3416 str_casefold = g_utf8_casefold (str, -1);
3417 str_chars_n = strlen (str);
3419 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3420 range_casefold = g_utf8_casefold (range_text, -1);
3421 range_chars_n = strlen (range_casefold);
3423 if (range_chars_n < str_chars_n) {
3424 g_free (str_casefold);
3425 g_free (range_text);
3426 g_free (range_casefold);
3430 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3431 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3432 if (!g_utf8_collate (range_subtext, str_casefold)) {
3433 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3435 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3436 match_start, match_end, NULL);
3437 g_free (found_text);
3439 g_free (range_subtext);
3443 g_free (str_casefold);
3444 g_free (range_text);
3445 g_free (range_casefold);
3452 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3453 ModestMsgEditWindow *window)
3455 gchar *current_search = NULL;
3456 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3458 GtkTextIter selection_start, selection_end;
3459 GtkTextIter match_start, match_end;
3460 gboolean continue_search = FALSE;
3462 if (message_is_empty (window)) {
3463 g_free (priv->last_search);
3464 priv->last_search = NULL;
3465 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3469 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3470 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3471 g_free (current_search);
3472 g_free (priv->last_search);
3473 priv->last_search = NULL;
3474 /* Information banner about empty search */
3475 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3479 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3480 continue_search = TRUE;
3482 g_free (priv->last_search);
3483 priv->last_search = g_strdup (current_search);
3486 if (continue_search) {
3487 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3488 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3489 &match_start, &match_end);
3491 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3493 GtkTextIter buffer_start;
3494 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3495 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3496 &match_start, &match_end);
3498 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3501 /* Mark as selected the string found in search */
3503 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3504 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3505 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3507 g_free (priv->last_search);
3508 priv->last_search = NULL;
3510 g_free (current_search);
3514 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3516 ModestMsgEditWindowPrivate *priv;
3518 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3523 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3526 ModestMsgEditWindowPrivate *priv;
3528 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3533 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3534 ModestMsgEditWindow *window)
3536 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3540 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3543 ModestMsgEditWindowPrivate *priv;
3544 TnyHeader *header = NULL;
3546 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3547 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3549 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3550 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3552 if (priv->draft_msg != NULL) {
3553 g_object_unref (priv->draft_msg);
3556 if (draft != NULL) {
3557 g_object_ref (draft);
3558 header = tny_msg_get_header (draft);
3559 if (priv->msg_uid) {
3560 g_free (priv->msg_uid);
3561 priv->msg_uid = NULL;
3563 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3564 if (GTK_WIDGET_REALIZED (window)) {
3565 if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3566 gtk_widget_destroy (GTK_WIDGET (window));
3572 priv->draft_msg = draft;
3576 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3577 GtkTextIter *start, GtkTextIter *end,
3580 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3581 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3584 if (tag == NULL) return;
3585 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3586 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3587 replace_with_images (window, priv->images);
3592 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3595 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3597 g_return_if_fail (TNY_IS_MIME_PART (part));
3598 tny_list_prepend (priv->attachments, (GObject *) part);
3599 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3600 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3601 gtk_widget_show_all (priv->attachments_caption);
3602 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3606 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3608 ModestMsgEditWindowPrivate *priv;
3610 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3611 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3613 return priv->msg_uid;
3617 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3618 ModestMsgEditWindowWidgetType widget_type)
3620 ModestMsgEditWindowPrivate *priv;
3622 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3623 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3625 switch (widget_type) {
3626 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3627 return priv->msg_body;
3629 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3630 return priv->to_field;
3632 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3633 return priv->cc_field;
3635 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3636 return priv->bcc_field;
3638 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3639 return priv->subject_field;
3641 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3642 return priv->attachments_view;
3650 remove_tags (WPTextBuffer *buffer)
3652 GtkTextIter start, end;
3654 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3655 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3657 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3661 on_account_removed (TnyAccountStore *account_store,
3662 TnyAccount *account,
3665 /* Do nothing if it's a store account, because we use the
3666 transport to send the messages */
3667 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3668 const gchar *parent_acc = NULL;
3669 const gchar *our_acc = NULL;
3671 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3672 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3673 /* Close this window if I'm showing a message of the removed account */
3674 if (strcmp (parent_acc, our_acc) == 0)
3675 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3680 from_field_changed (HildonPickerButton *button,
3681 ModestMsgEditWindow *self)
3683 ModestMsgEditWindowPrivate *priv;
3684 gboolean has_old_signature, has_new_signature;
3686 GtkTextIter match_start, match_end;
3687 ModestAccountMgr *mgr;
3689 gchar *full_signature;
3691 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3693 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3694 mgr = modest_runtime_get_account_mgr ();
3695 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3696 if (has_old_signature) {
3697 full_signature = g_strconcat ("\n--\n", signature, NULL);
3698 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3699 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3701 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3702 &match_start, &match_end, NULL)) {
3705 g_free (full_signature);
3709 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3710 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3711 if (has_new_signature) {
3712 full_signature = g_strconcat ("\n--\n", signature, NULL);
3713 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3714 g_free (full_signature);
3719 typedef struct _MessageSettingsHelper {
3720 ModestMsgEditWindow *window;
3721 GSList *priority_group;
3722 GSList *format_group;
3723 GtkToggleButton *current_priority;
3724 GtkToggleButton *current_format;
3725 } MessageSettingsHelper;
3728 on_priority_toggle (GtkToggleButton *button,
3729 MessageSettingsHelper *helper)
3732 ModestMsgEditWindowPrivate *priv;
3734 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3735 if (gtk_toggle_button_get_active (button)) {
3737 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3738 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3739 if ((node_button != button) &&
3740 gtk_toggle_button_get_active (node_button)) {
3741 gtk_toggle_button_set_active (node_button, FALSE);
3744 helper->current_priority = button;
3746 gboolean found = FALSE;
3747 /* If no one is active, activate it again */
3748 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3749 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3750 if (gtk_toggle_button_get_active (node_button)) {
3756 gtk_toggle_button_set_active (button, TRUE);
3762 on_format_toggle (GtkToggleButton *button,
3763 MessageSettingsHelper *helper)
3766 ModestMsgEditWindowPrivate *priv;
3768 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3769 if (gtk_toggle_button_get_active (button)) {
3771 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3772 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3773 if ((node_button != button) &&
3774 gtk_toggle_button_get_active (node_button)) {
3775 gtk_toggle_button_set_active (node_button, FALSE);
3778 helper->current_format = button;
3780 gboolean found = FALSE;
3781 /* If no one is active, activate it again */
3782 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3783 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3784 if (gtk_toggle_button_get_active (node_button)) {
3790 gtk_toggle_button_set_active (button, TRUE);
3797 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3802 GtkWidget *priority_hbox;
3803 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3804 GtkWidget *captioned;
3805 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3806 GtkWidget *format_hbox;
3807 GtkWidget *html_toggle, *text_toggle;
3808 ModestMsgEditWindowPrivate *priv;
3809 MessageSettingsHelper helper = {0,};
3811 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3812 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3813 helper.window = window;
3814 helper.priority_group = NULL;
3815 helper.format_group = NULL;
3817 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3818 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3820 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3821 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3822 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3823 vbox = gtk_vbox_new (FALSE, 0);
3824 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3825 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3826 gtk_container_add (GTK_CONTAINER (align), vbox);
3827 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3828 gtk_widget_show (align);
3829 gtk_widget_show (vbox);
3831 /* Priority toggles */
3832 priority_hbox = gtk_hbox_new (TRUE, 0);
3833 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3834 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3835 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3836 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3837 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3838 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3839 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3840 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3841 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3842 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3843 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3844 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3845 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3846 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3847 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3848 gtk_widget_show_all (priority_hbox);
3849 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3850 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3851 gtk_widget_show (captioned);
3852 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3854 /* format toggles */
3855 format_hbox = gtk_hbox_new (TRUE, 0);
3856 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3857 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3858 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3859 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3860 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3861 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3862 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3863 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3864 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3865 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3866 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3867 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3868 gtk_widget_show_all (format_hbox);
3869 gtk_widget_show (format_hbox);
3870 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3873 g_object_unref (title_sizegroup);
3874 g_object_unref (value_sizegroup);
3876 /* Set current values */
3877 switch (priv->priority_flags) {
3878 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3879 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3880 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3882 case TNY_HEADER_FLAG_LOW_PRIORITY:
3883 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3884 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3887 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3888 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3892 switch (modest_msg_edit_window_get_format (window)) {
3893 case MODEST_MSG_EDIT_FORMAT_TEXT:
3894 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3895 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3897 case MODEST_MSG_EDIT_FORMAT_HTML:
3899 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3900 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3904 /* Signal connects */
3905 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3906 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3907 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3908 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3909 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3911 /* Save settings if the user clicked on done */
3912 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3913 TnyHeaderFlags flags;
3914 ModestMsgEditFormat old_format, new_format;
3916 /* Set priority flags */
3917 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3918 if (priv->priority_flags != flags)
3919 modest_msg_edit_window_set_priority_flags (window, flags);
3921 /* Set edit format */
3922 old_format = modest_msg_edit_window_get_format (window);
3923 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3924 if (old_format != new_format) {
3925 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3926 modest_msg_edit_window_set_file_format (window, file_format);
3930 gtk_widget_destroy (dialog);
3931 g_slist_free (helper.priority_group);
3935 on_message_settings (GtkAction *action,
3936 ModestMsgEditWindow *window)
3938 modest_msg_edit_window_show_msg_settings_dialog (window);
3942 on_cc_button_toggled (HildonCheckButton *button,
3943 ModestMsgEditWindow *window)
3945 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3947 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3948 hildon_check_button_get_active (button));
3952 on_bcc_button_toggled (HildonCheckButton *button,
3953 ModestMsgEditWindow *window)
3955 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3957 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3958 hildon_check_button_get_active (button));
3962 setup_menu (ModestMsgEditWindow *self)
3964 ModestMsgEditWindowPrivate *priv = NULL;
3966 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3968 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3970 /* Settings menu buttons */
3971 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3972 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3974 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3975 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3976 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3978 priv->cc_button = hildon_check_button_new (0);
3979 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
3980 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
3982 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
3984 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
3985 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
3986 priv->bcc_button = hildon_check_button_new (0);
3987 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
3988 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
3990 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
3992 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
3993 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
3995 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
3996 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
3997 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
3998 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3999 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4000 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4001 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4002 APP_MENU_CALLBACK (on_message_settings),
4004 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4005 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),