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;
1589 #ifndef MODEST_TOOLKIT_HILDON2
1590 GSList *radio_group, *node;
1591 GtkWidget *fonts_menu;
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;
3625 gboolean no_to, no_cc, no_bcc;
3627 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3628 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3630 /* check if there's no recipient added */
3631 no_to = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)));
3632 no_cc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field)));
3633 no_bcc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field)));
3636 if (no_to && no_cc && no_bcc) {
3637 /* no recipient contents, then select contacts */
3638 modest_msg_edit_window_open_addressbook (window, NULL);
3643 g_object_ref (window);
3644 if (!no_to && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3645 (add_to_addressbook) ? &address_list : NULL)) {
3646 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3647 g_object_unref (window);
3650 if (!no_cc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3651 (add_to_addressbook) ? &address_list : NULL)) {
3652 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3653 g_object_unref (window);
3656 if (!no_bcc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3657 (add_to_addressbook) ? &address_list : NULL)) {
3658 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3659 g_object_unref (window);
3663 /* Add contacts to address book */
3664 if (add_to_addressbook && address_list)
3665 modest_address_book_add_address_list (address_list);
3667 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3668 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3669 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3670 g_object_unref (window);
3677 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3679 GSList *recipients = NULL;
3680 ModestMsgEditWindowPrivate *priv;
3681 gchar *joined, *after_remove, *to, *cc, *bcc;
3683 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3685 /* First of all check names */
3686 if (!modest_msg_edit_window_check_names (self, FALSE))
3689 if (!modest_msg_edit_window_has_pending_addresses (self))
3692 /* Don't add the from obviously */
3693 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3694 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3695 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3697 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3702 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3705 recipients = modest_text_utils_split_addresses_list (after_remove);
3706 g_free (after_remove);
3709 /* Offer the user to add recipients to the address book */
3710 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3711 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3716 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3717 ModestMsgEditWindow *window)
3719 modest_msg_edit_window_offer_attach_file (window);
3723 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3725 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3727 return priv->clipboard_text;
3731 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3733 ModestMsgEditWindow *window)
3735 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3736 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3739 /* It could happen that the window was already closed */
3740 if (!GTK_WIDGET_VISIBLE (window))
3743 g_object_ref (window);
3744 text = gtk_clipboard_wait_for_text (selection_clipboard);
3746 if (priv->clipboard_text != NULL) {
3747 g_free (priv->clipboard_text);
3749 priv->clipboard_text = text;
3751 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3753 g_object_unref (window);
3756 static gboolean clipboard_owner_change_idle (gpointer userdata)
3758 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3759 ModestMsgEditWindowPrivate *priv;
3761 gdk_threads_enter ();
3762 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3763 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3765 priv->clipboard_owner_idle = 0;
3766 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3767 gdk_threads_leave ();
3773 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3775 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3776 if (priv->clipboard_owner_idle == 0) {
3777 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3778 clipboard_owner_change_idle,
3779 g_object_ref (window),
3785 subject_field_move_cursor (GtkEntry *entry,
3786 GtkMovementStep step,
3791 /* It could happen that the window was already closed */
3792 if (!GTK_WIDGET_VISIBLE (window))
3795 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3799 update_window_title (ModestMsgEditWindow *window)
3801 ModestMsgEditWindowPrivate *priv = NULL;
3802 const gchar *subject;
3804 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3805 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3806 if (subject == NULL || subject[0] == '\0')
3807 subject = _("mail_va_new_email");
3809 modest_window_set_title (MODEST_WINDOW (window), subject);
3815 body_insert_text (GtkTextBuffer *buffer,
3816 GtkTextIter *location,
3819 ModestMsgEditWindow *window)
3821 GtkTextIter end_iter;
3828 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3830 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3832 offset = gtk_text_iter_get_offset (&end_iter);
3833 line = gtk_text_iter_get_line (&end_iter);
3837 while (text_offset < text + len) {
3838 if (*text_offset == '\n')
3840 if (text_lines + line >= MAX_BODY_LINES) {
3841 len = text_offset - text;
3847 utf8_len = g_utf8_strlen (text, len);
3849 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3850 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3851 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3856 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3858 /* Prevent endless recursion */
3859 result = g_strndup (text, utf8_end - text);
3860 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3861 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3862 (gpointer) result, (gpointer) (utf8_end - text),
3864 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3868 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3869 if (priv->max_chars_banner == NULL) {
3870 #ifdef MODEST_TOOLKIT_HILDON2
3871 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3872 _CS_MAXIMUM_CHARACTERS_REACHED);
3873 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3880 subject_field_changed (GtkEditable *editable,
3881 ModestMsgEditWindow *window)
3883 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3884 update_window_title (window);
3885 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3886 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3887 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3890 subject_field_insert_text (GtkEditable *editable,
3892 gint new_text_length,
3894 ModestMsgEditWindow *window)
3896 GString *result = g_string_new ("");
3898 gint result_len = 0;
3899 const gchar *entry_text = NULL;
3902 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3903 old_length = g_utf8_strlen (entry_text, -1);
3905 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3906 gunichar c = g_utf8_get_char_validated (current, 8);
3907 /* Invalid unichar, stop */
3913 result = g_string_append_unichar (result, c);
3917 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3918 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3921 /* Prevent endless recursion */
3922 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3923 g_signal_emit_by_name (editable, "insert-text",
3924 (gpointer) result->str, (gpointer) result->len,
3925 (gpointer) position, (gpointer) window);
3926 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3930 if (result_len + old_length > 1000) {
3931 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3932 _CS_MAXIMUM_CHARACTERS_REACHED);
3934 g_string_free (result, TRUE);
3938 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3941 ModestMsgEditWindowPrivate *priv = NULL;
3943 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3944 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3946 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3949 gtk_widget_show_all (priv->isearch_toolbar);
3950 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3952 gtk_widget_hide_all (priv->isearch_toolbar);
3953 gtk_widget_grab_focus (priv->msg_body);
3958 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3960 GtkTextIter *match_start,
3961 GtkTextIter *match_end)
3963 GtkTextIter end_iter;
3964 gchar *str_casefold;
3967 gchar *range_casefold;
3970 gboolean result = FALSE;
3977 gtk_text_iter_forward_to_end (&end_iter);
3979 str_casefold = g_utf8_casefold (str, -1);
3980 str_chars_n = strlen (str);
3982 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3983 range_casefold = g_utf8_casefold (range_text, -1);
3984 range_chars_n = strlen (range_casefold);
3986 if (range_chars_n < str_chars_n) {
3987 g_free (str_casefold);
3988 g_free (range_text);
3989 g_free (range_casefold);
3993 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3994 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3995 if (!g_utf8_collate (range_subtext, str_casefold)) {
3996 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3998 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3999 match_start, match_end, NULL)) {
4000 g_debug ("Matched string with collate, but not matched in model");
4002 g_free (found_text);
4004 g_free (range_subtext);
4008 g_free (str_casefold);
4009 g_free (range_text);
4010 g_free (range_casefold);
4017 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
4018 ModestMsgEditWindow *window)
4020 const gchar *current_search = NULL;
4021 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4023 GtkTextIter selection_start, selection_end;
4024 GtkTextIter match_start, match_end;
4025 gboolean continue_search = FALSE;
4027 if (message_is_empty (window)) {
4028 g_free (priv->last_search);
4029 priv->last_search = NULL;
4030 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
4034 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
4035 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
4036 g_free (priv->last_search);
4037 priv->last_search = NULL;
4038 /* Information banner about empty search */
4039 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
4043 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
4044 continue_search = TRUE;
4046 g_free (priv->last_search);
4047 priv->last_search = g_strdup (current_search);
4050 if (continue_search) {
4051 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
4052 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
4053 &match_start, &match_end);
4055 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_COMPLETE);
4057 GtkTextIter buffer_start;
4058 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
4059 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
4060 &match_start, &match_end);
4062 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_NO_MATCHES);
4065 /* Mark as selected the string found in search */
4067 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
4068 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
4069 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
4071 g_free (priv->last_search);
4072 priv->last_search = NULL;
4077 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
4079 ModestMsgEditWindowPrivate *priv;
4081 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
4086 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
4089 ModestMsgEditWindowPrivate *priv;
4091 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
4096 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
4097 ModestMsgEditWindow *window)
4099 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
4103 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
4106 ModestMsgEditWindowPrivate *priv;
4107 TnyHeader *header = NULL;
4109 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4110 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
4112 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4114 if (priv->draft_msg != NULL) {
4115 g_object_unref (priv->draft_msg);
4118 if (draft != NULL) {
4119 g_object_ref (draft);
4120 header = tny_msg_get_header (draft);
4121 if (priv->msg_uid) {
4122 g_free (priv->msg_uid);
4123 priv->msg_uid = NULL;
4125 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
4128 priv->draft_msg = draft;
4132 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
4133 GtkTextIter *start, GtkTextIter *end,
4136 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
4137 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
4140 if (tag == NULL) return;
4141 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
4142 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
4143 replace_with_images (window, priv->images);
4148 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
4151 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4153 g_return_if_fail (TNY_IS_MIME_PART (part));
4154 tny_list_prepend (priv->attachments, (GObject *) part);
4155 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
4156 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
4157 gtk_widget_show_all (priv->attachments_caption);
4158 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
4162 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
4164 ModestMsgEditWindowPrivate *priv;
4166 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
4167 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4169 return priv->msg_uid;
4173 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
4174 ModestMsgEditWindowWidgetType widget_type)
4176 ModestMsgEditWindowPrivate *priv;
4178 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
4179 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
4181 switch (widget_type) {
4182 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
4183 return priv->msg_body;
4185 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
4186 return priv->to_field;
4188 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
4189 return priv->cc_field;
4191 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4192 return priv->bcc_field;
4194 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4195 return priv->subject_field;
4197 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4198 return priv->attachments_view;
4206 remove_tags (WPTextBuffer *buffer)
4208 GtkTextIter start, end;
4210 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4211 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4213 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4217 on_account_removed (TnyAccountStore *account_store,
4218 TnyAccount *account,
4221 /* Do nothing if it's a store account, because we use the
4222 transport to send the messages */
4223 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4224 const gchar *parent_acc = NULL;
4225 const gchar *our_acc = NULL;
4227 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4228 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4229 /* Close this window if I'm showing a message of the removed account */
4230 if (strcmp (parent_acc, our_acc) == 0)
4231 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4236 update_signature (ModestMsgEditWindow *self,
4237 const gchar *old_account,
4238 const gchar *new_account)
4240 ModestMsgEditWindowPrivate *priv;
4241 gboolean has_old_signature, has_new_signature;
4243 ModestAccountMgr *mgr;
4246 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4248 gtk_text_buffer_begin_user_action (priv->text_buffer);
4250 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4251 mgr = modest_runtime_get_account_mgr ();
4255 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4256 if (has_old_signature) {
4257 GtkTextIter match_start, match_end;
4259 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4260 seems that the search has some problems
4261 with the blank space at the end */
4262 if (gtk_text_iter_forward_search (&iter, "--",
4263 GTK_TEXT_SEARCH_TEXT_ONLY,
4264 &match_start, NULL, NULL)) {
4265 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4266 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4268 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4269 &match_start, &match_end, NULL)) {
4273 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4278 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4279 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4280 if (has_new_signature) {
4283 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4284 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4286 is_rich = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
4288 WPTextBufferFormat *fmt;
4289 GdkColor style_color;
4290 if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
4291 gdk_color_parse ("grey", &style_color);
4293 fmt = g_new0 (WPTextBufferFormat, 1);
4294 fmt->color = style_color;
4295 fmt->cs.color = 0x1;
4296 wp_text_buffer_insert_with_attribute (WP_TEXT_BUFFER (priv->text_buffer), &iter,
4300 g_free (full_signature);
4302 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4306 gtk_text_buffer_end_user_action (priv->text_buffer);
4309 static void update_branding (ModestMsgEditWindow *self,
4310 const gchar *new_account)
4312 ModestMsgEditWindowPrivate *priv;
4313 ModestAccountMgr *mgr;
4314 const GdkPixbuf *new_icon = NULL;
4315 gchar *new_label = NULL;
4316 gboolean show = FALSE;
4318 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4320 mgr = modest_runtime_get_account_mgr ();
4322 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4324 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4325 gtk_widget_show (priv->brand_icon);
4328 gtk_widget_hide (priv->brand_icon);
4331 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4332 gtk_widget_show (priv->brand_label);
4336 gtk_widget_hide (priv->brand_label);
4340 gtk_widget_show (priv->brand_container);
4342 gtk_widget_hide (priv->brand_container);
4346 from_field_changed (GtkWidget *button,
4347 ModestMsgEditWindow *self)
4349 ModestMsgEditWindowPrivate *priv;
4350 gchar *old_account, *new_account;
4352 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4354 old_account = priv->last_from_account;
4355 new_account = modest_selector_get_active_id (priv->from_field);
4358 g_warning ("%s, could not get the new account", __FUNCTION__);
4362 /* If the From is the same do nothing */
4363 if (old_account && new_account && !strcmp (old_account, new_account))
4366 priv->last_from_account = new_account;
4368 update_signature (self, old_account, new_account);
4369 update_branding (self, new_account);
4373 typedef struct _MessageSettingsHelper {
4374 ModestMsgEditWindow *window;
4375 GSList *priority_group;
4376 GSList *format_group;
4377 GtkToggleButton *current_priority;
4378 GtkToggleButton *current_format;
4379 } MessageSettingsHelper;
4382 on_priority_toggle (GtkToggleButton *button,
4383 MessageSettingsHelper *helper)
4386 ModestMsgEditWindowPrivate *priv;
4388 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4389 if (gtk_toggle_button_get_active (button)) {
4391 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4392 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4393 if ((node_button != button) &&
4394 gtk_toggle_button_get_active (node_button)) {
4395 gtk_toggle_button_set_active (node_button, FALSE);
4398 helper->current_priority = button;
4400 gboolean found = FALSE;
4401 /* If no one is active, activate it again */
4402 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4403 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4404 if (gtk_toggle_button_get_active (node_button)) {
4410 gtk_toggle_button_set_active (button, TRUE);
4416 on_format_toggle (GtkToggleButton *button,
4417 MessageSettingsHelper *helper)
4420 ModestMsgEditWindowPrivate *priv;
4422 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4423 if (gtk_toggle_button_get_active (button)) {
4425 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4426 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4427 if ((node_button != button) &&
4428 gtk_toggle_button_get_active (node_button)) {
4429 gtk_toggle_button_set_active (node_button, FALSE);
4432 helper->current_format = button;
4434 gboolean found = FALSE;
4435 /* If no one is active, activate it again */
4436 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4437 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4438 if (gtk_toggle_button_get_active (node_button)) {
4444 gtk_toggle_button_set_active (button, TRUE);
4451 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4456 GtkWidget *priority_hbox;
4457 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4458 GtkWidget *captioned;
4459 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4460 GtkWidget *format_hbox;
4461 GtkWidget *html_toggle, *text_toggle;
4462 ModestMsgEditWindowPrivate *priv;
4463 MessageSettingsHelper helper = {0,};
4465 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4466 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4467 helper.window = window;
4468 helper.priority_group = NULL;
4469 helper.format_group = NULL;
4471 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4472 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4474 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4475 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4476 _HL_DONE, GTK_RESPONSE_ACCEPT, NULL);
4477 vbox = gtk_vbox_new (FALSE, 0);
4478 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4479 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4480 gtk_container_add (GTK_CONTAINER (align), vbox);
4481 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4482 gtk_widget_show (align);
4483 gtk_widget_show (vbox);
4485 /* Priority toggles */
4486 priority_hbox = gtk_hbox_new (TRUE, 0);
4487 #ifdef MODEST_TOOLKIT_HILDON2
4488 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4490 high_toggle = gtk_toggle_button_new ();
4492 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4493 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4494 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4495 #ifdef MODEST_TOOLKIT_HILDON2
4496 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4498 medium_toggle = gtk_toggle_button_new ();
4500 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4501 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4502 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4503 #ifdef MODEST_TOOLKIT_HILDON2
4504 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4506 low_toggle = gtk_toggle_button_new ();
4508 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4509 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4510 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4511 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4512 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4513 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4514 gtk_widget_show_all (priority_hbox);
4515 captioned = modest_toolkit_utils_create_captioned (title_sizegroup, value_sizegroup,
4516 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4517 gtk_widget_show (captioned);
4518 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4520 /* format toggles */
4521 format_hbox = gtk_hbox_new (TRUE, 0);
4522 #ifdef MODEST_TOOLKIT_HILDON2
4523 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4525 html_toggle = gtk_toggle_button_new ();
4527 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4528 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4529 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4530 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4531 #ifdef MODEST_TOOLKIT_HILDON2
4532 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4534 text_toggle = gtk_toggle_button_new ();
4536 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4537 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4538 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4539 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4540 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4541 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4542 gtk_widget_show_all (format_hbox);
4543 gtk_widget_show (format_hbox);
4544 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4547 g_object_unref (title_sizegroup);
4548 g_object_unref (value_sizegroup);
4550 /* Set current values */
4551 switch (priv->priority_flags) {
4552 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4553 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4554 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4556 case TNY_HEADER_FLAG_LOW_PRIORITY:
4557 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4558 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4561 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4562 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4566 switch (modest_msg_edit_window_get_format (window)) {
4567 case MODEST_MSG_EDIT_FORMAT_TEXT:
4568 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4569 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4571 case MODEST_MSG_EDIT_FORMAT_HTML:
4573 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4574 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4578 /* Signal connects */
4579 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4580 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4581 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4582 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4583 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4585 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4586 GTK_WINDOW (dialog), GTK_WINDOW (window));
4588 /* Save settings if the user clicked on done */
4589 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4590 TnyHeaderFlags flags;
4591 ModestMsgEditFormat old_format, new_format;
4593 /* Set priority flags */
4594 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4595 if (priv->priority_flags != flags)
4596 modest_msg_edit_window_set_priority_flags (window, flags);
4598 /* Set edit format */
4599 old_format = modest_msg_edit_window_get_format (window);
4600 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4601 if (old_format != new_format) {
4602 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4603 modest_msg_edit_window_set_file_format (window, file_format);
4607 gtk_widget_destroy (dialog);
4608 g_slist_free (helper.priority_group);
4612 on_message_settings (GtkAction *action,
4613 ModestMsgEditWindow *window)
4615 modest_msg_edit_window_show_msg_settings_dialog (window);
4619 on_cc_button_toggled (GtkWidget *button,
4620 ModestMsgEditWindow *window)
4622 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4624 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4625 modest_togglable_get_active (button));
4629 on_bcc_button_toggled (GtkWidget *button,
4630 ModestMsgEditWindow *window)
4632 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4634 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4635 modest_togglable_get_active (button));
4639 setup_menu (ModestMsgEditWindow *self)
4641 ModestMsgEditWindowPrivate *priv = NULL;
4643 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4645 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4647 /* Settings menu buttons */
4648 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4649 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4651 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4652 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4653 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4654 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4655 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4656 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4658 priv->cc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4659 _("mcen_me_editor_showcc"));
4660 modest_togglable_set_active (priv->cc_button,
4662 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4663 gtk_widget_show (priv->cc_button);
4664 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4665 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4667 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4668 _("mcen_me_editor_showbcc"));
4669 gtk_widget_show (priv->bcc_button);
4670 modest_togglable_set_active (priv->bcc_button,
4672 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4674 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4675 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4677 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4678 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4679 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4680 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4681 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4683 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4684 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4685 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4686 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4687 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4689 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4690 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4695 emit_open_addressbook (GtkButton *button,
4696 ModestRecptEditor *editor)
4698 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4702 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4703 const gchar *label, GtkWidget *control)
4705 GtkWidget *abook_button;
4708 GtkWidget *label_widget;
4710 box = gtk_hbox_new (FALSE, 0);
4712 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4713 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4715 #ifdef MODEST_TOOLKIT_HILDON2
4716 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4718 abook_button = gtk_button_new ();
4720 label_widget = gtk_label_new (label);
4721 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4722 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4724 gtk_container_add (GTK_CONTAINER (align), abook_button);
4725 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4726 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4727 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4728 if (title_size_group)
4729 gtk_size_group_add_widget (title_size_group, label_widget);
4730 if (value_size_group)
4731 gtk_size_group_add_widget (value_size_group, control);
4733 g_signal_connect (G_OBJECT (abook_button), "clicked",
4734 G_CALLBACK (emit_open_addressbook), control);
4740 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4742 ModestMsgEditWindowPrivate *priv = NULL;
4744 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4746 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4747 priv->max_chars_banner = NULL;
4751 has_pending_addresses (ModestRecptEditor *recpt_editor)
4753 const gchar *recipients = NULL;
4754 GSList *start_indexes = NULL, *end_indexes = NULL;
4755 GSList *current_start, *current_end;
4756 GtkTextBuffer *buffer;
4757 gint offset_delta = 0;
4759 gboolean has_recipients_to_add = FALSE;
4761 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4762 last_length = g_utf8_strlen (recipients, -1);
4763 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4768 current_start = start_indexes;
4769 current_end = end_indexes;
4770 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4772 while (current_start && !has_recipients_to_add) {
4774 gchar *start_ptr, *end_ptr;
4775 gint start_pos, end_pos;
4777 start_pos = (*((gint*) current_start->data)) + offset_delta;
4778 end_pos = (*((gint*) current_end->data)) + offset_delta;
4780 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4781 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4783 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4785 if (modest_text_utils_validate_recipient (address, NULL)) {
4786 if (!modest_address_book_has_address (address)) {
4787 has_recipients_to_add = TRUE;
4790 current_start = g_slist_next (current_start);
4791 current_end = g_slist_next (current_end);
4793 return has_recipients_to_add;
4797 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4799 ModestMsgEditWindowPrivate *priv = NULL;
4801 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4803 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4805 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4806 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4807 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))