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>
39 #include <modest-account-protocol.h>
43 #include <modest-account-mgr.h>
44 #include <modest-account-mgr-helpers.h>
46 #include <widgets/modest-msg-edit-window.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 <modest-scrollable.h>
67 #include <modest-isearch-toolbar.h>
68 #include "modest-msg-edit-window-ui-dimming.h"
70 #include "widgets/modest-msg-edit-window-ui.h"
71 #include <libgnomevfs/gnome-vfs-mime.h>
72 #include <modest-utils.h>
73 #include <modest-ui-constants.h>
74 #include <modest-toolkit-utils.h>
76 #ifdef MODEST_USE_CALENDAR_WIDGETS
77 #include <calendar-ui-widgets.h>
79 #ifdef MODEST_TOOLKIT_HILDON2
80 #include <hildon/hildon.h>
81 #include "modest-maemo-utils.h"
82 #include "modest-hildon-includes.h"
83 #include "modest-color-button.h"
86 #define DEFAULT_MAIN_VBOX_SPACING 0
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #ifdef MODEST_TOOLKIT_HILDON2
90 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
91 #define DEFAULT_FONT_SCALE 1.5
92 #define DEFAULT_FONT_SIZE 3
93 #define DEFAULT_FONT 2
95 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
96 #define DEFAULT_FONT_SCALE 1.0
97 #define DEFAULT_FONT_SIZE 2
98 #define DEFAULT_FONT 2
100 #define ATTACHMENT_BUTTON_WIDTH 118
101 #define MAX_FROM_VALUE 36
102 #define MAX_BODY_LENGTH 128*1024
103 #define MAX_BODY_LINES 2048
105 static gboolean is_wp_text_buffer_started = FALSE;
107 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
108 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
109 static void modest_msg_edit_window_finalize (GObject *obj);
111 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
112 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
113 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
115 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
116 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
117 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
118 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
119 GtkTextIter *start, GtkTextIter *end,
121 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
122 static void body_insert_text (GtkTextBuffer *buffer,
123 GtkTextIter *location,
126 ModestMsgEditWindow *window);
127 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
128 static void subject_field_insert_text (GtkEditable *editable,
130 gint new_text_length,
132 ModestMsgEditWindow *window);
133 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
135 #ifdef MODEST_TOOLKIT_HILDON2
136 static void font_face_clicked (GtkToolButton *button,
137 ModestMsgEditWindow *window);
139 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
142 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
144 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
145 ModestRecptEditor *editor);
146 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
147 ModestMsgEditWindow *window);
149 /* ModestWindow methods implementation */
150 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
151 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
152 gboolean show_toolbar);
153 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
155 ModestMsgEditWindow *window);
156 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
157 static void subject_field_move_cursor (GtkEntry *entry,
158 GtkMovementStep step,
162 static void update_window_title (ModestMsgEditWindow *window);
165 static void modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
166 ModestMsgEditWindow *window);
167 static void modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
168 ModestMsgEditWindow *window);
169 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
171 GtkTextIter *match_start,
172 GtkTextIter *match_end);
174 static void remove_tags (WPTextBuffer *buffer);
176 static void on_account_removed (TnyAccountStore *account_store,
180 static void init_window (ModestMsgEditWindow *obj);
182 gboolean scroll_drag_timeout (gpointer userdata);
183 static void correct_scroll (ModestMsgEditWindow *w);
184 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
185 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
186 ModestMsgEditWindow *userdata);
187 static void text_buffer_mark_set (GtkTextBuffer *buffer,
190 ModestMsgEditWindow *userdata);
191 static void on_message_settings (GtkAction *action,
192 ModestMsgEditWindow *window);
193 static void setup_menu (ModestMsgEditWindow *self);
195 static void from_field_changed (GtkWidget *button,
196 ModestMsgEditWindow *self);
197 static void font_size_clicked (GtkToolButton *button,
198 ModestMsgEditWindow *window);
199 static void update_signature (ModestMsgEditWindow *self,
200 const gchar *old_account,
201 const gchar *new_account);
202 static void update_branding (ModestMsgEditWindow *self,
203 const gchar *new_account);
204 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
205 const gchar *label, GtkWidget *control);
206 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
207 static void DEBUG_BUFFER (WPTextBuffer *buffer)
211 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
213 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
214 while (!gtk_text_iter_is_end (&iter)) {
215 GString *output = g_string_new ("");
216 GSList *toggled_tags;
219 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
220 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
221 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
222 GtkTextTag *tag = (GtkTextTag *) node->data;
224 g_object_get (G_OBJECT (tag), "name", &name, NULL);
225 output = g_string_append (output, name);
226 g_string_append (output, " ");
228 output = g_string_append (output, "] OPENED [ ");
229 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
230 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
231 GtkTextTag *tag = (GtkTextTag *) node->data;
233 g_object_get (G_OBJECT (tag), "name", &name, NULL);
234 output = g_string_append (output, name);
235 g_string_append (output, " ");
237 output = g_string_append (output, "]\n");
238 g_debug ("%s", output->str);
239 g_string_free (output, TRUE);
240 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
242 g_debug ("END BUFFER");
246 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
247 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
251 /* static gboolean */
252 /* on_key_pressed (GtkWidget *self, */
253 /* GdkEventKey *event, */
254 /* gpointer user_data); */
256 /* list my signals */
263 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
264 struct _ModestMsgEditWindowPrivate {
266 GtkWidget *header_box;
268 ModestPairList *from_field_protos;
269 GtkWidget *from_field;
270 gchar *last_from_account;
271 gchar *original_account_name;
276 gchar *original_mailbox;
280 GtkWidget *bcc_field;
281 GtkWidget *subject_field;
282 GtkWidget *attachments_view;
283 GtkWidget *priority_icon;
284 GtkWidget *subject_box;
285 GtkWidget *send_button;
287 GtkWidget *cc_caption;
288 GtkWidget *bcc_caption;
289 gboolean update_caption_visibility;
290 GtkWidget *attachments_caption;
292 GtkTextBuffer *text_buffer;
294 GtkWidget *font_size_toolitem;
295 GtkWidget *font_face_toolitem;
296 GtkWidget *font_color_button;
297 GtkWidget *font_color_toolitem;
298 GSList *font_items_group;
299 GtkTreeModel *faces_model;
300 gint current_face_index;
301 GtkWidget *font_tool_button_label;
302 GtkTreeModel *sizes_model;
303 gint current_size_index;
304 GtkWidget *size_tool_button_label;
306 GtkWidget *isearch_toolbar;
309 GtkWidget *font_dialog;
311 GtkWidget *scrollable;
312 guint correct_scroll_idle;
313 guint scroll_drag_timeout_id;
317 TnyList *attachments;
322 TnyHeaderFlags priority_flags;
324 gboolean can_undo, can_redo;
325 gulong clipboard_change_handler_id;
326 gulong default_clipboard_change_handler_id;
327 gulong account_removed_handler_id;
328 guint clipboard_owner_idle;
329 gchar *clipboard_text;
338 GtkWidget *cc_button;
339 GtkWidget *bcc_button;
341 GtkWidget *max_chars_banner;
343 GtkWidget *brand_icon;
344 GtkWidget *brand_label;
345 GtkWidget *brand_container;
348 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
349 MODEST_TYPE_MSG_EDIT_WINDOW, \
350 ModestMsgEditWindowPrivate))
352 static GtkWindowClass *parent_class = NULL;
354 /* uncomment the following if you have defined any signals */
355 /* static guint signals[LAST_SIGNAL] = {0}; */
358 modest_msg_edit_window_get_type (void)
360 static GType my_type = 0;
362 static const GTypeInfo my_info = {
363 sizeof(ModestMsgEditWindowClass),
364 NULL, /* base init */
365 NULL, /* base finalize */
366 (GClassInitFunc) modest_msg_edit_window_class_init,
367 NULL, /* class finalize */
368 NULL, /* class data */
369 sizeof(ModestMsgEditWindow),
371 (GInstanceInitFunc) modest_msg_edit_window_init,
374 my_type = g_type_register_static (
375 #ifdef MODEST_TOOLKIT_HILDON2
376 MODEST_TYPE_HILDON2_WINDOW,
378 MODEST_TYPE_SHELL_WINDOW,
380 "ModestMsgEditWindow",
388 save_state (ModestWindow *self)
390 modest_widget_memory_save (modest_runtime_get_conf(),
391 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
396 restore_settings (ModestMsgEditWindow *self)
398 ModestConf *conf = NULL;
400 conf = modest_runtime_get_conf ();
402 /* Dim at start clipboard actions */
403 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
408 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
410 GObjectClass *gobject_class;
411 ModestWindowClass *modest_window_class;
412 gobject_class = (GObjectClass*) klass;
413 modest_window_class = (ModestWindowClass*) klass;
415 parent_class = g_type_class_peek_parent (klass);
416 gobject_class->finalize = modest_msg_edit_window_finalize;
418 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
419 modest_window_class->save_state_func = save_state;
420 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
422 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
426 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
428 ModestMsgEditWindowPrivate *priv;
429 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
431 priv->msg_body = NULL;
432 priv->from_field = NULL;
433 priv->to_field = NULL;
434 priv->cc_field = NULL;
435 priv->bcc_field = NULL;
436 priv->subject_field = NULL;
437 priv->attachments = TNY_LIST (tny_simple_list_new ());
438 priv->images = TNY_LIST (tny_simple_list_new ());
439 priv->images_size = 0;
440 priv->images_count = 0;
443 priv->cc_caption = NULL;
444 priv->bcc_caption = NULL;
445 priv->update_caption_visibility = FALSE;
447 priv->priority_flags = 0;
449 priv->isearch_toolbar = NULL;
450 priv->last_search = NULL;
452 priv->draft_msg = NULL;
453 priv->outbox_msg = NULL;
454 priv->msg_uid = NULL;
456 priv->can_undo = FALSE;
457 priv->can_redo = FALSE;
458 priv->clipboard_change_handler_id = 0;
459 priv->default_clipboard_change_handler_id = 0;
460 priv->account_removed_handler_id = 0;
461 priv->clipboard_owner_idle = 0;
462 priv->clipboard_text = NULL;
465 priv->scroll_drag_timeout_id = 0;
466 priv->correct_scroll_idle = 0;
467 priv->last_upper = 0.0;
469 priv->font_dialog = NULL;
470 priv->app_menu = NULL;
472 priv->references = NULL;
473 priv->in_reply_to = NULL;
474 priv->max_chars_banner = NULL;
476 if (!is_wp_text_buffer_started) {
477 is_wp_text_buffer_started = TRUE;
478 wp_text_buffer_library_init ();
482 #ifdef MODEST_TOOLKIT_HILDON2
483 hildon_program_add_window (hildon_program_get_instance(),
489 multimailbox_get_default_mailbox (const gchar *account_name)
491 gchar *transport_account;
492 gchar *result = NULL;
494 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
496 TNY_ACCOUNT_TYPE_TRANSPORT);
497 if (transport_account) {
499 ModestProtocolRegistry *registry;
501 registry = modest_runtime_get_protocol_registry ();
503 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
504 MODEST_ACCOUNT_PROTO, TRUE);
506 ModestProtocol *protocol =
507 modest_protocol_registry_get_protocol_by_name (registry,
508 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
510 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
511 ModestPairList *pair_list;
513 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
516 ModestPair *pair = (ModestPair *) pair_list->data;
517 result = g_strdup ((const gchar *) pair->first);
518 modest_pair_list_free (pair_list);
529 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
531 static ModestPairList*
532 get_transports (void)
534 GSList *transports = NULL;
536 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
537 GSList *accounts = modest_account_mgr_account_names (account_mgr,
538 TRUE /* only enabled accounts. */);
540 GSList *cursor = accounts;
542 gchar *account_name = cursor->data;
545 gchar *transport_account;
546 gboolean multi_mailbox = FALSE;
547 ModestProtocol *protocol = NULL;
549 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
551 transport_account = modest_account_mgr_get_server_account_name
552 (modest_runtime_get_account_mgr (),
554 TNY_ACCOUNT_TYPE_TRANSPORT);
555 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
556 ModestPairList *pair_list;
557 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
560 transports = g_slist_concat (transports, pair_list);
561 multi_mailbox = TRUE;
566 if (!multi_mailbox) {
567 gchar *from_string = NULL;
569 from_string = modest_account_mgr_get_from_string (account_mgr,
571 if (from_string && account_name) {
572 gchar *name = account_name;
573 ModestPair *pair = modest_pair_new ((gpointer) name,
574 (gpointer) from_string , TRUE);
575 transports = g_slist_prepend (transports, pair);
580 cursor = cursor->next;
582 g_slist_free (accounts); /* only free the accounts, not the elements,
583 * because they are used in the pairlist */
587 static void window_focus (GtkWindow *window,
591 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
595 scroll_drag_timeout (gpointer userdata)
597 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
598 ModestMsgEditWindowPrivate *priv;
600 /* It could happen that the window was already closed */
601 if (!GTK_WIDGET_VISIBLE (win))
604 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
606 correct_scroll_without_drag_check (win, TRUE);
608 priv->scroll_drag_timeout_id = 0;
614 correct_scroll_without_drag_check_idle (gpointer userdata)
616 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
617 ModestMsgEditWindowPrivate *priv;
619 GdkRectangle rectangle;
620 gint offset_min, offset_max;
624 /* It could happen that the window was already closed */
625 if (!GTK_WIDGET_VISIBLE (w))
628 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
630 insert = gtk_text_buffer_get_insert (priv->text_buffer);
631 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
633 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
634 offset_min = priv->msg_body->allocation.y + rectangle.y;
635 offset_max = offset_min + rectangle.height;
637 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
638 offset_min = MAX (offset_min - 48, 0);
639 offset_max = MIN (offset_max + 48, vadj->upper);
641 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
643 priv->correct_scroll_idle = 0;
648 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
650 ModestMsgEditWindowPrivate *priv;
652 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
654 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
657 if (priv->correct_scroll_idle > 0) {
661 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
662 (GSourceFunc) correct_scroll_without_drag_check_idle,
668 correct_scroll (ModestMsgEditWindow *w)
670 ModestMsgEditWindowPrivate *priv;
672 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
673 if (gtk_grab_get_current () == priv->msg_body) {
674 if (priv->scroll_drag_timeout_id == 0) {
675 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
677 (GSourceFunc) scroll_drag_timeout,
684 correct_scroll_without_drag_check (w, TRUE);
688 text_buffer_end_user_action (GtkTextBuffer *buffer,
689 ModestMsgEditWindow *userdata)
692 correct_scroll (userdata);
696 text_buffer_mark_set (GtkTextBuffer *buffer,
699 ModestMsgEditWindow *userdata)
701 gtk_text_buffer_begin_user_action (buffer);
702 gtk_text_buffer_end_user_action (buffer);
706 cut_clipboard_check (GtkTextView *text_view,
709 GtkTextBuffer *buffer;
711 buffer = gtk_text_view_get_buffer (text_view);
712 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
713 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
718 copy_clipboard_check (GtkTextView *text_view,
721 GtkTextBuffer *buffer;
723 buffer = gtk_text_view_get_buffer (text_view);
724 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
725 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
730 attachment_deleted (ModestAttachmentsView *attachments_view,
733 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
738 body_size_request (GtkWidget *body,
742 /* Make sure the body always get at least 70 pixels */
743 if (req->height < 70)
748 connect_signals (ModestMsgEditWindow *obj)
750 ModestMsgEditWindowPrivate *priv;
752 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
754 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
755 G_CALLBACK (text_buffer_refresh_attributes), obj);
756 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
757 G_CALLBACK (text_buffer_can_undo), obj);
758 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
759 G_CALLBACK (text_buffer_can_redo), obj);
760 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
761 G_CALLBACK (body_changed), obj);
762 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
763 G_CALLBACK (body_insert_text), obj);
764 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
765 G_CALLBACK (body_changed), obj);
766 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
767 G_CALLBACK (text_buffer_end_user_action), obj);
768 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
769 G_CALLBACK (text_buffer_mark_set), obj);
770 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
771 G_CALLBACK (text_buffer_apply_tag), obj);
772 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
773 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
774 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
775 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
776 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
777 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
779 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
780 G_CALLBACK (modest_ui_actions_on_send), obj);
782 if (GTK_IS_COMBO_BOX (priv->from_field)) {
783 g_signal_connect (G_OBJECT (priv->from_field), "changed",
784 G_CALLBACK (from_field_changed), obj);
786 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
787 G_CALLBACK (from_field_changed), obj);
790 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
791 G_CALLBACK (msg_body_focus), obj);
792 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
793 G_CALLBACK (msg_body_focus), obj);
794 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
795 G_CALLBACK (body_size_request), obj);
796 if (GTK_IS_WINDOW (obj)) {
797 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
799 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
800 "changed", G_CALLBACK (recpt_field_changed), obj);
801 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
802 "changed", G_CALLBACK (recpt_field_changed), obj);
803 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
804 "changed", G_CALLBACK (recpt_field_changed), obj);
805 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
806 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
807 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
809 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
810 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
811 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
812 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_close), obj);
814 priv->clipboard_change_handler_id =
815 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
816 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
817 priv->default_clipboard_change_handler_id =
818 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
819 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
821 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
822 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
823 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
827 init_wp_text_view_style ()
829 static gboolean initialized = FALSE;
832 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
838 init_window (ModestMsgEditWindow *obj)
840 GtkWidget *to_caption, *subject_caption;
841 GtkWidget *main_vbox;
842 ModestMsgEditWindowPrivate *priv;
843 GtkActionGroup *action_group;
844 ModestWindowPrivate *parent_priv;
845 GError *error = NULL;
847 GtkSizeGroup *title_size_group;
848 GtkSizeGroup *value_size_group;
849 GtkWidget *window_box;
850 GtkWidget *window_align;
851 #if (GTK_MINOR_VERSION >= 10)
852 GdkAtom deserialize_type;
854 GtkWidget *from_send_hbox;
855 GtkWidget *send_icon;
856 GtkWidget *attachments_label;
857 GtkWidget *branding_box;
858 GtkWidget *from_caption;
860 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
861 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
863 parent_priv->ui_manager = gtk_ui_manager_new();
864 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
865 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
867 /* Add common actions */
868 gtk_action_group_add_actions (action_group,
869 modest_msg_edit_action_entries,
870 G_N_ELEMENTS (modest_msg_edit_action_entries),
872 gtk_action_group_add_actions (action_group,
873 hildon2_msg_edit_action_entries,
874 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
876 gtk_action_group_add_toggle_actions (action_group,
877 modest_msg_edit_toggle_action_entries,
878 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
880 gtk_action_group_add_radio_actions (action_group,
881 modest_msg_edit_alignment_radio_action_entries,
882 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
884 G_CALLBACK (modest_ui_actions_on_change_justify),
886 gtk_action_group_add_radio_actions (action_group,
887 modest_msg_edit_priority_action_entries,
888 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
890 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
892 gtk_action_group_add_radio_actions (action_group,
893 modest_msg_edit_file_format_action_entries,
894 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
895 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
896 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
898 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
899 g_object_unref (action_group);
901 /* Load the UI definition */
902 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
905 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
906 g_clear_error (&error);
909 parent_priv->menubar = NULL;
911 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
912 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
914 /* Note: This ModestPairList* must exist for as long as the picker
915 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
916 * so it can't know how to manage its memory. */
917 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
919 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
920 if (GTK_IS_COMBO_BOX (priv->from_field)) {
921 from_caption = modest_toolkit_utils_create_captioned (title_size_group, NULL,
922 _("mail_va_from"), FALSE,
924 gtk_widget_show (from_caption);
926 #ifdef MODEST_TOOLKIT_HILDON2
927 modest_toolkit_utils_set_hbutton_layout (title_size_group, NULL,
928 _("mail_va_from"), priv->from_field);
929 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
930 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
931 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
932 from_caption = priv->from_field;
936 priv->to_field = modest_recpt_editor_new ();
937 priv->cc_field = modest_recpt_editor_new ();
938 priv->bcc_field = modest_recpt_editor_new ();
939 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
940 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
941 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
942 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
943 priv->priority_icon = gtk_image_new ();
944 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
945 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
946 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
947 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
948 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
950 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
951 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
953 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
954 priv->attachments_view = modest_attachments_view_new (NULL);
955 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
956 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
958 priv->header_box = gtk_vbox_new (FALSE, 0);
960 to_caption = _create_addressbook_box
961 (title_size_group, value_size_group,
962 _("mail_va_to"), priv->to_field);
963 priv->cc_caption = _create_addressbook_box
964 (title_size_group, value_size_group,
965 _("mail_va_cc"), priv->cc_field);
966 priv->bcc_caption = _create_addressbook_box
967 (title_size_group, value_size_group,
968 _("mail_va_hotfix1"), priv->bcc_field);
969 subject_caption = modest_toolkit_utils_create_captioned (title_size_group, value_size_group,
970 _("mail_va_subject"), FALSE, priv->subject_box);
971 priv->attachments_caption = modest_toolkit_utils_create_captioned_with_size_type (NULL, NULL,
972 _("mail_va_attachment"),
974 priv->attachments_view,
975 #ifdef MODEST_TOOLKIT_HILDON2
976 HILDON_SIZE_AUTO_WIDTH |
977 HILDON_SIZE_AUTO_HEIGHT
982 attachments_label = modest_toolkit_utils_captioned_get_label_widget (priv->attachments_caption);
984 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
988 #ifdef MODEST_TOOLKIT_HILDON2
989 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
990 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
992 priv->send_button = gtk_button_new ();
993 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, GTK_ICON_SIZE_BUTTON);
995 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
996 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
998 g_object_unref (title_size_group);
999 g_object_unref (value_size_group);
1001 priv->brand_icon = gtk_image_new ();
1002 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
1003 priv->brand_label = gtk_label_new (NULL);
1004 #ifdef MODEST_TOOLKIT_HILDON2
1005 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
1007 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
1008 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
1009 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
1011 from_send_hbox = gtk_hbox_new (FALSE, 0);
1012 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
1013 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
1015 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
1016 gtk_widget_show (branding_box);
1017 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
1018 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
1020 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
1021 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1022 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
1023 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
1026 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
1027 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
1028 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
1029 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
1030 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
1031 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
1032 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
1033 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1035 init_wp_text_view_style ();
1037 priv->msg_body = modest_wp_text_view_new ();
1040 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1041 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1042 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1043 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1044 #if (GTK_MINOR_VERSION >= 10)
1045 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1046 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1048 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1049 deserialize_type, TRUE);
1051 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1053 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1055 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1057 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1059 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1061 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1063 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1064 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1065 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1067 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1068 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1069 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1071 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1072 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1074 window_box = gtk_vbox_new (FALSE, 0);
1075 gtk_container_add (GTK_CONTAINER(obj), window_box);
1077 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1082 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1084 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1086 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1087 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1088 priv->clipboard_change_handler_id))
1089 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1090 priv->clipboard_change_handler_id);
1091 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1092 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1093 priv->default_clipboard_change_handler_id))
1094 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1095 priv->default_clipboard_change_handler_id);
1097 if (priv->account_removed_handler_id &&
1098 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1099 priv->account_removed_handler_id))
1100 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1101 priv->account_removed_handler_id);
1105 modest_msg_edit_window_finalize (GObject *obj)
1107 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1109 if (priv->max_chars_banner) {
1110 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1111 priv->max_chars_banner = FALSE;
1114 /* Sanity check: shouldn't be needed, the window mgr should
1115 call this function before */
1116 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1118 if (priv->font_dialog != NULL) {
1119 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1122 if (priv->clipboard_text != NULL) {
1123 g_free (priv->clipboard_text);
1124 priv->clipboard_text = NULL;
1127 if (priv->draft_msg != NULL) {
1128 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1129 if (TNY_IS_HEADER (header)) {
1130 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1131 modest_window_mgr_unregister_header (mgr, header);
1133 g_object_unref (priv->draft_msg);
1134 priv->draft_msg = NULL;
1136 if (priv->outbox_msg != NULL) {
1137 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1138 if (TNY_IS_HEADER (header)) {
1139 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1140 modest_window_mgr_unregister_header (mgr, header);
1142 g_object_unref (priv->outbox_msg);
1143 priv->outbox_msg = NULL;
1145 if (priv->correct_scroll_idle > 0) {
1146 g_source_remove (priv->correct_scroll_idle);
1147 priv->correct_scroll_idle = 0;
1149 if (priv->scroll_drag_timeout_id > 0) {
1150 g_source_remove (priv->scroll_drag_timeout_id);
1151 priv->scroll_drag_timeout_id = 0;
1153 if (priv->clipboard_owner_idle > 0) {
1154 g_source_remove (priv->clipboard_owner_idle);
1155 priv->clipboard_owner_idle = 0;
1157 if (priv->original_account_name)
1158 g_free (priv->original_account_name);
1159 if (priv->original_mailbox)
1160 g_free (priv->original_mailbox);
1161 g_free (priv->msg_uid);
1162 g_free (priv->last_search);
1163 g_slist_free (priv->font_items_group);
1164 g_free (priv->references);
1165 g_free (priv->in_reply_to);
1166 g_object_unref (priv->attachments);
1167 g_object_unref (priv->images);
1169 /* This had to stay alive for as long as the picker that used it: */
1170 modest_pair_list_free (priv->from_field_protos);
1172 G_OBJECT_CLASS(parent_class)->finalize (obj);
1176 pixbuf_size_prepared (GdkPixbufLoader *loader,
1179 ModestMsgEditWindow *self)
1181 gint new_height, new_width;
1184 new_height = height;
1188 if (width > IMAGE_MAX_WIDTH) {
1189 new_height = height * IMAGE_MAX_WIDTH / width;
1190 new_width = IMAGE_MAX_WIDTH;
1193 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1197 pixbuf_from_stream (TnyStream *stream,
1198 const gchar *mime_type,
1199 guint64 *stream_size,
1200 ModestMsgEditWindow *self)
1202 GdkPixbufLoader *loader;
1205 GError *error = NULL;
1209 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1211 if (loader == NULL) {
1216 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1218 modest_window_show_progress (MODEST_WINDOW (self), TRUE);
1220 tny_stream_reset (TNY_STREAM (stream));
1221 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1222 unsigned char read_buffer[128];
1224 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1226 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1229 /* Allow some UI responsiveness */
1230 while (gtk_events_pending ())
1231 gtk_main_iteration ();
1233 modest_window_show_progress (MODEST_WINDOW (self), FALSE);
1235 gdk_pixbuf_loader_close (loader, &error);
1238 g_error_free (error);
1239 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1241 g_object_ref (pixbuf);
1242 g_object_unref (loader);
1247 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1248 GdkPixbuf *new_pixbuf;
1250 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1251 gdk_pixbuf_get_width (pixbuf);
1252 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1253 g_object_unref (pixbuf);
1254 pixbuf = new_pixbuf;
1258 *stream_size = size;
1264 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1266 ModestMsgEditWindowPrivate *priv;
1269 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1271 g_object_ref (self);
1272 for (iter = tny_list_create_iterator (attachments);
1273 !tny_iterator_is_done (iter);
1274 tny_iterator_next (iter)) {
1275 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1276 const gchar *cid = tny_mime_part_get_content_id (part);
1277 const gchar *mime_type = tny_mime_part_get_content_type (part);
1278 if ((cid != NULL)&&(mime_type != NULL)) {
1279 guint64 stream_size;
1280 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1281 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1284 g_object_unref (stream);
1286 if (pixbuf != NULL) {
1287 priv->images_count ++;
1288 priv->images_size += stream_size;
1289 #ifndef MODEST_HAVE_LIBWPEDITOR_PLUS
1290 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1292 g_object_unref (pixbuf);
1295 g_object_unref (part);
1297 g_object_unref (iter);
1298 g_object_unref (self);
1302 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1304 TnyMimePart *parent = NULL;
1305 const gchar *content_type = NULL;
1306 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1308 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1310 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1311 parent = g_object_ref (msg);
1312 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1313 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1316 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1317 iter = tny_list_create_iterator (parts);
1318 while (!tny_iterator_is_done (iter)) {
1320 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1321 content_type = tny_mime_part_get_content_type (part);
1322 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1326 g_object_unref (part);
1328 tny_iterator_next (iter);
1330 g_object_unref (iter);
1331 g_object_unref (parts);
1334 if (parent != NULL) {
1335 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1338 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1339 iter = tny_list_create_iterator (parts);
1340 while (!tny_iterator_is_done (iter)) {
1342 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1343 content_type = tny_mime_part_get_content_type (part);
1344 if (content_type && g_str_has_prefix (content_type, "image/")) {
1345 tny_list_prepend (priv->images, (GObject *) part);
1347 g_object_unref (part);
1348 tny_iterator_next (iter);
1350 g_object_unref (iter);
1351 g_object_unref (parts);
1352 g_object_unref (parent);
1357 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1360 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1362 for (iter = tny_list_create_iterator (attachments) ;
1363 !tny_iterator_is_done (iter);
1364 tny_iterator_next (iter)) {
1365 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1366 const gchar *cid = tny_mime_part_get_content_id (part);
1368 char *invalid = NULL;
1369 gint int_cid = strtol (cid, &invalid, 10);
1370 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1371 priv->next_cid = int_cid + 1;
1374 g_object_unref (part);
1376 g_object_unref (iter);
1380 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1383 gchar *to, *cc, *bcc, *subject;
1385 ModestMsgEditWindowPrivate *priv;
1386 ModestWindowPrivate *parent_priv;
1388 TnyHeaderFlags priority_flags;
1389 TnyFolder *msg_folder;
1390 gboolean is_html = FALSE;
1391 gboolean field_view_set;
1393 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1394 g_return_if_fail (TNY_IS_MSG (msg));
1396 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1397 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1399 header = tny_msg_get_header (msg);
1400 to = tny_header_dup_to (header);
1401 cc = tny_header_dup_cc (header);
1402 bcc = tny_header_dup_bcc (header);
1403 subject = tny_header_dup_subject (header);
1405 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1406 priority_flags = tny_header_get_priority (header);
1409 gchar *quoted_names = modest_text_utils_quote_names (to);
1410 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1411 g_free (quoted_names);
1414 field_view_set = TRUE;
1416 gchar *quoted_names = modest_text_utils_quote_names (cc);
1417 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1418 g_free (quoted_names);
1419 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1420 gtk_widget_show (priv->cc_caption);
1421 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1422 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1423 gtk_widget_hide (priv->cc_caption);
1424 field_view_set = FALSE;
1426 modest_togglable_set_active (priv->cc_button, field_view_set);
1428 field_view_set = TRUE;
1430 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1431 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1432 g_free (quoted_names);
1433 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1434 gtk_widget_show (priv->bcc_caption);
1435 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1436 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1437 gtk_widget_hide (priv->bcc_caption);
1438 field_view_set = FALSE;
1440 modest_togglable_set_active (priv->bcc_button, field_view_set);
1444 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1445 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1448 update_window_title (self);
1450 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1451 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1453 if ((body == NULL)||(body[0] == '\0')) {
1455 body = modest_text_utils_convert_to_html ("");
1458 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1459 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1462 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1465 /* Add attachments to the view */
1466 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1467 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1468 if (tny_list_get_length (priv->attachments) == 0) {
1469 gtk_widget_hide (priv->attachments_caption);
1471 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1472 gtk_widget_show_all (priv->attachments_caption);
1474 get_related_images (self, msg);
1475 update_next_cid (self, priv->attachments);
1476 update_next_cid (self, priv->images);
1477 replace_with_images (self, priv->images);
1479 if (preserve_is_rich && !is_html) {
1480 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1481 /* Get the default format required from configuration */
1482 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1483 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1486 /* Set the default focus depending on having already a To: field or not */
1487 if ((!to)||(*to == '\0')) {
1488 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1490 gtk_widget_grab_focus (priv->msg_body);
1493 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1495 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1496 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1498 modest_msg_edit_window_set_modified (self, FALSE);
1500 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1501 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1502 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1503 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1505 if (priv->msg_uid) {
1506 g_free (priv->msg_uid);
1507 priv->msg_uid = NULL;
1510 /* we should set a reference to the incoming message if it is a draft */
1511 msg_folder = tny_msg_get_folder (msg);
1513 if (modest_tny_folder_is_local_folder (msg_folder)) {
1514 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1515 if (type == TNY_FOLDER_TYPE_INVALID)
1516 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1518 if (type == TNY_FOLDER_TYPE_DRAFTS)
1519 priv->draft_msg = g_object_ref(msg);
1520 if (type == TNY_FOLDER_TYPE_OUTBOX)
1521 priv->outbox_msg = g_object_ref(msg);
1522 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1524 g_object_unref (msg_folder);
1533 #ifndef MODEST_TOOLKIT_HILDON2
1535 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1538 GList *item_children, *node;
1539 GtkWidget *bin_child;
1541 bin_child = gtk_bin_get_child (GTK_BIN(item));
1543 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1545 for (node = item_children; node != NULL; node = g_list_next (node)) {
1546 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1547 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1550 g_list_free (item_children);
1554 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1557 GList *item_children, *node;
1559 box = gtk_bin_get_child (GTK_BIN (item));
1560 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1561 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1563 for (node = item_children; node != NULL; node = g_list_next (node)) {
1564 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1565 if (GTK_IS_TOGGLE_BUTTON (node->data))
1566 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1567 else if (GTK_IS_BUTTON (node->data))
1568 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1570 g_list_free (item_children);
1575 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1577 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1578 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1579 GtkWidget *placeholder;
1580 GtkWidget *tool_item;
1585 GtkWidget *sizes_menu;
1586 GtkWidget *fonts_menu;
1590 #ifndef MODEST_TOOLKIT_HILDON2
1591 GSList *radio_group, *node;
1595 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1596 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1597 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar),
1598 #ifdef MODEST_TOOLKIT_HILDON2
1599 HILDON_ICON_SIZE_FINGER
1601 GTK_ICON_SIZE_LARGE_TOOLBAR
1604 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1606 /* Font color placeholder */
1607 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1608 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1611 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1612 #ifdef MODEST_TOOLKIT_HILDON2
1613 priv->font_color_button = modest_color_button_new ();
1615 priv->font_color_button = gtk_color_button_new ();
1617 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1618 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1619 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1620 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1621 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1622 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1623 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1624 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1626 G_CALLBACK (modest_msg_edit_window_color_button_change),
1629 /* Font size and face placeholder */
1630 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1631 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1633 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, ""));
1634 priv->size_tool_button_label = gtk_label_new (NULL);
1635 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1636 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1637 size_text, "</span>", NULL);
1638 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1639 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1641 #ifdef MODEST_TOOLKIT_HILDON2
1642 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1644 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1645 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1646 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1647 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1648 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1649 gtk_widget_set_sensitive (arrow, FALSE);
1650 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1651 sizes_menu = gtk_menu_new ();
1652 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1653 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1656 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1657 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1659 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1663 if (wp_font_size[size_index] == 12)
1664 priv->current_size_index = size_index;
1668 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1669 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1670 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1671 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1672 priv->font_size_toolitem = tool_item;
1674 #ifdef MODEST_TOOLKIT_HILDON2
1676 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, ""));
1677 priv->font_tool_button_label = gtk_label_new (NULL);
1678 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1679 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1680 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1682 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1683 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1684 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1685 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1686 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1687 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1688 gtk_widget_set_sensitive (arrow, FALSE);
1689 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1691 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1692 priv->font_tool_button_label = gtk_label_new (NULL);
1693 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1694 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1696 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1697 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1698 gtk_widget_show (priv->font_tool_button_label);
1699 gtk_widget_show (GTK_WIDGET (tool_item));
1700 fonts_menu = gtk_menu_new ();
1703 #ifdef MODEST_TOOLKIT_HILDON2
1704 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1705 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1708 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1710 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1711 0, wp_get_font_name (font_index),
1714 if (font_index == DEFAULT_FONT)
1715 priv->current_face_index = font_index;
1717 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1718 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1719 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1720 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1721 priv->font_face_toolitem = tool_item;
1723 priv->font_items_group = NULL;
1725 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1726 GtkWidget *font_menu_item;
1727 GtkWidget *child_label;
1729 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1730 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1731 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1732 wp_get_font_name (font_index), "</span>", NULL);
1733 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1736 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1737 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1738 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1739 gtk_widget_show (font_menu_item);
1741 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1744 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1745 GtkWidget *item = (GtkWidget *) node->data;
1746 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1749 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1750 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1751 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1752 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1753 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1754 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1755 priv->font_face_toolitem = tool_item;
1758 /* Set expand and homogeneous for remaining items */
1759 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1760 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1761 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1762 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1763 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1764 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1766 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1767 will not show the tool items added to the placeholders) */
1768 gtk_widget_show_all (parent_priv->toolbar);
1770 /* Set the no show all *after* showing all items. We do not
1771 want the toolbar to be shown with a show all because it
1772 could go agains the gconf setting regarding showing or not
1773 the toolbar of the editor window */
1774 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1780 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1783 ModestWindowPrivate *parent_priv;
1784 ModestMsgEditWindowPrivate *priv;
1785 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1786 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1787 ModestWindowMgr *mgr = NULL;
1789 g_return_val_if_fail (msg, NULL);
1790 g_return_val_if_fail (account_name, NULL);
1792 mgr = modest_runtime_get_window_mgr ();
1794 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1796 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1797 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1799 /* Menubar. Update the state of some toggles */
1800 priv->from_field_protos = get_transports ();
1801 priv->original_mailbox = NULL;
1802 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1803 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1804 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1805 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1806 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1807 priv->original_mailbox = g_strdup (mailbox);
1808 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1809 /* We set the first mailbox as the active mailbox */
1810 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1811 if (priv->original_mailbox != NULL)
1812 modest_selector_set_active_id (priv->from_field,
1813 (gpointer) priv->original_mailbox);
1815 modest_selector_set_active_id (priv->from_field,
1816 (gpointer) account_name);
1818 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1820 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1821 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1822 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1823 #ifdef HILDON_TOOLKIT_HILDON2
1824 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1826 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1827 hildon_touch_selector_get_current_text
1828 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1831 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1832 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1835 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1837 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1839 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1840 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1842 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1844 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1845 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1846 /* Add common dimming rules */
1847 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1848 modest_msg_edit_window_toolbar_dimming_entries,
1849 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1850 MODEST_WINDOW (obj));
1851 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1852 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1853 MODEST_WINDOW (obj));
1854 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1855 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1856 MODEST_WINDOW (obj));
1857 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1858 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1859 MODEST_WINDOW (obj));
1860 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1861 G_CALLBACK (modest_ui_dimming_rules_on_send),
1862 MODEST_WINDOW (obj));
1863 /* Insert dimming rules group for this window */
1864 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1865 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1867 /* Setup app menu */
1868 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1870 /* Checks the dimming rules */
1871 g_object_unref (toolbar_rules_group);
1872 g_object_unref (clipboard_rules_group);
1873 gtk_widget_hide (priv->priority_icon);
1874 gtk_widget_queue_resize (priv->subject_box);
1875 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1877 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1879 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1880 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1881 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1882 priv->update_caption_visibility = TRUE;
1884 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1886 /* Track account-removed signal, this window should be closed
1887 in the case we're creating a mail associated to the account
1889 priv->account_removed_handler_id =
1890 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1892 G_CALLBACK(on_account_removed),
1895 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1897 return (ModestWindow*) obj;
1901 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1903 GString **string_buffer = (GString **) user_data;
1905 *string_buffer = g_string_append (*string_buffer, buffer);
1911 * @result: A new string which should be freed with g_free().
1914 get_formatted_data (ModestMsgEditWindow *edit_window)
1916 ModestMsgEditWindowPrivate *priv;
1917 GString *string_buffer = g_string_new ("");
1919 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1921 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1923 modest_text_utils_hyperlinkify (string_buffer);
1925 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1927 return g_string_free (string_buffer, FALSE);
1932 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1935 const gchar *account_name;
1936 ModestMsgEditWindowPrivate *priv;
1937 TnyIterator *att_iter;
1938 const gchar *picker_active_id;
1940 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1942 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1944 picker_active_id = modest_selector_get_active_id (priv->from_field);
1945 g_return_val_if_fail (picker_active_id, NULL);
1946 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1948 /* don't free these (except from) */
1949 data = g_slice_new0 (MsgData);
1950 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1951 data->account_name = g_strdup (account_name);
1952 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1953 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1954 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1955 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1956 data->references = g_strdup (priv->references);
1957 data->in_reply_to = g_strdup (priv->in_reply_to);
1958 if (priv->draft_msg) {
1959 data->draft_msg = g_object_ref (priv->draft_msg);
1960 } else if (priv->outbox_msg) {
1961 data->draft_msg = g_object_ref (priv->outbox_msg);
1963 data->draft_msg = NULL;
1966 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1968 gtk_text_buffer_get_bounds (buf, &b, &e);
1969 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1971 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1972 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1974 data->html_body = NULL;
1976 /* deep-copy the data */
1977 att_iter = tny_list_create_iterator (priv->attachments);
1978 data->attachments = NULL;
1979 while (!tny_iterator_is_done (att_iter)) {
1980 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1981 if (!(TNY_IS_MIME_PART(part))) {
1982 g_warning ("strange data in attachment list");
1983 g_object_unref (part);
1984 tny_iterator_next (att_iter);
1987 data->attachments = g_list_append (data->attachments,
1989 tny_iterator_next (att_iter);
1991 g_object_unref (att_iter);
1993 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1994 att_iter = tny_list_create_iterator (priv->images);
1995 data->images = NULL;
1996 while (!tny_iterator_is_done (att_iter)) {
1997 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1999 if (!(TNY_IS_MIME_PART(part))) {
2000 g_warning ("strange data in attachment list");
2001 g_object_unref (part);
2002 tny_iterator_next (att_iter);
2005 cid = tny_mime_part_get_content_id (part);
2007 gchar *image_tag_id;
2008 GtkTextTag *image_tag;
2010 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
2011 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
2012 g_free (image_tag_id);
2014 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
2016 ((gtk_text_iter_has_tag (&iter, image_tag))||
2017 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
2018 data->images = g_list_append (data->images,
2019 g_object_ref (part));
2021 g_object_unref (part);
2022 tny_iterator_next (att_iter);
2024 g_object_unref (att_iter);
2026 data->priority_flags = priv->priority_flags;
2033 unref_gobject (GObject *obj, gpointer data)
2035 if (!G_IS_OBJECT(obj))
2037 g_object_unref (obj);
2041 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
2044 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
2052 g_free (data->from);
2053 g_free (data->subject);
2054 g_free (data->plain_body);
2055 g_free (data->html_body);
2056 g_free (data->account_name);
2057 g_free (data->references);
2058 g_free (data->in_reply_to);
2060 if (data->draft_msg != NULL) {
2061 g_object_unref (data->draft_msg);
2062 data->draft_msg = NULL;
2065 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
2066 g_list_free (data->attachments);
2067 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
2068 g_list_free (data->images);
2070 g_slice_free (MsgData, data);
2074 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
2076 guint64 *parts_size)
2078 ModestMsgEditWindowPrivate *priv;
2080 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2082 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
2084 /* TODO: add images */
2085 *parts_size += priv->images_size;
2086 *parts_count += priv->images_count;
2091 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
2094 ModestMsgEditWindowPrivate *priv = NULL;
2095 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
2097 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2099 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2101 return MODEST_MSG_EDIT_FORMAT_HTML;
2103 return MODEST_MSG_EDIT_FORMAT_TEXT;
2107 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
2108 ModestMsgEditFormat format)
2110 ModestMsgEditWindowPrivate *priv;
2111 ModestWindowPrivate *parent_priv;
2113 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2114 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2115 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2118 case MODEST_MSG_EDIT_FORMAT_HTML:
2119 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2120 update_signature (self, priv->last_from_account, priv->last_from_account);
2121 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
2123 case MODEST_MSG_EDIT_FORMAT_TEXT:
2124 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2125 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
2128 g_return_if_reached ();
2132 ModestMsgEditFormatState *
2133 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2135 ModestMsgEditFormatState *format_state = NULL;
2136 ModestMsgEditWindowPrivate *priv;
2137 WPTextBufferFormat *buffer_format;
2139 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2141 buffer_format = g_new0 (WPTextBufferFormat, 1);
2142 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2144 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2146 format_state = g_new0 (ModestMsgEditFormatState, 1);
2147 format_state->bold = buffer_format->bold&0x1;
2148 format_state->italics = buffer_format->italic&0x1;
2149 format_state->bullet = buffer_format->bullet&0x1;
2150 format_state->color = buffer_format->color;
2151 format_state->font_size = buffer_format->font_size;
2152 format_state->font_family = wp_get_font_name (buffer_format->font);
2153 format_state->justification = buffer_format->justification;
2154 g_free (buffer_format);
2156 return format_state;
2161 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2162 const ModestMsgEditFormatState *format_state)
2164 ModestMsgEditWindowPrivate *priv;
2165 WPTextBufferFormat *buffer_format;
2166 WPTextBufferFormat *current_format;
2168 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2169 g_return_if_fail (format_state != NULL);
2171 buffer_format = g_new0 (WPTextBufferFormat, 1);
2172 current_format = g_new0 (WPTextBufferFormat, 1);
2174 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2175 gtk_widget_grab_focus (priv->msg_body);
2176 buffer_format->bold = (format_state->bold != FALSE);
2177 buffer_format->italic = (format_state->italics != FALSE);
2178 buffer_format->color = format_state->color;
2179 buffer_format->font_size = format_state->font_size;
2180 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2181 buffer_format->justification = format_state->justification;
2182 buffer_format->bullet = format_state->bullet;
2184 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2186 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2187 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2188 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2189 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2190 buffer_format->cs.font = (buffer_format->font != current_format->font);
2191 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2192 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2194 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2195 if (buffer_format->cs.bold) {
2196 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2197 GINT_TO_POINTER (buffer_format->bold&0x1));
2199 if (buffer_format->cs.italic) {
2200 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2201 GINT_TO_POINTER (buffer_format->italic&0x1));
2203 if (buffer_format->cs.color) {
2204 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2205 GINT_TO_POINTER (&(buffer_format->color)));
2207 if (buffer_format->cs.font_size) {
2208 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2209 GINT_TO_POINTER (buffer_format->font_size));
2211 if (buffer_format->cs.justification) {
2212 switch (buffer_format->justification) {
2213 case GTK_JUSTIFY_LEFT:
2214 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2215 GINT_TO_POINTER(TRUE));
2217 case GTK_JUSTIFY_CENTER:
2218 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2219 GINT_TO_POINTER(TRUE));
2221 case GTK_JUSTIFY_RIGHT:
2222 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2223 GINT_TO_POINTER(TRUE));
2230 if (buffer_format->cs.font) {
2231 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2232 GINT_TO_POINTER (buffer_format->font));
2234 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2235 if (buffer_format->cs.bullet) {
2236 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2237 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2239 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2241 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2243 g_free (buffer_format);
2244 g_free (current_format);
2246 /* Check dimming rules */
2247 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2248 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2252 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2254 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2256 ModestWindowPrivate *parent_priv;
2257 ModestMsgEditWindowPrivate *priv;
2259 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2260 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2262 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2263 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2264 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2265 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2267 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2268 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2269 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2272 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2274 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2275 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2277 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2278 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2280 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2281 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2284 switch (buffer_format->justification)
2286 case GTK_JUSTIFY_LEFT:
2287 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2289 case GTK_JUSTIFY_CENTER:
2290 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2292 case GTK_JUSTIFY_RIGHT:
2293 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2300 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2302 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2303 G_CALLBACK (modest_msg_edit_window_color_button_change),
2305 #ifdef MODEST_TOOLKIT_HILDON2
2306 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2308 gtk_color_button_set_color (GTK_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2310 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2311 G_CALLBACK (modest_msg_edit_window_color_button_change),
2314 if (priv->current_size_index != buffer_format->font_size) {
2318 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2319 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2323 priv->current_size_index = buffer_format->font_size;
2325 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2326 markup = g_strconcat ("<span font_family='Sans'>",
2327 size_text, "</span>", NULL);
2329 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2333 gtk_tree_path_free (path);
2336 #ifdef MODEST_TOOLKIT_HILDON2
2337 if (priv->current_face_index != buffer_format->font) {
2341 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2342 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2346 priv->current_face_index = buffer_format->font;
2347 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2348 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2349 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2356 GtkWidget *new_font_menuitem;
2357 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
2358 buffer_format->font))->data);
2359 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
2363 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
2364 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2365 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2367 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
2368 G_CALLBACK (modest_msg_edit_window_font_change),
2370 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
2371 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
2372 G_CALLBACK (modest_msg_edit_window_font_change),
2377 g_free (buffer_format);
2383 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2385 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2386 ModestMsgEditWindowPrivate *priv;
2387 GtkWidget *dialog = NULL;
2389 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2390 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2392 #ifdef MODEST_TOOLKIT_HILDON2
2393 dialog = hildon_color_chooser_new ();
2394 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2395 g_free (buffer_format);
2397 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2399 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2400 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2403 gtk_widget_destroy (dialog);
2405 dialog = gtk_color_selection_dialog_new (NULL);
2406 GtkWidget *selection;
2408 g_object_get (G_OBJECT (dialog), "color_selection", &selection, NULL);
2409 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2410 gtk_color_selection_set_previous_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2411 g_free (buffer_format);
2413 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2415 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION(selection), &col);
2416 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2419 gtk_widget_destroy (dialog);
2426 create_stream_for_uri (const gchar* uri)
2431 TnyStream *result = NULL;
2433 GnomeVFSHandle *handle = NULL;
2434 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2435 if (test == GNOME_VFS_OK) {
2436 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2437 /* Streams over OBEX (Bluetooth) are not seekable but
2438 * we expect them to be (we might need to read them
2439 * several times). So if this is a Bluetooth URI just
2440 * read the whole file into memory (this is not a fast
2441 * protocol so we can assume that these files are not
2442 * going to be very big) */
2443 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2444 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2445 TnyStream *memstream = tny_camel_mem_stream_new ();
2446 tny_stream_write_to_stream (vfssstream, memstream);
2447 g_object_unref (vfssstream);
2450 result = vfssstream;
2458 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2461 ModestMsgEditWindowPrivate *priv;
2462 GtkWidget *dialog = NULL;
2464 GSList *uris = NULL;
2465 GSList *uri_node = NULL;
2467 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2469 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2470 _("mcen_ia_select_inline_image_title"),
2471 (GtkWindow *) window,
2472 GTK_FILE_CHOOSER_ACTION_OPEN);
2473 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2475 #ifdef MODEST_TOOLKIT_HILDON2
2476 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2479 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2480 GTK_WINDOW (dialog), GTK_WINDOW (window));
2482 response = gtk_dialog_run (GTK_DIALOG (dialog));
2484 case GTK_RESPONSE_OK:
2486 gchar *current_folder;
2487 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2488 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2489 if (current_folder && current_folder != '\0') {
2491 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2492 current_folder, &err);
2494 g_debug ("Error storing latest used folder: %s", err->message);
2498 g_free (current_folder);
2504 gtk_widget_destroy (dialog);
2506 g_object_ref (window);
2507 /* The operation could take some time so allow the dialog to be closed */
2508 while (gtk_events_pending ())
2509 gtk_main_iteration ();
2511 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2513 GnomeVFSHandle *handle = NULL;
2514 GnomeVFSResult result;
2515 GtkTextIter position;
2516 GtkTextMark *insert_mark;
2518 uri = (const gchar *) uri_node->data;
2519 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2520 if (result == GNOME_VFS_OK) {
2522 GnomeVFSFileInfo *info;
2523 gchar *filename, *basename, *escaped_filename;
2524 TnyMimePart *mime_part;
2526 const gchar *mime_type = NULL;
2527 GnomeVFSURI *vfs_uri;
2528 guint64 stream_size;
2530 gnome_vfs_close (handle);
2531 vfs_uri = gnome_vfs_uri_new (uri);
2533 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2534 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2535 g_free (escaped_filename);
2536 gnome_vfs_uri_unref (vfs_uri);
2537 info = gnome_vfs_file_info_new ();
2539 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2540 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2542 mime_type = gnome_vfs_file_info_get_mime_type (info);
2544 mime_part = tny_platform_factory_new_mime_part
2545 (modest_runtime_get_platform_factory ());
2547 TnyStream *stream = create_stream_for_uri (uri);
2549 if (stream == NULL) {
2551 modest_platform_information_banner (NULL, NULL,
2552 _FM_OPENING_NOT_ALLOWED);
2554 g_object_unref (mime_part);
2555 gnome_vfs_file_info_unref (info);
2559 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2561 content_id = g_strdup_printf ("%d", priv->next_cid);
2562 tny_mime_part_set_content_id (mime_part, content_id);
2563 g_free (content_id);
2566 basename = g_path_get_basename (filename);
2567 tny_mime_part_set_filename (mime_part, basename);
2570 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2572 if (pixbuf != NULL) {
2573 priv->images_size += stream_size;
2574 priv->images_count ++;
2575 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2576 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2577 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2578 tny_mime_part_get_content_id (mime_part), pixbuf);
2579 g_object_unref (pixbuf);
2581 tny_list_prepend (priv->images, (GObject *) mime_part);
2582 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2584 modest_platform_information_banner (NULL, NULL,
2585 _("mail_ib_file_operation_failed"));
2589 g_object_unref (mime_part);
2590 gnome_vfs_file_info_unref (info);
2594 g_object_unref (window);
2598 on_attach_file_response (GtkDialog *dialog,
2602 GSList *uris = NULL;
2604 GnomeVFSFileSize total_size, allowed_size;
2605 ModestMsgEditWindow *window;
2606 ModestMsgEditWindowPrivate *priv;
2611 case GTK_RESPONSE_OK:
2613 gchar *current_folder;
2615 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2616 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2617 if (current_folder && current_folder != '\0') {
2619 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2620 current_folder, &err);
2622 g_debug ("Error storing latest used folder: %s", err->message);
2626 g_free (current_folder);
2633 window = MODEST_MSG_EDIT_WINDOW (user_data);
2634 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2636 /* allowed size is the maximum size - what's already there */
2637 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2638 &att_num, &att_size);
2639 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2642 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2644 const gchar *uri = (const gchar *) uri_node->data;
2647 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2649 if (total_size > allowed_size) {
2650 g_debug ("%s: total size: %u",
2651 __FUNCTION__, (unsigned int)total_size);
2654 allowed_size -= total_size;
2656 g_slist_foreach (uris, (GFunc) g_free, NULL);
2657 g_slist_free (uris);
2659 gtk_widget_destroy (GTK_WIDGET (dialog));
2663 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2665 GtkWidget *dialog = NULL;
2666 ModestMsgEditWindowPrivate *priv;
2669 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2671 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2673 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2676 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2677 _("mcen_ia_select_attachment_title"),
2678 (GtkWindow *) window,
2679 GTK_FILE_CHOOSER_ACTION_OPEN);
2680 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2681 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2682 if (conf_folder && conf_folder[0] != '\0') {
2683 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2686 /* Set the default folder to documents folder */
2687 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2688 #ifdef MODEST_TOOLKIT_HILDON2
2691 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2692 ".documents", NULL);
2695 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2696 g_free (docs_folder);
2698 g_free (conf_folder);
2699 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2700 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2701 GTK_WINDOW (dialog), GTK_WINDOW (window));
2703 /* Connect to response & show */
2704 g_signal_connect (dialog, "response",
2705 G_CALLBACK (on_attach_file_response), window);
2706 gtk_widget_show (dialog);
2711 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2713 GnomeVFSFileSize allowed_size)
2716 GnomeVFSHandle *handle = NULL;
2717 ModestMsgEditWindowPrivate *priv;
2718 GnomeVFSResult result;
2719 GnomeVFSFileSize size = 0;
2720 g_return_val_if_fail (window, 0);
2721 g_return_val_if_fail (uri, 0);
2723 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2725 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2726 if (result == GNOME_VFS_OK) {
2727 TnyMimePart *mime_part;
2729 const gchar *mime_type = NULL;
2731 gchar *escaped_filename;
2734 GnomeVFSFileInfo *info;
2735 GnomeVFSURI *vfs_uri;
2737 gnome_vfs_close (handle);
2738 vfs_uri = gnome_vfs_uri_new (uri);
2741 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2742 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2743 g_free (escaped_filename);
2744 gnome_vfs_uri_unref (vfs_uri);
2746 info = gnome_vfs_file_info_new ();
2748 if (gnome_vfs_get_file_info (uri,
2750 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2752 mime_type = gnome_vfs_file_info_get_mime_type (info);
2753 mime_part = tny_platform_factory_new_mime_part
2754 (modest_runtime_get_platform_factory ());
2756 /* try to get the attachment's size; this may fail for weird
2757 * file systems, like obex, upnp... */
2758 if (allowed_size != 0 &&
2759 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2761 if (size > allowed_size) {
2762 modest_platform_information_banner (NULL, NULL,
2763 _("mail_ib_error_attachment_size"));
2768 g_debug ("%s: could not get attachment size", __FUNCTION__);
2770 stream = create_stream_for_uri (uri);
2772 if (stream == NULL) {
2774 modest_platform_information_banner (NULL, NULL, _FM_OPENING_NOT_ALLOWED);
2776 g_object_unref (mime_part);
2778 gnome_vfs_file_info_unref (info);
2782 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2783 g_object_unref (stream);
2785 content_id = g_strdup_printf ("%d", priv->next_cid);
2786 tny_mime_part_set_content_id (mime_part, content_id);
2787 g_free (content_id);
2790 basename = g_path_get_basename (filename);
2791 tny_mime_part_set_filename (mime_part, basename);
2794 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2795 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2797 info->size == 0, info->size);
2798 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2799 gtk_widget_show_all (priv->attachments_caption);
2800 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2802 g_object_unref (mime_part);
2803 gnome_vfs_file_info_unref (info);
2810 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2813 ModestMsgEditWindowPrivate *priv;
2816 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2817 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2819 if (att_list == NULL) {
2820 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2821 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2822 g_object_unref (att_list);
2826 g_object_ref (att_list);
2829 if (tny_list_get_length (att_list) == 0) {
2830 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2832 gboolean dialog_response;
2833 gchar *message = NULL;
2834 gchar *filename = NULL;
2836 if (tny_list_get_length (att_list) == 1) {
2838 iter = tny_list_create_iterator (att_list);
2839 part = (TnyMimePart *) tny_iterator_get_current (iter);
2840 g_object_unref (iter);
2841 if (TNY_IS_MSG (part)) {
2842 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2844 filename = tny_header_dup_subject (header);
2845 g_object_unref (header);
2847 if (filename == NULL) {
2848 filename = g_strdup (_("mail_va_no_subject"));
2851 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2853 g_object_unref (part);
2855 filename = g_strdup ("");
2857 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2858 "emev_nc_delete_attachments",
2859 tny_list_get_length (att_list)), filename);
2862 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2866 if (dialog_response != GTK_RESPONSE_OK) {
2867 g_object_unref (att_list);
2871 for (iter = tny_list_create_iterator (att_list);
2872 !tny_iterator_is_done (iter);
2873 tny_iterator_next (iter)) {
2874 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2875 const gchar *att_id;
2876 tny_list_remove (priv->attachments, (GObject *) mime_part);
2878 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2880 if (tny_list_get_length (priv->attachments) == 0)
2881 gtk_widget_hide (priv->attachments_caption);
2882 att_id = tny_mime_part_get_content_id (mime_part);
2884 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2886 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2887 g_object_unref (mime_part);
2889 g_object_unref (iter);
2892 g_object_unref (att_list);
2894 /* if the last attachment has been removed, focus the Subject: field */
2895 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2896 gtk_widget_grab_focus (priv->subject_field);
2900 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2903 ModestMsgEditWindowPrivate *priv;
2906 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2908 gtk_color_button_get_color (GTK_COLOR_BUTTON(priv->font_color_button), &new_color);
2910 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2912 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2915 #ifndef MODEST_TOOLKIT_HILDON2
2917 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2920 ModestMsgEditWindowPrivate *priv;
2921 gint new_font_index;
2922 ModestMsgEditWindow *window;
2925 window = MODEST_MSG_EDIT_WINDOW (userdata);
2926 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2927 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2929 if (gtk_check_menu_item_get_active (menu_item)) {
2932 label = gtk_bin_get_child (GTK_BIN (menu_item));
2934 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2936 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2937 GINT_TO_POINTER(new_font_index)))
2938 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2940 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2941 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2942 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2949 font_size_clicked (GtkToolButton *button,
2950 ModestMsgEditWindow *window)
2952 #ifdef MODEST_TOOLKIT_HILDON2
2953 ModestMsgEditWindowPrivate *priv;
2954 GtkWidget *selector, *dialog;
2956 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2958 selector = hildon_touch_selector_new ();
2959 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2960 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2962 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2963 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2964 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2966 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2970 WPTextBufferFormat format;
2972 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2974 memset (&format, 0, sizeof (format));
2975 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2977 format.cs.font_size = TRUE;
2978 format.cs.text_position = TRUE;
2979 format.cs.font = TRUE;
2980 format.font_size = new_index;
2981 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2983 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2984 GINT_TO_POINTER (new_index)))
2985 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2987 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2988 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2989 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2990 size_text, "</span>", NULL);
2992 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2996 gtk_widget_destroy (dialog);
2998 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
3002 #ifdef MODEST_TOOLKIT_HILDON2
3004 font_face_clicked (GtkToolButton *button,
3005 ModestMsgEditWindow *window)
3007 ModestMsgEditWindowPrivate *priv;
3008 GtkWidget *selector, *dialog;
3009 GtkCellRenderer *renderer;
3011 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3013 selector = hildon_touch_selector_new ();
3014 renderer = gtk_cell_renderer_text_new ();
3015 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
3016 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
3017 renderer, "family", 0, "text", 0, NULL);
3018 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
3020 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
3021 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
3022 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
3024 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
3025 gint new_font_index;
3029 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
3030 path = gtk_tree_path_new_from_indices (new_font_index, -1);
3031 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
3035 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
3037 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
3038 GINT_TO_POINTER(new_font_index)))
3039 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
3041 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
3042 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
3044 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
3048 gtk_tree_path_free (path);
3051 gtk_widget_destroy (dialog);
3053 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
3058 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
3061 ModestMsgEditWindowPrivate *priv = NULL;
3062 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3064 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3065 if (!priv->update_caption_visibility)
3068 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
3070 gtk_widget_show (priv->cc_caption);
3072 gtk_widget_hide (priv->cc_caption);
3074 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
3078 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
3081 ModestMsgEditWindowPrivate *priv = NULL;
3082 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3084 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3085 if (!priv->update_caption_visibility)
3088 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
3090 gtk_widget_show (priv->bcc_caption);
3092 gtk_widget_hide (priv->bcc_caption);
3094 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
3098 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
3099 ModestRecptEditor *editor)
3101 ModestMsgEditWindowPrivate *priv;
3103 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3104 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
3106 /* we check for low-mem; in that case, show a warning, and don't allow
3107 * for the addressbook
3109 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3112 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3114 if (editor == NULL) {
3115 GtkWidget *view_focus, *parent;
3116 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
3118 /* This code should be kept in sync with ModestRecptEditor. The
3119 textview inside the recpt editor is the one that really gets the
3120 focus. As it's inside a scrolled window, and this one inside the
3121 hbox recpt editor inherits from, we'll need to go up in the
3122 hierarchy to know if the text view is part of the recpt editor
3123 or if it's a different text entry */
3124 parent = gtk_widget_get_parent (view_focus);
3125 if (parent && MODEST_IS_RECPT_EDITOR (parent))
3126 editor = MODEST_RECPT_EDITOR (parent);
3129 editor = MODEST_RECPT_EDITOR (priv->to_field);
3132 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
3136 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
3138 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3140 modest_msg_edit_window_open_addressbook (window, NULL);
3144 modest_msg_edit_window_show_toolbar (ModestWindow *self,
3145 gboolean show_toolbar)
3147 ModestWindowPrivate *parent_priv;
3148 ModestMsgEditWindowPrivate *priv;
3150 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
3151 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3152 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
3154 /* We can not just use the code of
3155 modest_msg_edit_window_setup_toolbar because it has a
3156 mixture of both initialization and creation code. */
3158 gint current_format;
3159 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3160 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3161 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3162 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3164 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
3167 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3172 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
3173 TnyHeaderFlags priority_flags)
3175 ModestMsgEditWindowPrivate *priv;
3176 ModestWindowPrivate *parent_priv;
3178 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3180 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3181 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3183 if (priv->priority_flags != priority_flags) {
3184 GtkAction *priority_action = NULL;
3186 priv->priority_flags = priority_flags;
3188 switch (priority_flags) {
3189 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3190 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3191 MODEST_HEADER_ICON_HIGH,
3192 #ifdef MODEST_TOOLKIT_HILDON2
3193 HILDON_ICON_SIZE_SMALL
3195 GTK_ICON_SIZE_BUTTON
3198 gtk_widget_show (priv->priority_icon);
3199 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3200 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3202 case TNY_HEADER_FLAG_LOW_PRIORITY:
3203 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3204 MODEST_HEADER_ICON_LOW,
3205 #ifdef MODEST_TOOLKIT_HILDON2
3206 HILDON_ICON_SIZE_SMALL
3208 GTK_ICON_SIZE_BUTTON
3211 gtk_widget_show (priv->priority_icon);
3212 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3213 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3216 gtk_widget_hide (priv->priority_icon);
3217 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3218 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3221 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3222 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3224 gtk_widget_queue_resize (priv->subject_box);
3228 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3231 ModestMsgEditWindowPrivate *priv;
3232 ModestWindowPrivate *parent_priv;
3233 gint current_format;
3235 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3237 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3238 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3240 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3241 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3243 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3245 if (current_format != file_format) {
3246 switch (file_format) {
3247 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3248 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3249 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3250 update_signature (window, priv->last_from_account, priv->last_from_account);
3251 if (parent_priv->toolbar)
3252 gtk_widget_show (parent_priv->toolbar);
3254 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3257 response = modest_platform_run_confirmation_dialog (NULL, _("emev_nc_formatting_lost"));
3258 if (response == GTK_RESPONSE_OK) {
3259 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3260 if (parent_priv->toolbar)
3261 gtk_widget_hide (parent_priv->toolbar);
3263 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3264 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3269 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3270 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3271 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3276 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3278 #ifdef MODEST_TOOLKIT_HILDON2
3280 ModestMsgEditWindowPrivate *priv;
3281 WPTextBufferFormat oldfmt, fmt;
3282 gint old_position = 0;
3286 GdkColor *color = NULL;
3287 gboolean bold, bold_set, italic, italic_set;
3288 gboolean underline, underline_set;
3289 gboolean strikethrough, strikethrough_set;
3290 gboolean position_set;
3291 gboolean font_size_set, font_set, color_set;
3294 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3295 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3297 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3298 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3299 GTK_WINDOW(dialog), GTK_WINDOW (window));
3301 /* First we get the currently selected font information */
3302 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3304 switch (oldfmt.text_position) {
3305 case TEXT_POSITION_NORMAL:
3308 case TEXT_POSITION_SUPERSCRIPT:
3316 g_object_set (G_OBJECT (dialog),
3317 "bold", oldfmt.bold != FALSE,
3318 "bold-set", !oldfmt.cs.bold,
3319 "underline", oldfmt.underline != FALSE,
3320 "underline-set", !oldfmt.cs.underline,
3321 "italic", oldfmt.italic != FALSE,
3322 "italic-set", !oldfmt.cs.italic,
3323 "strikethrough", oldfmt.strikethrough != FALSE,
3324 "strikethrough-set", !oldfmt.cs.strikethrough,
3325 "color", &oldfmt.color,
3326 "color-set", !oldfmt.cs.color,
3327 "size", wp_font_size[oldfmt.font_size],
3328 "size-set", !oldfmt.cs.font_size,
3329 "position", old_position,
3330 "position-set", !oldfmt.cs.text_position,
3331 "family", wp_get_font_name (oldfmt.font),
3332 "family-set", !oldfmt.cs.font,
3335 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3336 GTK_WINDOW (dialog), GTK_WINDOW (window));
3337 gtk_widget_show_all (dialog);
3338 priv->font_dialog = dialog;
3339 response = gtk_dialog_run (GTK_DIALOG (dialog));
3340 priv->font_dialog = NULL;
3341 if (response == GTK_RESPONSE_OK) {
3343 g_object_get( dialog,
3345 "bold-set", &bold_set,
3346 "underline", &underline,
3347 "underline-set", &underline_set,
3349 "italic-set", &italic_set,
3350 "strikethrough", &strikethrough,
3351 "strikethrough-set", &strikethrough_set,
3353 "color-set", &color_set,
3355 "size-set", &font_size_set,
3356 "family", &font_name,
3357 "family-set", &font_set,
3358 "position", &position,
3359 "position-set", &position_set,
3364 if (response == GTK_RESPONSE_OK) {
3365 memset(&fmt, 0, sizeof(fmt));
3371 fmt.italic = italic;
3372 fmt.cs.italic = TRUE;
3374 if (underline_set) {
3375 fmt.underline = underline;
3376 fmt.cs.underline = TRUE;
3378 if (strikethrough_set) {
3379 fmt.strikethrough = strikethrough;
3380 fmt.cs.strikethrough = TRUE;
3385 ? TEXT_POSITION_NORMAL
3386 : ( ( position == 1 )
3387 ? TEXT_POSITION_SUPERSCRIPT
3388 : TEXT_POSITION_SUBSCRIPT );
3389 fmt.cs.text_position = TRUE;
3390 fmt.font_size = oldfmt.font_size;
3394 fmt.cs.color = TRUE;
3397 fmt.font = wp_get_font_index(font_name,
3402 if (font_size_set) {
3403 fmt.cs.font_size = TRUE;
3404 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3406 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3407 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3409 gtk_widget_destroy (dialog);
3411 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3416 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3418 ModestMsgEditWindowPrivate *priv;
3419 ModestWindowPrivate *parent_priv;
3420 gboolean was_rich_text, is_rich_text;
3422 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3423 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3424 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3426 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3428 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3430 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3432 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3434 gtk_widget_show (parent_priv->toolbar);
3436 gtk_widget_hide (parent_priv->toolbar);
3439 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3440 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3444 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3446 ModestMsgEditWindowPrivate *priv;
3448 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3449 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3451 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3453 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3454 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3459 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3461 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3463 priv->can_undo = can_undo;
3467 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3469 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3471 priv->can_redo = can_redo;
3475 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3477 ModestMsgEditWindowPrivate *priv;
3478 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3479 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3481 return priv->can_undo;
3485 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3487 ModestMsgEditWindowPrivate *priv;
3488 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3489 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3491 return priv->can_redo;
3496 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3499 GtkTextIter match_start, match_end;
3501 if (image_id == NULL)
3504 gtk_text_buffer_get_start_iter (buffer, &iter);
3506 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3507 GSList *tags = gtk_text_iter_get_tags (&match_start);
3509 for (node = tags; node != NULL; node = g_slist_next (node)) {
3510 GtkTextTag *tag = (GtkTextTag *) node->data;
3511 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3512 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3513 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3515 offset = gtk_text_iter_get_offset (&match_start);
3516 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3517 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3521 gtk_text_iter_forward_char (&iter);
3526 message_is_empty (ModestMsgEditWindow *window)
3528 ModestMsgEditWindowPrivate *priv = NULL;
3530 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3531 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3533 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3534 * so we can ignore markup.
3536 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3539 count = gtk_text_buffer_get_char_count (buf);
3545 msg_body_focus (GtkWidget *focus,
3546 GdkEventFocus *event,
3550 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3551 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3552 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3557 recpt_field_changed (GtkTextBuffer *buffer,
3558 ModestMsgEditWindow *editor)
3560 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3561 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3565 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3567 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3568 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3572 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3575 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3576 GtkTextBuffer *buffer;
3578 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3579 gtk_text_buffer_set_modified (buffer, modified);
3580 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3581 gtk_text_buffer_set_modified (buffer, modified);
3582 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3583 gtk_text_buffer_set_modified (buffer, modified);
3584 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3588 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3590 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3591 const char *account_name;
3592 GtkTextBuffer *buffer;
3594 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3595 if (gtk_text_buffer_get_modified (buffer))
3597 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3598 if (gtk_text_buffer_get_modified (buffer))
3600 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3601 if (gtk_text_buffer_get_modified (buffer))
3603 if (gtk_text_buffer_get_modified (priv->text_buffer))
3606 account_name = modest_selector_get_active_id (priv->from_field);
3607 if (priv->original_mailbox) {
3608 if (!account_name || strcmp (account_name, priv->original_mailbox))
3610 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3621 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3623 ModestMsgEditWindowPrivate *priv = NULL;
3624 GSList *address_list = NULL;
3626 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3627 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3629 /* check if there's no recipient added */
3630 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3631 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3632 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3633 /* no recipient contents, then select contacts */
3634 modest_msg_edit_window_open_addressbook (window, NULL);
3639 g_object_ref (window);
3640 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3641 (add_to_addressbook) ? &address_list : NULL)) {
3642 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3643 g_object_unref (window);
3646 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3647 (add_to_addressbook) ? &address_list : NULL)) {
3648 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3649 g_object_unref (window);
3652 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3653 (add_to_addressbook) ? &address_list : NULL)) {
3654 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3655 g_object_unref (window);
3659 /* Add contacts to address book */
3660 if (add_to_addressbook && address_list)
3661 modest_address_book_add_address_list (address_list);
3663 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3664 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3665 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3666 g_object_unref (window);
3673 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3675 GSList *recipients = NULL;
3676 ModestMsgEditWindowPrivate *priv;
3677 gchar *joined, *after_remove, *to, *cc, *bcc;
3679 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3681 /* First of all check names */
3682 if (!modest_msg_edit_window_check_names (self, FALSE))
3685 if (!modest_msg_edit_window_has_pending_addresses (self))
3688 /* Don't add the from obviously */
3689 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3690 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3691 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3693 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3698 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3701 recipients = modest_text_utils_split_addresses_list (after_remove);
3702 g_free (after_remove);
3705 /* Offer the user to add recipients to the address book */
3706 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3707 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3712 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3713 ModestMsgEditWindow *window)
3715 modest_msg_edit_window_offer_attach_file (window);
3719 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3721 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3723 return priv->clipboard_text;
3727 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3729 ModestMsgEditWindow *window)
3731 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3732 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3735 /* It could happen that the window was already closed */
3736 if (!GTK_WIDGET_VISIBLE (window))
3739 g_object_ref (window);
3740 text = gtk_clipboard_wait_for_text (selection_clipboard);
3742 if (priv->clipboard_text != NULL) {
3743 g_free (priv->clipboard_text);
3745 priv->clipboard_text = text;
3747 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3749 g_object_unref (window);
3752 static gboolean clipboard_owner_change_idle (gpointer userdata)
3754 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3755 ModestMsgEditWindowPrivate *priv;
3757 gdk_threads_enter ();
3758 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3759 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3761 priv->clipboard_owner_idle = 0;
3762 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3763 gdk_threads_leave ();
3769 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3771 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3772 if (priv->clipboard_owner_idle == 0) {
3773 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3774 clipboard_owner_change_idle,
3775 g_object_ref (window),
3781 subject_field_move_cursor (GtkEntry *entry,
3782 GtkMovementStep step,
3787 /* It could happen that the window was already closed */
3788 if (!GTK_WIDGET_VISIBLE (window))
3791 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3795 update_window_title (ModestMsgEditWindow *window)
3797 ModestMsgEditWindowPrivate *priv = NULL;
3798 const gchar *subject;
3800 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3801 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3802 if (subject == NULL || subject[0] == '\0')
3803 subject = _("mail_va_new_email");
3805 modest_window_set_title (MODEST_WINDOW (window), subject);
3811 body_insert_text (GtkTextBuffer *buffer,
3812 GtkTextIter *location,
3815 ModestMsgEditWindow *window)
3817 GtkTextIter end_iter;
3824 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3826 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3828 offset = gtk_text_iter_get_offset (&end_iter);
3829 line = gtk_text_iter_get_line (&end_iter);
3833 while (text_offset < text + len) {
3834 if (*text_offset == '\n')
3836 if (text_lines + line >= MAX_BODY_LINES) {
3837 len = text_offset - text;
3843 utf8_len = g_utf8_strlen (text, len);
3845 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3846 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3847 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3852 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3854 /* Prevent endless recursion */
3855 result = g_strndup (text, utf8_end - text);
3856 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3857 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3858 (gpointer) result, (gpointer) (utf8_end - text),
3860 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3864 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3865 if (priv->max_chars_banner == NULL) {
3866 #ifdef MODEST_TOOLKIT_HILDON2
3867 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3868 _CS_MAXIMUM_CHARACTERS_REACHED);
3869 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3876 subject_field_changed (GtkEditable *editable,
3877 ModestMsgEditWindow *window)
3879 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3880 update_window_title (window);
3881 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3882 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3883 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3886 subject_field_insert_text (GtkEditable *editable,
3888 gint new_text_length,
3890 ModestMsgEditWindow *window)
3892 GString *result = g_string_new ("");
3894 gint result_len = 0;
3895 const gchar *entry_text = NULL;
3898 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3899 old_length = g_utf8_strlen (entry_text, -1);
3901 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3902 gunichar c = g_utf8_get_char_validated (current, 8);
3903 /* Invalid unichar, stop */
3909 result = g_string_append_unichar (result, c);
3913 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3914 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3917 /* Prevent endless recursion */
3918 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3919 g_signal_emit_by_name (editable, "insert-text",
3920 (gpointer) result->str, (gpointer) result->len,
3921 (gpointer) position, (gpointer) window);
3922 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3926 if (result_len + old_length > 1000) {
3927 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3928 _CS_MAXIMUM_CHARACTERS_REACHED);
3930 g_string_free (result, TRUE);
3934 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3937 ModestMsgEditWindowPrivate *priv = NULL;
3939 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3940 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3942 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3945 gtk_widget_show_all (priv->isearch_toolbar);
3946 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3948 gtk_widget_hide_all (priv->isearch_toolbar);
3949 gtk_widget_grab_focus (priv->msg_body);
3954 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3956 GtkTextIter *match_start,
3957 GtkTextIter *match_end)
3959 GtkTextIter end_iter;
3960 gchar *str_casefold;
3963 gchar *range_casefold;
3966 gboolean result = FALSE;
3973 gtk_text_iter_forward_to_end (&end_iter);
3975 str_casefold = g_utf8_casefold (str, -1);
3976 str_chars_n = strlen (str);
3978 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3979 range_casefold = g_utf8_casefold (range_text, -1);
3980 range_chars_n = strlen (range_casefold);
3982 if (range_chars_n < str_chars_n) {
3983 g_free (str_casefold);
3984 g_free (range_text);
3985 g_free (range_casefold);
3989 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3990 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3991 if (!g_utf8_collate (range_subtext, str_casefold)) {
3992 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3994 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3995 match_start, match_end, NULL)) {
3996 g_debug ("Matched string with collate, but not matched in model");
3998 g_free (found_text);
4000 g_free (range_subtext);
4004 g_free (str_casefold);
4005 g_free (range_text);
4006 g_free (range_casefold);
4013 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
4014 ModestMsgEditWindow *window)
4016 const gchar *current_search = NULL;
4017 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4019 GtkTextIter selection_start, selection_end;
4020 GtkTextIter match_start, match_end;
4021 gboolean continue_search = FALSE;
4023 if (message_is_empty (window)) {
4024 g_free (priv->last_search);
4025 priv->last_search = NULL;
4026 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
4030 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
4031 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
4032 g_free (priv->last_search);
4033 priv->last_search = NULL;
4034 /* Information banner about empty search */
4035 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
4039 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
4040 continue_search = TRUE;
4042 g_free (priv->last_search);
4043 priv->last_search = g_strdup (current_search);
4046 if (continue_search) {
4047 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
4048 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
4049 &match_start, &match_end);
4051 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_COMPLETE);
4053 GtkTextIter buffer_start;
4054 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
4055 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
4056 &match_start, &match_end);
4058 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_NO_MATCHES);
4061 /* Mark as selected the string found in search */
4063 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
4064 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
4065 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
4067 g_free (priv->last_search);
4068 priv->last_search = NULL;
4073 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
4075 ModestMsgEditWindowPrivate *priv;
4077 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
4082 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
4085 ModestMsgEditWindowPrivate *priv;
4087 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
4092 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
4093 ModestMsgEditWindow *window)
4095 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
4099 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
4102 ModestMsgEditWindowPrivate *priv;
4103 TnyHeader *header = NULL;
4105 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4106 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
4108 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4110 if (priv->draft_msg != NULL) {
4111 g_object_unref (priv->draft_msg);
4114 if (draft != NULL) {
4115 g_object_ref (draft);
4116 header = tny_msg_get_header (draft);
4117 if (priv->msg_uid) {
4118 g_free (priv->msg_uid);
4119 priv->msg_uid = NULL;
4121 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
4124 priv->draft_msg = draft;
4128 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
4129 GtkTextIter *start, GtkTextIter *end,
4132 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
4133 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
4136 if (tag == NULL) return;
4137 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
4138 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
4139 replace_with_images (window, priv->images);
4144 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
4147 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4149 g_return_if_fail (TNY_IS_MIME_PART (part));
4150 tny_list_prepend (priv->attachments, (GObject *) part);
4151 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
4152 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
4153 gtk_widget_show_all (priv->attachments_caption);
4154 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
4158 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
4160 ModestMsgEditWindowPrivate *priv;
4162 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
4163 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4165 return priv->msg_uid;
4169 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
4170 ModestMsgEditWindowWidgetType widget_type)
4172 ModestMsgEditWindowPrivate *priv;
4174 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
4175 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
4177 switch (widget_type) {
4178 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
4179 return priv->msg_body;
4181 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
4182 return priv->to_field;
4184 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
4185 return priv->cc_field;
4187 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4188 return priv->bcc_field;
4190 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4191 return priv->subject_field;
4193 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4194 return priv->attachments_view;
4202 remove_tags (WPTextBuffer *buffer)
4204 GtkTextIter start, end;
4206 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4207 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4209 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4213 on_account_removed (TnyAccountStore *account_store,
4214 TnyAccount *account,
4217 /* Do nothing if it's a store account, because we use the
4218 transport to send the messages */
4219 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4220 const gchar *parent_acc = NULL;
4221 const gchar *our_acc = NULL;
4223 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4224 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4225 /* Close this window if I'm showing a message of the removed account */
4226 if (strcmp (parent_acc, our_acc) == 0)
4227 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4232 update_signature (ModestMsgEditWindow *self,
4233 const gchar *old_account,
4234 const gchar *new_account)
4236 ModestMsgEditWindowPrivate *priv;
4237 gboolean has_old_signature, has_new_signature;
4239 ModestAccountMgr *mgr;
4242 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4244 gtk_text_buffer_begin_user_action (priv->text_buffer);
4246 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4247 mgr = modest_runtime_get_account_mgr ();
4251 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4252 if (has_old_signature) {
4253 GtkTextIter match_start, match_end;
4255 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4256 seems that the search has some problems
4257 with the blank space at the end */
4258 if (gtk_text_iter_forward_search (&iter, "--",
4259 GTK_TEXT_SEARCH_TEXT_ONLY,
4260 &match_start, NULL, NULL)) {
4261 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4262 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4264 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4265 &match_start, &match_end, NULL)) {
4269 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4274 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4275 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4276 if (has_new_signature) {
4279 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4280 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4282 is_rich = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
4284 WPTextBufferFormat *fmt;
4285 GdkColor style_color;
4286 if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
4287 gdk_color_parse ("grey", &style_color);
4289 fmt = g_new0 (WPTextBufferFormat, 1);
4290 fmt->color = style_color;
4291 fmt->cs.color = 0x1;
4292 wp_text_buffer_insert_with_attribute (WP_TEXT_BUFFER (priv->text_buffer), &iter,
4296 g_free (full_signature);
4298 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4302 gtk_text_buffer_end_user_action (priv->text_buffer);
4305 static void update_branding (ModestMsgEditWindow *self,
4306 const gchar *new_account)
4308 ModestMsgEditWindowPrivate *priv;
4309 ModestAccountMgr *mgr;
4310 const GdkPixbuf *new_icon = NULL;
4311 gchar *new_label = NULL;
4312 gboolean show = FALSE;
4314 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4316 mgr = modest_runtime_get_account_mgr ();
4318 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4320 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4321 gtk_widget_show (priv->brand_icon);
4324 gtk_widget_hide (priv->brand_icon);
4327 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4328 gtk_widget_show (priv->brand_label);
4332 gtk_widget_hide (priv->brand_label);
4336 gtk_widget_show (priv->brand_container);
4338 gtk_widget_hide (priv->brand_container);
4342 from_field_changed (GtkWidget *button,
4343 ModestMsgEditWindow *self)
4345 ModestMsgEditWindowPrivate *priv;
4346 gchar *old_account, *new_account;
4348 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4350 old_account = priv->last_from_account;
4351 new_account = modest_selector_get_active_id (priv->from_field);
4354 g_warning ("%s, could not get the new account", __FUNCTION__);
4358 /* If the From is the same do nothing */
4359 if (old_account && new_account && !strcmp (old_account, new_account))
4362 priv->last_from_account = new_account;
4364 update_signature (self, old_account, new_account);
4365 update_branding (self, new_account);
4369 typedef struct _MessageSettingsHelper {
4370 ModestMsgEditWindow *window;
4371 GSList *priority_group;
4372 GSList *format_group;
4373 GtkToggleButton *current_priority;
4374 GtkToggleButton *current_format;
4375 } MessageSettingsHelper;
4378 on_priority_toggle (GtkToggleButton *button,
4379 MessageSettingsHelper *helper)
4382 ModestMsgEditWindowPrivate *priv;
4384 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4385 if (gtk_toggle_button_get_active (button)) {
4387 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4388 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4389 if ((node_button != button) &&
4390 gtk_toggle_button_get_active (node_button)) {
4391 gtk_toggle_button_set_active (node_button, FALSE);
4394 helper->current_priority = button;
4396 gboolean found = FALSE;
4397 /* If no one is active, activate it again */
4398 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4399 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4400 if (gtk_toggle_button_get_active (node_button)) {
4406 gtk_toggle_button_set_active (button, TRUE);
4412 on_format_toggle (GtkToggleButton *button,
4413 MessageSettingsHelper *helper)
4416 ModestMsgEditWindowPrivate *priv;
4418 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4419 if (gtk_toggle_button_get_active (button)) {
4421 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4422 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4423 if ((node_button != button) &&
4424 gtk_toggle_button_get_active (node_button)) {
4425 gtk_toggle_button_set_active (node_button, FALSE);
4428 helper->current_format = button;
4430 gboolean found = FALSE;
4431 /* If no one is active, activate it again */
4432 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4433 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4434 if (gtk_toggle_button_get_active (node_button)) {
4440 gtk_toggle_button_set_active (button, TRUE);
4447 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4452 GtkWidget *priority_hbox;
4453 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4454 GtkWidget *captioned;
4455 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4456 GtkWidget *format_hbox;
4457 GtkWidget *html_toggle, *text_toggle;
4458 ModestMsgEditWindowPrivate *priv;
4459 MessageSettingsHelper helper = {0,};
4461 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4462 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4463 helper.window = window;
4464 helper.priority_group = NULL;
4465 helper.format_group = NULL;
4467 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4468 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4470 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4471 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4472 _HL_DONE, GTK_RESPONSE_ACCEPT, NULL);
4473 vbox = gtk_vbox_new (FALSE, 0);
4474 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4475 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4476 gtk_container_add (GTK_CONTAINER (align), vbox);
4477 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4478 gtk_widget_show (align);
4479 gtk_widget_show (vbox);
4481 /* Priority toggles */
4482 priority_hbox = gtk_hbox_new (TRUE, 0);
4483 #ifdef MODEST_TOOLKIT_HILDON2
4484 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4486 high_toggle = gtk_toggle_button_new ();
4488 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4489 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4490 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4491 #ifdef MODEST_TOOLKIT_HILDON2
4492 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4494 medium_toggle = gtk_toggle_button_new ();
4496 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4497 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4498 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4499 #ifdef MODEST_TOOLKIT_HILDON2
4500 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4502 low_toggle = gtk_toggle_button_new ();
4504 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4505 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4506 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4507 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4508 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4509 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4510 gtk_widget_show_all (priority_hbox);
4511 captioned = modest_toolkit_utils_create_captioned (title_sizegroup, value_sizegroup,
4512 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4513 gtk_widget_show (captioned);
4514 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4516 /* format toggles */
4517 format_hbox = gtk_hbox_new (TRUE, 0);
4518 #ifdef MODEST_TOOLKIT_HILDON2
4519 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4521 html_toggle = gtk_toggle_button_new ();
4523 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4524 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4525 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4526 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4527 #ifdef MODEST_TOOLKIT_HILDON2
4528 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4530 text_toggle = gtk_toggle_button_new ();
4532 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4533 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4534 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4535 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4536 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4537 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4538 gtk_widget_show_all (format_hbox);
4539 gtk_widget_show (format_hbox);
4540 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4543 g_object_unref (title_sizegroup);
4544 g_object_unref (value_sizegroup);
4546 /* Set current values */
4547 switch (priv->priority_flags) {
4548 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4549 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4550 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4552 case TNY_HEADER_FLAG_LOW_PRIORITY:
4553 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4554 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4557 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4558 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4562 switch (modest_msg_edit_window_get_format (window)) {
4563 case MODEST_MSG_EDIT_FORMAT_TEXT:
4564 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4565 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4567 case MODEST_MSG_EDIT_FORMAT_HTML:
4569 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4570 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4574 /* Signal connects */
4575 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4576 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4577 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4578 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4579 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4581 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4582 GTK_WINDOW (dialog), GTK_WINDOW (window));
4584 /* Save settings if the user clicked on done */
4585 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4586 TnyHeaderFlags flags;
4587 ModestMsgEditFormat old_format, new_format;
4589 /* Set priority flags */
4590 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4591 if (priv->priority_flags != flags)
4592 modest_msg_edit_window_set_priority_flags (window, flags);
4594 /* Set edit format */
4595 old_format = modest_msg_edit_window_get_format (window);
4596 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4597 if (old_format != new_format) {
4598 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4599 modest_msg_edit_window_set_file_format (window, file_format);
4603 gtk_widget_destroy (dialog);
4604 g_slist_free (helper.priority_group);
4608 on_message_settings (GtkAction *action,
4609 ModestMsgEditWindow *window)
4611 modest_msg_edit_window_show_msg_settings_dialog (window);
4615 on_cc_button_toggled (GtkWidget *button,
4616 ModestMsgEditWindow *window)
4618 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4620 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4621 modest_togglable_get_active (button));
4625 on_bcc_button_toggled (GtkWidget *button,
4626 ModestMsgEditWindow *window)
4628 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4630 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4631 modest_togglable_get_active (button));
4635 setup_menu (ModestMsgEditWindow *self)
4637 ModestMsgEditWindowPrivate *priv = NULL;
4639 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4641 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4643 /* Settings menu buttons */
4644 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4645 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4647 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4648 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4649 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4650 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4651 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4652 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4654 priv->cc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4655 _("mcen_me_editor_showcc"));
4656 modest_togglable_set_active (priv->cc_button,
4658 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4659 gtk_widget_show (priv->cc_button);
4660 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4661 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4663 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4664 _("mcen_me_editor_showbcc"));
4665 gtk_widget_show (priv->bcc_button);
4666 modest_togglable_set_active (priv->bcc_button,
4668 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4670 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4671 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4673 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4674 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4675 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4676 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4677 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4679 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4680 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4681 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4682 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4683 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4685 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4686 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4691 emit_open_addressbook (GtkButton *button,
4692 ModestRecptEditor *editor)
4694 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4698 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4699 const gchar *label, GtkWidget *control)
4701 GtkWidget *abook_button;
4704 GtkWidget *label_widget;
4706 box = gtk_hbox_new (FALSE, 0);
4708 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4709 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4711 #ifdef MODEST_TOOLKIT_HILDON2
4712 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4714 abook_button = gtk_button_new ();
4716 label_widget = gtk_label_new (label);
4717 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4718 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4720 gtk_container_add (GTK_CONTAINER (align), abook_button);
4721 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4722 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4723 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4724 if (title_size_group)
4725 gtk_size_group_add_widget (title_size_group, label_widget);
4726 if (value_size_group)
4727 gtk_size_group_add_widget (value_size_group, control);
4729 g_signal_connect (G_OBJECT (abook_button), "clicked",
4730 G_CALLBACK (emit_open_addressbook), control);
4736 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4738 ModestMsgEditWindowPrivate *priv = NULL;
4740 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4742 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4743 priv->max_chars_banner = NULL;
4747 has_pending_addresses (ModestRecptEditor *recpt_editor)
4749 const gchar *recipients = NULL;
4750 GSList *start_indexes = NULL, *end_indexes = NULL;
4751 GSList *current_start, *current_end;
4752 GtkTextBuffer *buffer;
4753 gint offset_delta = 0;
4755 gboolean has_recipients_to_add = FALSE;
4757 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4758 last_length = g_utf8_strlen (recipients, -1);
4759 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4764 current_start = start_indexes;
4765 current_end = end_indexes;
4766 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4768 while (current_start && !has_recipients_to_add) {
4770 gchar *start_ptr, *end_ptr;
4771 gint start_pos, end_pos;
4773 start_pos = (*((gint*) current_start->data)) + offset_delta;
4774 end_pos = (*((gint*) current_end->data)) + offset_delta;
4776 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4777 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4779 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4781 if (modest_text_utils_validate_recipient (address, NULL)) {
4782 if (!modest_address_book_has_address (address)) {
4783 has_recipients_to_add = TRUE;
4786 current_start = g_slist_next (current_start);
4787 current_end = g_slist_next (current_end);
4789 return has_recipients_to_add;
4793 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4795 ModestMsgEditWindowPrivate *priv = NULL;
4797 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4799 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4801 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4802 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4803 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))