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_show_toolbar_button_toggled (GtkWidget *button,
192 ModestMsgEditWindow *window);
193 static void on_message_settings (GtkAction *action,
194 ModestMsgEditWindow *window);
195 static void setup_menu (ModestMsgEditWindow *self);
197 static void from_field_changed (GtkWidget *button,
198 ModestMsgEditWindow *self);
199 static void font_size_clicked (GtkToolButton *button,
200 ModestMsgEditWindow *window);
201 static void update_signature (ModestMsgEditWindow *self,
202 const gchar *old_account,
203 const gchar *new_account);
204 static void update_branding (ModestMsgEditWindow *self,
205 const gchar *new_account);
206 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
207 const gchar *label, GtkWidget *control);
208 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
209 static void DEBUG_BUFFER (WPTextBuffer *buffer)
213 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
215 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
216 while (!gtk_text_iter_is_end (&iter)) {
217 GString *output = g_string_new ("");
218 GSList *toggled_tags;
221 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
222 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
223 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
224 GtkTextTag *tag = (GtkTextTag *) node->data;
226 g_object_get (G_OBJECT (tag), "name", &name, NULL);
227 output = g_string_append (output, name);
228 g_string_append (output, " ");
230 output = g_string_append (output, "] OPENED [ ");
231 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
232 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
233 GtkTextTag *tag = (GtkTextTag *) node->data;
235 g_object_get (G_OBJECT (tag), "name", &name, NULL);
236 output = g_string_append (output, name);
237 g_string_append (output, " ");
239 output = g_string_append (output, "]\n");
240 g_debug ("%s", output->str);
241 g_string_free (output, TRUE);
242 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
244 g_debug ("END BUFFER");
248 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
249 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
253 /* static gboolean */
254 /* on_key_pressed (GtkWidget *self, */
255 /* GdkEventKey *event, */
256 /* gpointer user_data); */
258 /* list my signals */
265 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
266 struct _ModestMsgEditWindowPrivate {
268 GtkWidget *header_box;
270 ModestPairList *from_field_protos;
271 GtkWidget *from_field;
272 gchar *last_from_account;
273 gchar *original_account_name;
278 gchar *original_mailbox;
282 GtkWidget *bcc_field;
283 GtkWidget *subject_field;
284 GtkWidget *attachments_view;
285 GtkWidget *priority_icon;
286 GtkWidget *subject_box;
287 GtkWidget *send_button;
289 GtkWidget *cc_caption;
290 GtkWidget *bcc_caption;
291 gboolean update_caption_visibility;
292 GtkWidget *attachments_caption;
294 GtkTextBuffer *text_buffer;
296 GtkWidget *font_size_toolitem;
297 GtkWidget *font_face_toolitem;
298 GtkWidget *font_color_button;
299 GtkWidget *font_color_toolitem;
300 GSList *font_items_group;
301 GtkTreeModel *faces_model;
302 gint current_face_index;
303 GtkWidget *font_tool_button_label;
304 GtkTreeModel *sizes_model;
305 gint current_size_index;
306 GtkWidget *size_tool_button_label;
308 GtkWidget *isearch_toolbar;
311 GtkWidget *font_dialog;
313 GtkWidget *scrollable;
314 guint correct_scroll_idle;
315 guint scroll_drag_timeout_id;
319 TnyList *attachments;
324 TnyHeaderFlags priority_flags;
326 gboolean can_undo, can_redo;
327 gulong clipboard_change_handler_id;
328 gulong default_clipboard_change_handler_id;
329 gulong account_removed_handler_id;
330 guint clipboard_owner_idle;
331 gchar *clipboard_text;
340 GtkWidget *cc_button;
341 GtkWidget *bcc_button;
342 GtkWidget *show_toolbar_button;
344 GtkWidget *max_chars_banner;
346 GtkWidget *brand_icon;
347 GtkWidget *brand_label;
348 GtkWidget *brand_container;
351 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
352 MODEST_TYPE_MSG_EDIT_WINDOW, \
353 ModestMsgEditWindowPrivate))
355 static GtkWindowClass *parent_class = NULL;
357 /* uncomment the following if you have defined any signals */
358 /* static guint signals[LAST_SIGNAL] = {0}; */
361 modest_msg_edit_window_get_type (void)
363 static GType my_type = 0;
365 static const GTypeInfo my_info = {
366 sizeof(ModestMsgEditWindowClass),
367 NULL, /* base init */
368 NULL, /* base finalize */
369 (GClassInitFunc) modest_msg_edit_window_class_init,
370 NULL, /* class finalize */
371 NULL, /* class data */
372 sizeof(ModestMsgEditWindow),
374 (GInstanceInitFunc) modest_msg_edit_window_init,
377 my_type = g_type_register_static (
378 #ifdef MODEST_TOOLKIT_HILDON2
379 MODEST_TYPE_HILDON2_WINDOW,
381 MODEST_TYPE_SHELL_WINDOW,
383 "ModestMsgEditWindow",
391 save_state (ModestWindow *self)
393 modest_widget_memory_save (modest_runtime_get_conf(),
394 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
399 restore_settings (ModestMsgEditWindow *self)
401 ModestConf *conf = NULL;
403 conf = modest_runtime_get_conf ();
405 /* Dim at start clipboard actions */
406 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
411 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
413 GObjectClass *gobject_class;
414 ModestWindowClass *modest_window_class;
415 gobject_class = (GObjectClass*) klass;
416 modest_window_class = (ModestWindowClass*) klass;
418 parent_class = g_type_class_peek_parent (klass);
419 gobject_class->finalize = modest_msg_edit_window_finalize;
421 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
422 modest_window_class->save_state_func = save_state;
423 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
425 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
429 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
431 ModestMsgEditWindowPrivate *priv;
432 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
434 priv->msg_body = NULL;
435 priv->from_field = NULL;
436 priv->to_field = NULL;
437 priv->cc_field = NULL;
438 priv->bcc_field = NULL;
439 priv->subject_field = NULL;
440 priv->attachments = TNY_LIST (tny_simple_list_new ());
441 priv->images = TNY_LIST (tny_simple_list_new ());
442 priv->images_size = 0;
443 priv->images_count = 0;
446 priv->cc_caption = NULL;
447 priv->bcc_caption = NULL;
448 priv->update_caption_visibility = FALSE;
450 priv->priority_flags = 0;
452 priv->isearch_toolbar = NULL;
453 priv->last_search = NULL;
455 priv->draft_msg = NULL;
456 priv->outbox_msg = NULL;
457 priv->msg_uid = NULL;
459 priv->can_undo = FALSE;
460 priv->can_redo = FALSE;
461 priv->clipboard_change_handler_id = 0;
462 priv->default_clipboard_change_handler_id = 0;
463 priv->account_removed_handler_id = 0;
464 priv->clipboard_owner_idle = 0;
465 priv->clipboard_text = NULL;
468 priv->scroll_drag_timeout_id = 0;
469 priv->correct_scroll_idle = 0;
470 priv->last_upper = 0.0;
472 priv->font_dialog = NULL;
473 priv->app_menu = NULL;
475 priv->references = NULL;
476 priv->in_reply_to = NULL;
477 priv->max_chars_banner = NULL;
479 if (!is_wp_text_buffer_started) {
480 is_wp_text_buffer_started = TRUE;
481 wp_text_buffer_library_init ();
485 #ifdef MODEST_TOOLKIT_HILDON2
486 hildon_program_add_window (hildon_program_get_instance(),
492 multimailbox_get_default_mailbox (const gchar *account_name)
494 gchar *transport_account;
495 gchar *result = NULL;
497 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
499 TNY_ACCOUNT_TYPE_TRANSPORT);
500 if (transport_account) {
502 ModestProtocolRegistry *registry;
504 registry = modest_runtime_get_protocol_registry ();
506 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
507 MODEST_ACCOUNT_PROTO, TRUE);
509 ModestProtocol *protocol =
510 modest_protocol_registry_get_protocol_by_name (registry,
511 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
513 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
514 ModestPairList *pair_list;
516 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
519 ModestPair *pair = (ModestPair *) pair_list->data;
520 result = g_strdup ((const gchar *) pair->first);
521 modest_pair_list_free (pair_list);
532 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
534 static ModestPairList*
535 get_transports (void)
537 GSList *transports = NULL;
539 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
540 GSList *accounts = modest_account_mgr_account_names (account_mgr,
541 TRUE /* only enabled accounts. */);
543 GSList *cursor = accounts;
545 gchar *account_name = cursor->data;
548 gchar *transport_account;
549 gboolean multi_mailbox = FALSE;
550 ModestProtocol *protocol = NULL;
552 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
554 transport_account = modest_account_mgr_get_server_account_name
555 (modest_runtime_get_account_mgr (),
557 TNY_ACCOUNT_TYPE_TRANSPORT);
558 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
559 ModestPairList *pair_list;
560 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
563 transports = g_slist_concat (transports, pair_list);
564 multi_mailbox = TRUE;
569 if (!multi_mailbox) {
570 gchar *from_string = NULL;
572 from_string = modest_account_mgr_get_from_string (account_mgr,
574 if (from_string && account_name) {
575 gchar *name = account_name;
576 ModestPair *pair = modest_pair_new ((gpointer) name,
577 (gpointer) from_string , TRUE);
578 transports = g_slist_prepend (transports, pair);
583 cursor = cursor->next;
585 g_slist_free (accounts); /* only free the accounts, not the elements,
586 * because they are used in the pairlist */
590 static void window_focus (GtkWindow *window,
594 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
598 scroll_drag_timeout (gpointer userdata)
600 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
601 ModestMsgEditWindowPrivate *priv;
603 /* It could happen that the window was already closed */
604 if (!GTK_WIDGET_VISIBLE (win))
607 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
609 correct_scroll_without_drag_check (win, TRUE);
611 priv->scroll_drag_timeout_id = 0;
617 correct_scroll_without_drag_check_idle (gpointer userdata)
619 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
620 ModestMsgEditWindowPrivate *priv;
622 GdkRectangle rectangle;
623 gint offset_min, offset_max;
627 /* It could happen that the window was already closed */
628 if (!GTK_WIDGET_VISIBLE (w))
631 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
633 insert = gtk_text_buffer_get_insert (priv->text_buffer);
634 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
636 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
637 offset_min = priv->msg_body->allocation.y + rectangle.y;
638 offset_max = offset_min + rectangle.height;
640 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
641 offset_min = MAX (offset_min - 48, 0);
642 offset_max = MIN (offset_max + 48, vadj->upper);
644 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
646 priv->correct_scroll_idle = 0;
651 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
653 ModestMsgEditWindowPrivate *priv;
655 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
657 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
660 if (priv->correct_scroll_idle > 0) {
664 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
665 (GSourceFunc) correct_scroll_without_drag_check_idle,
671 correct_scroll (ModestMsgEditWindow *w)
673 ModestMsgEditWindowPrivate *priv;
675 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
676 if (gtk_grab_get_current () == priv->msg_body) {
677 if (priv->scroll_drag_timeout_id == 0) {
678 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
680 (GSourceFunc) scroll_drag_timeout,
687 correct_scroll_without_drag_check (w, TRUE);
691 text_buffer_end_user_action (GtkTextBuffer *buffer,
692 ModestMsgEditWindow *userdata)
695 correct_scroll (userdata);
699 text_buffer_mark_set (GtkTextBuffer *buffer,
702 ModestMsgEditWindow *userdata)
704 gtk_text_buffer_begin_user_action (buffer);
705 gtk_text_buffer_end_user_action (buffer);
709 cut_clipboard_check (GtkTextView *text_view,
712 GtkTextBuffer *buffer;
714 buffer = gtk_text_view_get_buffer (text_view);
715 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
716 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
721 copy_clipboard_check (GtkTextView *text_view,
724 GtkTextBuffer *buffer;
726 buffer = gtk_text_view_get_buffer (text_view);
727 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
728 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
733 attachment_deleted (ModestAttachmentsView *attachments_view,
736 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
741 body_size_request (GtkWidget *body,
745 /* Make sure the body always get at least 70 pixels */
746 if (req->height < 70)
751 connect_signals (ModestMsgEditWindow *obj)
753 ModestMsgEditWindowPrivate *priv;
755 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
757 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
758 G_CALLBACK (text_buffer_refresh_attributes), obj);
759 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
760 G_CALLBACK (text_buffer_can_undo), obj);
761 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
762 G_CALLBACK (text_buffer_can_redo), obj);
763 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
764 G_CALLBACK (body_changed), obj);
765 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
766 G_CALLBACK (body_insert_text), obj);
767 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
768 G_CALLBACK (body_changed), obj);
769 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
770 G_CALLBACK (text_buffer_end_user_action), obj);
771 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
772 G_CALLBACK (text_buffer_mark_set), obj);
773 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
774 G_CALLBACK (text_buffer_apply_tag), obj);
775 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
776 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
777 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
778 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
779 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
780 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
782 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
783 G_CALLBACK (modest_ui_actions_on_send), obj);
785 if (GTK_IS_COMBO_BOX (priv->from_field)) {
786 g_signal_connect (G_OBJECT (priv->from_field), "changed",
787 G_CALLBACK (from_field_changed), obj);
789 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
790 G_CALLBACK (from_field_changed), obj);
793 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
794 G_CALLBACK (msg_body_focus), obj);
795 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
796 G_CALLBACK (msg_body_focus), obj);
797 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
798 G_CALLBACK (body_size_request), obj);
799 if (GTK_IS_WINDOW (obj)) {
800 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
802 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
803 "changed", G_CALLBACK (recpt_field_changed), obj);
804 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
805 "changed", G_CALLBACK (recpt_field_changed), obj);
806 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
807 "changed", G_CALLBACK (recpt_field_changed), obj);
808 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
809 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
810 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
812 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
813 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
814 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
815 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_close), obj);
817 priv->clipboard_change_handler_id =
818 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
819 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
820 priv->default_clipboard_change_handler_id =
821 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
822 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
824 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
825 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
826 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
830 init_wp_text_view_style ()
832 static gboolean initialized = FALSE;
835 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
841 init_window (ModestMsgEditWindow *obj)
843 GtkWidget *to_caption, *subject_caption;
844 GtkWidget *main_vbox;
845 ModestMsgEditWindowPrivate *priv;
846 GtkActionGroup *action_group;
847 ModestWindowPrivate *parent_priv;
848 GError *error = NULL;
850 GtkSizeGroup *title_size_group;
851 GtkSizeGroup *value_size_group;
852 GtkWidget *window_box;
853 GtkWidget *window_align;
854 #if (GTK_MINOR_VERSION >= 10)
855 GdkAtom deserialize_type;
857 GtkWidget *from_send_hbox;
858 GtkWidget *send_icon;
859 GtkWidget *attachments_label;
860 GtkWidget *branding_box;
861 GtkWidget *from_caption;
863 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
864 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
866 parent_priv->ui_manager = gtk_ui_manager_new();
867 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
868 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
870 /* Add common actions */
871 gtk_action_group_add_actions (action_group,
872 modest_msg_edit_action_entries,
873 G_N_ELEMENTS (modest_msg_edit_action_entries),
875 gtk_action_group_add_actions (action_group,
876 hildon2_msg_edit_action_entries,
877 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
879 gtk_action_group_add_toggle_actions (action_group,
880 modest_msg_edit_toggle_action_entries,
881 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
883 gtk_action_group_add_radio_actions (action_group,
884 modest_msg_edit_alignment_radio_action_entries,
885 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
887 G_CALLBACK (modest_ui_actions_on_change_justify),
889 gtk_action_group_add_radio_actions (action_group,
890 modest_msg_edit_priority_action_entries,
891 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
893 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
895 gtk_action_group_add_radio_actions (action_group,
896 modest_msg_edit_file_format_action_entries,
897 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
898 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
899 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
901 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
902 g_object_unref (action_group);
904 /* Load the UI definition */
905 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
908 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
909 g_clear_error (&error);
912 parent_priv->menubar = NULL;
914 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
915 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
917 /* Note: This ModestPairList* must exist for as long as the picker
918 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
919 * so it can't know how to manage its memory. */
920 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
922 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
923 if (GTK_IS_COMBO_BOX (priv->from_field)) {
924 from_caption = modest_toolkit_utils_create_captioned (title_size_group, NULL,
925 _("mail_va_from"), FALSE,
927 gtk_widget_show (from_caption);
929 #ifdef MODEST_TOOLKIT_HILDON2
930 modest_toolkit_utils_set_hbutton_layout (title_size_group, NULL,
931 _("mail_va_from"), priv->from_field);
932 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
933 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
934 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
935 from_caption = priv->from_field;
939 priv->to_field = modest_recpt_editor_new ();
940 priv->cc_field = modest_recpt_editor_new ();
941 priv->bcc_field = modest_recpt_editor_new ();
942 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
943 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
944 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
945 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
946 priv->priority_icon = gtk_image_new ();
947 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
948 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
949 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
950 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
951 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
953 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
954 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
956 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
957 priv->attachments_view = modest_attachments_view_new (NULL);
958 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
959 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
961 priv->header_box = gtk_vbox_new (FALSE, 0);
963 to_caption = _create_addressbook_box
964 (title_size_group, value_size_group,
965 _("mail_va_to"), priv->to_field);
966 priv->cc_caption = _create_addressbook_box
967 (title_size_group, value_size_group,
968 _("mail_va_cc"), priv->cc_field);
969 priv->bcc_caption = _create_addressbook_box
970 (title_size_group, value_size_group,
971 _("mail_va_hotfix1"), priv->bcc_field);
972 subject_caption = modest_toolkit_utils_create_captioned (title_size_group, value_size_group,
973 _("mail_va_subject"), FALSE, priv->subject_box);
974 priv->attachments_caption = modest_toolkit_utils_create_captioned_with_size_type (NULL, NULL,
975 _("mail_va_attachment"),
977 priv->attachments_view,
978 #ifdef MODEST_TOOLKIT_HILDON2
979 HILDON_SIZE_AUTO_WIDTH |
980 HILDON_SIZE_AUTO_HEIGHT
985 attachments_label = modest_toolkit_utils_captioned_get_label_widget (priv->attachments_caption);
987 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
991 #ifdef MODEST_TOOLKIT_HILDON2
992 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
993 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
995 priv->send_button = gtk_button_new ();
996 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, GTK_ICON_SIZE_BUTTON);
998 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
999 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
1001 g_object_unref (title_size_group);
1002 g_object_unref (value_size_group);
1004 priv->brand_icon = gtk_image_new ();
1005 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
1006 priv->brand_label = gtk_label_new (NULL);
1007 #ifdef MODEST_TOOLKIT_HILDON2
1008 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
1010 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
1011 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
1012 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
1014 from_send_hbox = gtk_hbox_new (FALSE, 0);
1015 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
1016 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
1018 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
1019 gtk_widget_show (branding_box);
1020 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
1021 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
1023 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
1024 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1025 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
1026 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
1029 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
1030 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
1031 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
1032 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
1033 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
1034 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
1035 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
1036 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1038 init_wp_text_view_style ();
1040 priv->msg_body = modest_wp_text_view_new ();
1043 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1044 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1045 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1046 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1047 #if (GTK_MINOR_VERSION >= 10)
1048 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1049 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1051 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1052 deserialize_type, TRUE);
1054 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1056 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1058 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1060 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1062 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1064 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1066 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1067 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1068 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1070 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1071 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1072 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1074 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1075 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1077 window_box = gtk_vbox_new (FALSE, 0);
1078 gtk_container_add (GTK_CONTAINER(obj), window_box);
1080 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1085 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1087 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1089 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1090 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1091 priv->clipboard_change_handler_id))
1092 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1093 priv->clipboard_change_handler_id);
1094 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1095 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1096 priv->default_clipboard_change_handler_id))
1097 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1098 priv->default_clipboard_change_handler_id);
1100 if (priv->account_removed_handler_id &&
1101 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1102 priv->account_removed_handler_id))
1103 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1104 priv->account_removed_handler_id);
1108 modest_msg_edit_window_finalize (GObject *obj)
1110 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1112 if (priv->max_chars_banner) {
1113 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1114 priv->max_chars_banner = FALSE;
1117 /* Sanity check: shouldn't be needed, the window mgr should
1118 call this function before */
1119 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1121 if (priv->font_dialog != NULL) {
1122 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1125 if (priv->clipboard_text != NULL) {
1126 g_free (priv->clipboard_text);
1127 priv->clipboard_text = NULL;
1130 if (priv->draft_msg != NULL) {
1131 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1132 if (TNY_IS_HEADER (header)) {
1133 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1134 modest_window_mgr_unregister_header (mgr, header);
1136 g_object_unref (priv->draft_msg);
1137 priv->draft_msg = NULL;
1139 if (priv->outbox_msg != NULL) {
1140 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1141 if (TNY_IS_HEADER (header)) {
1142 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1143 modest_window_mgr_unregister_header (mgr, header);
1145 g_object_unref (priv->outbox_msg);
1146 priv->outbox_msg = NULL;
1148 if (priv->correct_scroll_idle > 0) {
1149 g_source_remove (priv->correct_scroll_idle);
1150 priv->correct_scroll_idle = 0;
1152 if (priv->scroll_drag_timeout_id > 0) {
1153 g_source_remove (priv->scroll_drag_timeout_id);
1154 priv->scroll_drag_timeout_id = 0;
1156 if (priv->clipboard_owner_idle > 0) {
1157 g_source_remove (priv->clipboard_owner_idle);
1158 priv->clipboard_owner_idle = 0;
1160 if (priv->original_account_name)
1161 g_free (priv->original_account_name);
1162 if (priv->original_mailbox)
1163 g_free (priv->original_mailbox);
1164 g_free (priv->msg_uid);
1165 g_free (priv->last_search);
1166 g_slist_free (priv->font_items_group);
1167 g_free (priv->references);
1168 g_free (priv->in_reply_to);
1169 g_object_unref (priv->attachments);
1170 g_object_unref (priv->images);
1172 /* This had to stay alive for as long as the picker that used it: */
1173 modest_pair_list_free (priv->from_field_protos);
1175 G_OBJECT_CLASS(parent_class)->finalize (obj);
1179 pixbuf_size_prepared (GdkPixbufLoader *loader,
1182 ModestMsgEditWindow *self)
1184 gint new_height, new_width;
1187 new_height = height;
1191 if (width > IMAGE_MAX_WIDTH) {
1192 new_height = height * IMAGE_MAX_WIDTH / width;
1193 new_width = IMAGE_MAX_WIDTH;
1196 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1200 pixbuf_from_stream (TnyStream *stream,
1201 const gchar *mime_type,
1202 guint64 *stream_size,
1203 ModestMsgEditWindow *self)
1205 GdkPixbufLoader *loader;
1208 GError *error = NULL;
1212 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1214 if (loader == NULL) {
1219 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1221 modest_window_show_progress (MODEST_WINDOW (self), TRUE);
1223 tny_stream_reset (TNY_STREAM (stream));
1224 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1225 unsigned char read_buffer[128];
1227 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1229 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1232 /* Allow some UI responsiveness */
1233 while (gtk_events_pending ())
1234 gtk_main_iteration ();
1236 modest_window_show_progress (MODEST_WINDOW (self), FALSE);
1238 gdk_pixbuf_loader_close (loader, &error);
1241 g_error_free (error);
1242 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1244 g_object_ref (pixbuf);
1245 g_object_unref (loader);
1250 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1251 GdkPixbuf *new_pixbuf;
1253 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1254 gdk_pixbuf_get_width (pixbuf);
1255 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1256 g_object_unref (pixbuf);
1257 pixbuf = new_pixbuf;
1261 *stream_size = size;
1267 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1269 ModestMsgEditWindowPrivate *priv;
1272 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1274 g_object_ref (self);
1275 for (iter = tny_list_create_iterator (attachments);
1276 !tny_iterator_is_done (iter);
1277 tny_iterator_next (iter)) {
1278 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1279 const gchar *cid = tny_mime_part_get_content_id (part);
1280 const gchar *mime_type = tny_mime_part_get_content_type (part);
1281 if ((cid != NULL)&&(mime_type != NULL)) {
1282 guint64 stream_size;
1283 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1284 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1287 g_object_unref (stream);
1289 if (pixbuf != NULL) {
1290 priv->images_count ++;
1291 priv->images_size += stream_size;
1292 #ifndef MODEST_HAVE_LIBWPEDITOR_PLUS
1293 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1295 g_object_unref (pixbuf);
1298 g_object_unref (part);
1300 g_object_unref (iter);
1301 g_object_unref (self);
1305 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1307 TnyMimePart *parent = NULL;
1308 const gchar *content_type = NULL;
1309 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1311 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1313 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1314 parent = g_object_ref (msg);
1315 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1316 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1319 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1320 iter = tny_list_create_iterator (parts);
1321 while (!tny_iterator_is_done (iter)) {
1323 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1324 content_type = tny_mime_part_get_content_type (part);
1325 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1329 g_object_unref (part);
1331 tny_iterator_next (iter);
1333 g_object_unref (iter);
1334 g_object_unref (parts);
1337 if (parent != NULL) {
1338 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1341 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1342 iter = tny_list_create_iterator (parts);
1343 while (!tny_iterator_is_done (iter)) {
1345 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1346 content_type = tny_mime_part_get_content_type (part);
1347 if (content_type && g_str_has_prefix (content_type, "image/")) {
1348 tny_list_prepend (priv->images, (GObject *) part);
1350 g_object_unref (part);
1351 tny_iterator_next (iter);
1353 g_object_unref (iter);
1354 g_object_unref (parts);
1355 g_object_unref (parent);
1360 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1363 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1365 for (iter = tny_list_create_iterator (attachments) ;
1366 !tny_iterator_is_done (iter);
1367 tny_iterator_next (iter)) {
1368 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1369 const gchar *cid = tny_mime_part_get_content_id (part);
1371 char *invalid = NULL;
1372 gint int_cid = strtol (cid, &invalid, 10);
1373 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1374 priv->next_cid = int_cid + 1;
1377 g_object_unref (part);
1379 g_object_unref (iter);
1383 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1386 gchar *to, *cc, *bcc, *subject;
1388 ModestMsgEditWindowPrivate *priv;
1389 ModestWindowPrivate *parent_priv;
1391 TnyHeaderFlags priority_flags;
1392 TnyFolder *msg_folder;
1393 gboolean is_html = FALSE;
1394 gboolean field_view_set;
1396 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1397 g_return_if_fail (TNY_IS_MSG (msg));
1399 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1400 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1402 header = tny_msg_get_header (msg);
1403 to = tny_header_dup_to (header);
1404 cc = tny_header_dup_cc (header);
1405 bcc = tny_header_dup_bcc (header);
1406 subject = tny_header_dup_subject (header);
1408 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1409 priority_flags = tny_header_get_priority (header);
1412 gchar *quoted_names = modest_text_utils_quote_names (to);
1413 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1414 g_free (quoted_names);
1417 field_view_set = TRUE;
1419 gchar *quoted_names = modest_text_utils_quote_names (cc);
1420 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1421 g_free (quoted_names);
1422 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1423 gtk_widget_show (priv->cc_caption);
1424 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1425 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1426 gtk_widget_hide (priv->cc_caption);
1427 field_view_set = FALSE;
1429 modest_togglable_set_active (priv->cc_button, field_view_set);
1431 field_view_set = TRUE;
1433 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1434 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1435 g_free (quoted_names);
1436 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1437 gtk_widget_show (priv->bcc_caption);
1438 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1439 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1440 gtk_widget_hide (priv->bcc_caption);
1441 field_view_set = FALSE;
1443 modest_togglable_set_active (priv->bcc_button, field_view_set);
1447 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1448 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1451 update_window_title (self);
1453 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1454 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1456 if ((body == NULL)||(body[0] == '\0')) {
1458 body = modest_text_utils_convert_to_html ("");
1461 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1462 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1465 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1468 /* Add attachments to the view */
1469 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1470 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1471 if (tny_list_get_length (priv->attachments) == 0) {
1472 gtk_widget_hide (priv->attachments_caption);
1474 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1475 gtk_widget_show_all (priv->attachments_caption);
1477 get_related_images (self, msg);
1478 update_next_cid (self, priv->attachments);
1479 update_next_cid (self, priv->images);
1480 replace_with_images (self, priv->images);
1482 if (preserve_is_rich && !is_html) {
1483 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1484 /* Get the default format required from configuration */
1485 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1486 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1489 /* Set the default focus depending on having already a To: field or not */
1490 if ((!to)||(*to == '\0')) {
1491 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1493 gtk_widget_grab_focus (priv->msg_body);
1496 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1498 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1499 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1501 modest_msg_edit_window_set_modified (self, FALSE);
1503 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1504 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1505 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1506 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1508 if (priv->msg_uid) {
1509 g_free (priv->msg_uid);
1510 priv->msg_uid = NULL;
1513 /* we should set a reference to the incoming message if it is a draft */
1514 msg_folder = tny_msg_get_folder (msg);
1516 if (modest_tny_folder_is_local_folder (msg_folder)) {
1517 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1518 if (type == TNY_FOLDER_TYPE_INVALID)
1519 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1521 if (type == TNY_FOLDER_TYPE_DRAFTS)
1522 priv->draft_msg = g_object_ref(msg);
1523 if (type == TNY_FOLDER_TYPE_OUTBOX)
1524 priv->outbox_msg = g_object_ref(msg);
1525 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1527 g_object_unref (msg_folder);
1536 #ifndef MODEST_TOOLKIT_HILDON2
1538 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1541 GList *item_children, *node;
1542 GtkWidget *bin_child;
1544 bin_child = gtk_bin_get_child (GTK_BIN(item));
1546 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1548 for (node = item_children; node != NULL; node = g_list_next (node)) {
1549 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1550 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1553 g_list_free (item_children);
1557 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1560 GList *item_children, *node;
1562 box = gtk_bin_get_child (GTK_BIN (item));
1563 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1564 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1566 for (node = item_children; node != NULL; node = g_list_next (node)) {
1567 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1568 if (GTK_IS_TOGGLE_BUTTON (node->data))
1569 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1570 else if (GTK_IS_BUTTON (node->data))
1571 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1573 g_list_free (item_children);
1578 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1580 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1581 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1582 GtkWidget *placeholder;
1583 GtkWidget *tool_item;
1588 GtkWidget *sizes_menu;
1592 #ifndef MODEST_TOOLKIT_HILDON2
1593 GSList *radio_group, *node;
1594 GtkWidget *fonts_menu;
1598 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1599 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1600 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar),
1601 #ifdef MODEST_TOOLKIT_HILDON2
1602 HILDON_ICON_SIZE_FINGER
1604 GTK_ICON_SIZE_LARGE_TOOLBAR
1607 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1609 /* Font color placeholder */
1610 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1611 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1614 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1615 #ifdef MODEST_TOOLKIT_HILDON2
1616 priv->font_color_button = modest_color_button_new ();
1618 priv->font_color_button = gtk_color_button_new ();
1620 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1621 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1622 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1623 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1624 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1625 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1626 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1627 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1629 G_CALLBACK (modest_msg_edit_window_color_button_change),
1632 /* Font size and face placeholder */
1633 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1634 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1636 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, ""));
1637 priv->size_tool_button_label = gtk_label_new (NULL);
1638 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1639 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1640 size_text, "</span>", NULL);
1641 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1642 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1644 #ifdef MODEST_TOOLKIT_HILDON2
1645 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1647 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1648 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1649 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1650 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1651 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1652 gtk_widget_set_sensitive (arrow, FALSE);
1653 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1654 sizes_menu = gtk_menu_new ();
1655 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1656 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1659 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1660 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1662 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1666 if (wp_font_size[size_index] == 12)
1667 priv->current_size_index = size_index;
1671 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1672 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1673 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1674 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1675 priv->font_size_toolitem = tool_item;
1677 #ifdef MODEST_TOOLKIT_HILDON2
1679 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, ""));
1680 priv->font_tool_button_label = gtk_label_new (NULL);
1681 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1682 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1683 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1685 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1686 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1687 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1688 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1689 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1690 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1691 gtk_widget_set_sensitive (arrow, FALSE);
1692 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1694 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1695 priv->font_tool_button_label = gtk_label_new (NULL);
1696 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1697 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1699 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1700 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1701 gtk_widget_show (priv->font_tool_button_label);
1702 gtk_widget_show (GTK_WIDGET (tool_item));
1703 fonts_menu = gtk_menu_new ();
1706 #ifdef MODEST_TOOLKIT_HILDON2
1707 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1708 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1711 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1713 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1714 0, wp_get_font_name (font_index),
1717 if (font_index == DEFAULT_FONT)
1718 priv->current_face_index = font_index;
1720 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1721 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1722 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1723 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1724 priv->font_face_toolitem = tool_item;
1726 priv->font_items_group = NULL;
1728 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1729 GtkWidget *font_menu_item;
1730 GtkWidget *child_label;
1732 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1733 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1734 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1735 wp_get_font_name (font_index), "</span>", NULL);
1736 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1739 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1740 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1741 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1742 gtk_widget_show (font_menu_item);
1744 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1747 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1748 GtkWidget *item = (GtkWidget *) node->data;
1749 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1752 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1753 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1754 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1755 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1756 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1757 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1758 priv->font_face_toolitem = tool_item;
1761 /* Set expand and homogeneous for remaining items */
1762 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1763 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1764 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1765 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1766 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1767 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1769 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1770 will not show the tool items added to the placeholders) */
1771 gtk_widget_show_all (parent_priv->toolbar);
1773 /* Set the no show all *after* showing all items. We do not
1774 want the toolbar to be shown with a show all because it
1775 could go agains the gconf setting regarding showing or not
1776 the toolbar of the editor window */
1777 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1783 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1786 ModestWindowPrivate *parent_priv;
1787 ModestMsgEditWindowPrivate *priv;
1788 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1789 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1790 ModestWindowMgr *mgr = NULL;
1792 g_return_val_if_fail (msg, NULL);
1793 g_return_val_if_fail (account_name, NULL);
1795 mgr = modest_runtime_get_window_mgr ();
1797 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1799 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1800 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1802 /* Menubar. Update the state of some toggles */
1803 priv->from_field_protos = get_transports ();
1804 priv->original_mailbox = NULL;
1805 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1806 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1807 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1808 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1809 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1810 priv->original_mailbox = g_strdup (mailbox);
1811 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1812 /* We set the first mailbox as the active mailbox */
1813 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1814 if (priv->original_mailbox != NULL)
1815 modest_selector_set_active_id (priv->from_field,
1816 (gpointer) priv->original_mailbox);
1818 modest_selector_set_active_id (priv->from_field,
1819 (gpointer) account_name);
1821 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1823 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1824 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1825 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1826 #ifdef HILDON_TOOLKIT_HILDON2
1827 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1829 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1830 hildon_touch_selector_get_current_text
1831 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1834 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1835 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1838 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1840 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1842 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1843 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1845 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1847 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1848 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1849 /* Add common dimming rules */
1850 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1851 modest_msg_edit_window_toolbar_dimming_entries,
1852 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1853 MODEST_WINDOW (obj));
1854 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_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_size_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->font_face_toolitem,
1861 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1862 MODEST_WINDOW (obj));
1863 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1864 G_CALLBACK (modest_ui_dimming_rules_on_send),
1865 MODEST_WINDOW (obj));
1866 /* Insert dimming rules group for this window */
1867 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1868 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1870 /* Setup app menu */
1871 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1873 /* Checks the dimming rules */
1874 g_object_unref (toolbar_rules_group);
1875 g_object_unref (clipboard_rules_group);
1876 gtk_widget_hide (priv->priority_icon);
1877 gtk_widget_queue_resize (priv->subject_box);
1878 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1880 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1882 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1883 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1884 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1885 priv->update_caption_visibility = TRUE;
1887 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1889 /* Track account-removed signal, this window should be closed
1890 in the case we're creating a mail associated to the account
1892 priv->account_removed_handler_id =
1893 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1895 G_CALLBACK(on_account_removed),
1898 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1900 return (ModestWindow*) obj;
1904 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1906 GString **string_buffer = (GString **) user_data;
1908 *string_buffer = g_string_append (*string_buffer, buffer);
1914 * @result: A new string which should be freed with g_free().
1917 get_formatted_data (ModestMsgEditWindow *edit_window)
1919 ModestMsgEditWindowPrivate *priv;
1920 GString *string_buffer = g_string_new ("");
1922 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1924 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1926 modest_text_utils_hyperlinkify (string_buffer);
1928 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1930 return g_string_free (string_buffer, FALSE);
1935 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1938 const gchar *account_name;
1939 ModestMsgEditWindowPrivate *priv;
1940 TnyIterator *att_iter;
1941 const gchar *picker_active_id;
1943 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1945 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1947 picker_active_id = modest_selector_get_active_id (priv->from_field);
1948 g_return_val_if_fail (picker_active_id, NULL);
1949 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1951 /* don't free these (except from) */
1952 data = g_slice_new0 (MsgData);
1953 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1954 data->account_name = g_strdup (account_name);
1955 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1956 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1957 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1958 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1959 data->references = g_strdup (priv->references);
1960 data->in_reply_to = g_strdup (priv->in_reply_to);
1961 if (priv->draft_msg) {
1962 data->draft_msg = g_object_ref (priv->draft_msg);
1963 } else if (priv->outbox_msg) {
1964 data->draft_msg = g_object_ref (priv->outbox_msg);
1966 data->draft_msg = NULL;
1969 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1971 gtk_text_buffer_get_bounds (buf, &b, &e);
1972 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1974 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1975 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1977 data->html_body = NULL;
1979 /* deep-copy the data */
1980 att_iter = tny_list_create_iterator (priv->attachments);
1981 data->attachments = NULL;
1982 while (!tny_iterator_is_done (att_iter)) {
1983 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1984 if (!(TNY_IS_MIME_PART(part))) {
1985 g_warning ("strange data in attachment list");
1986 g_object_unref (part);
1987 tny_iterator_next (att_iter);
1990 data->attachments = g_list_append (data->attachments,
1992 tny_iterator_next (att_iter);
1994 g_object_unref (att_iter);
1996 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1997 att_iter = tny_list_create_iterator (priv->images);
1998 data->images = NULL;
1999 while (!tny_iterator_is_done (att_iter)) {
2000 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
2002 if (!(TNY_IS_MIME_PART(part))) {
2003 g_warning ("strange data in attachment list");
2004 g_object_unref (part);
2005 tny_iterator_next (att_iter);
2008 cid = tny_mime_part_get_content_id (part);
2010 gchar *image_tag_id;
2011 GtkTextTag *image_tag;
2013 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
2014 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
2015 g_free (image_tag_id);
2017 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
2019 ((gtk_text_iter_has_tag (&iter, image_tag))||
2020 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
2021 data->images = g_list_append (data->images,
2022 g_object_ref (part));
2024 g_object_unref (part);
2025 tny_iterator_next (att_iter);
2027 g_object_unref (att_iter);
2029 data->priority_flags = priv->priority_flags;
2036 unref_gobject (GObject *obj, gpointer data)
2038 if (!G_IS_OBJECT(obj))
2040 g_object_unref (obj);
2044 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
2047 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
2055 g_free (data->from);
2056 g_free (data->subject);
2057 g_free (data->plain_body);
2058 g_free (data->html_body);
2059 g_free (data->account_name);
2060 g_free (data->references);
2061 g_free (data->in_reply_to);
2063 if (data->draft_msg != NULL) {
2064 g_object_unref (data->draft_msg);
2065 data->draft_msg = NULL;
2068 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
2069 g_list_free (data->attachments);
2070 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
2071 g_list_free (data->images);
2073 g_slice_free (MsgData, data);
2077 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
2079 guint64 *parts_size)
2081 ModestMsgEditWindowPrivate *priv;
2083 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2085 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
2087 /* TODO: add images */
2088 *parts_size += priv->images_size;
2089 *parts_count += priv->images_count;
2094 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
2097 ModestMsgEditWindowPrivate *priv = NULL;
2098 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
2100 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2102 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2104 return MODEST_MSG_EDIT_FORMAT_HTML;
2106 return MODEST_MSG_EDIT_FORMAT_TEXT;
2110 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
2111 ModestMsgEditFormat format)
2113 ModestMsgEditWindowPrivate *priv;
2114 ModestWindowPrivate *parent_priv;
2116 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2117 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2118 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2121 case MODEST_MSG_EDIT_FORMAT_HTML:
2122 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2123 update_signature (self, priv->last_from_account, priv->last_from_account);
2124 if (parent_priv->toolbar)
2125 on_show_toolbar_button_toggled (priv->show_toolbar_button,
2126 MODEST_MSG_EDIT_WINDOW (self));
2128 case MODEST_MSG_EDIT_FORMAT_TEXT:
2129 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2130 if (parent_priv->toolbar)
2131 on_show_toolbar_button_toggled (priv->show_toolbar_button,
2132 MODEST_MSG_EDIT_WINDOW (self));
2135 g_return_if_reached ();
2139 ModestMsgEditFormatState *
2140 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2142 ModestMsgEditFormatState *format_state = NULL;
2143 ModestMsgEditWindowPrivate *priv;
2144 WPTextBufferFormat *buffer_format;
2146 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2148 buffer_format = g_new0 (WPTextBufferFormat, 1);
2149 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2151 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2153 format_state = g_new0 (ModestMsgEditFormatState, 1);
2154 format_state->bold = buffer_format->bold&0x1;
2155 format_state->italics = buffer_format->italic&0x1;
2156 format_state->bullet = buffer_format->bullet&0x1;
2157 format_state->color = buffer_format->color;
2158 format_state->font_size = buffer_format->font_size;
2159 format_state->font_family = wp_get_font_name (buffer_format->font);
2160 format_state->justification = buffer_format->justification;
2161 g_free (buffer_format);
2163 return format_state;
2168 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2169 const ModestMsgEditFormatState *format_state)
2171 ModestMsgEditWindowPrivate *priv;
2172 WPTextBufferFormat *buffer_format;
2173 WPTextBufferFormat *current_format;
2175 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2176 g_return_if_fail (format_state != NULL);
2178 buffer_format = g_new0 (WPTextBufferFormat, 1);
2179 current_format = g_new0 (WPTextBufferFormat, 1);
2181 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2182 gtk_widget_grab_focus (priv->msg_body);
2183 buffer_format->bold = (format_state->bold != FALSE);
2184 buffer_format->italic = (format_state->italics != FALSE);
2185 buffer_format->color = format_state->color;
2186 buffer_format->font_size = format_state->font_size;
2187 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2188 buffer_format->justification = format_state->justification;
2189 buffer_format->bullet = format_state->bullet;
2191 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2193 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2194 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2195 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2196 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2197 buffer_format->cs.font = (buffer_format->font != current_format->font);
2198 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2199 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2201 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2202 if (buffer_format->cs.bold) {
2203 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2204 GINT_TO_POINTER (buffer_format->bold&0x1));
2206 if (buffer_format->cs.italic) {
2207 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2208 GINT_TO_POINTER (buffer_format->italic&0x1));
2210 if (buffer_format->cs.color) {
2211 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2212 GINT_TO_POINTER (&(buffer_format->color)));
2214 if (buffer_format->cs.font_size) {
2215 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2216 GINT_TO_POINTER (buffer_format->font_size));
2218 if (buffer_format->cs.justification) {
2219 switch (buffer_format->justification) {
2220 case GTK_JUSTIFY_LEFT:
2221 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2222 GINT_TO_POINTER(TRUE));
2224 case GTK_JUSTIFY_CENTER:
2225 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2226 GINT_TO_POINTER(TRUE));
2228 case GTK_JUSTIFY_RIGHT:
2229 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2230 GINT_TO_POINTER(TRUE));
2237 if (buffer_format->cs.font) {
2238 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2239 GINT_TO_POINTER (buffer_format->font));
2241 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2242 if (buffer_format->cs.bullet) {
2243 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2244 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2246 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2248 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2250 g_free (buffer_format);
2251 g_free (current_format);
2253 /* Check dimming rules */
2254 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2255 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2259 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2261 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2263 ModestWindowPrivate *parent_priv;
2264 ModestMsgEditWindowPrivate *priv;
2266 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2267 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2269 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2270 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2271 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2272 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2274 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2275 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2276 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2279 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2281 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2282 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2284 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2285 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2287 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2288 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2291 switch (buffer_format->justification)
2293 case GTK_JUSTIFY_LEFT:
2294 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2296 case GTK_JUSTIFY_CENTER:
2297 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2299 case GTK_JUSTIFY_RIGHT:
2300 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2307 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2309 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2310 G_CALLBACK (modest_msg_edit_window_color_button_change),
2312 #ifdef MODEST_TOOLKIT_HILDON2
2313 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2315 gtk_color_button_set_color (GTK_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2317 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2318 G_CALLBACK (modest_msg_edit_window_color_button_change),
2321 if (priv->current_size_index != buffer_format->font_size) {
2325 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2326 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2330 priv->current_size_index = buffer_format->font_size;
2332 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2333 markup = g_strconcat ("<span font_family='Sans'>",
2334 size_text, "</span>", NULL);
2336 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2340 gtk_tree_path_free (path);
2343 #ifdef MODEST_TOOLKIT_HILDON2
2344 if (priv->current_face_index != buffer_format->font) {
2348 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2349 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2353 priv->current_face_index = buffer_format->font;
2354 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2355 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2356 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2363 GtkWidget *new_font_menuitem;
2364 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
2365 buffer_format->font))->data);
2366 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
2370 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
2371 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2372 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2374 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
2375 G_CALLBACK (modest_msg_edit_window_font_change),
2377 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
2378 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
2379 G_CALLBACK (modest_msg_edit_window_font_change),
2384 g_free (buffer_format);
2390 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2392 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2393 ModestMsgEditWindowPrivate *priv;
2394 GtkWidget *dialog = NULL;
2396 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2397 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2399 #ifdef MODEST_TOOLKIT_HILDON2
2400 dialog = hildon_color_chooser_new ();
2401 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2402 g_free (buffer_format);
2404 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2406 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2407 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2410 gtk_widget_destroy (dialog);
2412 dialog = gtk_color_selection_dialog_new (NULL);
2413 GtkWidget *selection;
2415 g_object_get (G_OBJECT (dialog), "color_selection", &selection, NULL);
2416 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2417 gtk_color_selection_set_previous_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2418 g_free (buffer_format);
2420 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2422 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION(selection), &col);
2423 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2426 gtk_widget_destroy (dialog);
2433 create_stream_for_uri (const gchar* uri)
2438 TnyStream *result = NULL;
2440 GnomeVFSHandle *handle = NULL;
2441 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2442 if (test == GNOME_VFS_OK) {
2443 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2444 /* Streams over OBEX (Bluetooth) are not seekable but
2445 * we expect them to be (we might need to read them
2446 * several times). So if this is a Bluetooth URI just
2447 * read the whole file into memory (this is not a fast
2448 * protocol so we can assume that these files are not
2449 * going to be very big) */
2450 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2451 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2452 TnyStream *memstream = tny_camel_mem_stream_new ();
2453 tny_stream_write_to_stream (vfssstream, memstream);
2454 g_object_unref (vfssstream);
2457 result = vfssstream;
2465 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2468 ModestMsgEditWindowPrivate *priv;
2469 GtkWidget *dialog = NULL;
2471 GSList *uris = NULL;
2472 GSList *uri_node = NULL;
2474 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2476 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2477 _("mcen_ia_select_inline_image_title"),
2478 (GtkWindow *) window,
2479 GTK_FILE_CHOOSER_ACTION_OPEN);
2480 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2482 #ifdef MODEST_TOOLKIT_HILDON2
2483 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2486 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2487 GTK_WINDOW (dialog), GTK_WINDOW (window));
2489 response = gtk_dialog_run (GTK_DIALOG (dialog));
2491 case GTK_RESPONSE_OK:
2493 gchar *current_folder;
2494 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2495 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2496 if (current_folder && current_folder != '\0') {
2498 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2499 current_folder, &err);
2501 g_debug ("Error storing latest used folder: %s", err->message);
2505 g_free (current_folder);
2511 gtk_widget_destroy (dialog);
2513 g_object_ref (window);
2514 /* The operation could take some time so allow the dialog to be closed */
2515 while (gtk_events_pending ())
2516 gtk_main_iteration ();
2518 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2520 GnomeVFSHandle *handle = NULL;
2521 GnomeVFSResult result;
2522 GtkTextIter position;
2523 GtkTextMark *insert_mark;
2525 uri = (const gchar *) uri_node->data;
2526 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2527 if (result == GNOME_VFS_OK) {
2529 GnomeVFSFileInfo *info;
2530 gchar *filename, *basename, *escaped_filename;
2531 TnyMimePart *mime_part;
2533 const gchar *mime_type = NULL;
2534 GnomeVFSURI *vfs_uri;
2535 guint64 stream_size;
2537 gnome_vfs_close (handle);
2538 vfs_uri = gnome_vfs_uri_new (uri);
2540 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2541 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2542 g_free (escaped_filename);
2543 gnome_vfs_uri_unref (vfs_uri);
2544 info = gnome_vfs_file_info_new ();
2546 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2547 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2549 mime_type = gnome_vfs_file_info_get_mime_type (info);
2551 mime_part = tny_platform_factory_new_mime_part
2552 (modest_runtime_get_platform_factory ());
2554 TnyStream *stream = create_stream_for_uri (uri);
2556 if (stream == NULL) {
2558 modest_platform_information_banner (NULL, NULL,
2559 _FM_OPENING_NOT_ALLOWED);
2561 g_object_unref (mime_part);
2562 gnome_vfs_file_info_unref (info);
2566 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2568 content_id = g_strdup_printf ("%d", priv->next_cid);
2569 tny_mime_part_set_content_id (mime_part, content_id);
2570 g_free (content_id);
2573 basename = g_path_get_basename (filename);
2574 tny_mime_part_set_filename (mime_part, basename);
2577 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2579 if (pixbuf != NULL) {
2580 priv->images_size += stream_size;
2581 priv->images_count ++;
2582 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2583 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2584 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2585 tny_mime_part_get_content_id (mime_part), pixbuf);
2586 g_object_unref (pixbuf);
2588 tny_list_prepend (priv->images, (GObject *) mime_part);
2589 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2591 modest_platform_information_banner (NULL, NULL,
2592 _("mail_ib_file_operation_failed"));
2596 g_object_unref (mime_part);
2597 gnome_vfs_file_info_unref (info);
2601 g_object_unref (window);
2605 on_attach_file_response (GtkDialog *dialog,
2609 GSList *uris = NULL;
2611 GnomeVFSFileSize total_size, allowed_size;
2612 ModestMsgEditWindow *window;
2613 ModestMsgEditWindowPrivate *priv;
2618 case GTK_RESPONSE_OK:
2620 gchar *current_folder;
2622 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2623 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2624 if (current_folder && current_folder != '\0') {
2626 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2627 current_folder, &err);
2629 g_debug ("Error storing latest used folder: %s", err->message);
2633 g_free (current_folder);
2640 window = MODEST_MSG_EDIT_WINDOW (user_data);
2641 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2643 /* allowed size is the maximum size - what's already there */
2644 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2645 &att_num, &att_size);
2646 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2649 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2651 const gchar *uri = (const gchar *) uri_node->data;
2654 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2656 if (total_size > allowed_size) {
2657 g_debug ("%s: total size: %u",
2658 __FUNCTION__, (unsigned int)total_size);
2661 allowed_size -= total_size;
2663 g_slist_foreach (uris, (GFunc) g_free, NULL);
2664 g_slist_free (uris);
2666 gtk_widget_destroy (GTK_WIDGET (dialog));
2670 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2672 GtkWidget *dialog = NULL;
2673 ModestMsgEditWindowPrivate *priv;
2676 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2678 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2680 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2683 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2684 _("mcen_ia_select_attachment_title"),
2685 (GtkWindow *) window,
2686 GTK_FILE_CHOOSER_ACTION_OPEN);
2687 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2688 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2689 if (conf_folder && conf_folder[0] != '\0') {
2690 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2693 /* Set the default folder to documents folder */
2694 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2695 #ifdef MODEST_TOOLKIT_HILDON2
2698 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2699 ".documents", NULL);
2702 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2703 g_free (docs_folder);
2705 g_free (conf_folder);
2706 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2707 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2708 GTK_WINDOW (dialog), GTK_WINDOW (window));
2710 /* Connect to response & show */
2711 g_signal_connect (dialog, "response",
2712 G_CALLBACK (on_attach_file_response), window);
2713 gtk_widget_show (dialog);
2718 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2720 GnomeVFSFileSize allowed_size)
2723 GnomeVFSHandle *handle = NULL;
2724 ModestMsgEditWindowPrivate *priv;
2725 GnomeVFSResult result;
2726 GnomeVFSFileSize size = 0;
2727 g_return_val_if_fail (window, 0);
2728 g_return_val_if_fail (uri, 0);
2730 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2732 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2733 if (result == GNOME_VFS_OK) {
2734 TnyMimePart *mime_part;
2736 const gchar *mime_type = NULL;
2738 gchar *escaped_filename;
2741 GnomeVFSFileInfo *info;
2742 GnomeVFSURI *vfs_uri;
2744 gnome_vfs_close (handle);
2745 vfs_uri = gnome_vfs_uri_new (uri);
2748 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2749 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2750 g_free (escaped_filename);
2751 gnome_vfs_uri_unref (vfs_uri);
2753 info = gnome_vfs_file_info_new ();
2755 if (gnome_vfs_get_file_info (uri,
2757 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2759 mime_type = gnome_vfs_file_info_get_mime_type (info);
2760 mime_part = tny_platform_factory_new_mime_part
2761 (modest_runtime_get_platform_factory ());
2763 /* try to get the attachment's size; this may fail for weird
2764 * file systems, like obex, upnp... */
2765 if (allowed_size != 0 &&
2766 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2768 if (size > allowed_size) {
2769 modest_platform_information_banner (NULL, NULL,
2770 _("mail_ib_error_attachment_size"));
2775 g_debug ("%s: could not get attachment size", __FUNCTION__);
2777 stream = create_stream_for_uri (uri);
2779 if (stream == NULL) {
2781 modest_platform_information_banner (NULL, NULL, _FM_OPENING_NOT_ALLOWED);
2783 g_object_unref (mime_part);
2785 gnome_vfs_file_info_unref (info);
2789 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2790 g_object_unref (stream);
2792 content_id = g_strdup_printf ("%d", priv->next_cid);
2793 tny_mime_part_set_content_id (mime_part, content_id);
2794 g_free (content_id);
2797 basename = g_path_get_basename (filename);
2798 tny_mime_part_set_filename (mime_part, basename);
2801 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2802 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2804 info->size == 0, info->size);
2805 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2806 gtk_widget_show_all (priv->attachments_caption);
2807 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2809 g_object_unref (mime_part);
2810 gnome_vfs_file_info_unref (info);
2817 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2820 ModestMsgEditWindowPrivate *priv;
2823 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2824 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2826 if (att_list == NULL) {
2827 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2828 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2829 g_object_unref (att_list);
2833 g_object_ref (att_list);
2836 if (tny_list_get_length (att_list) == 0) {
2837 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2839 gboolean dialog_response;
2840 gchar *message = NULL;
2841 gchar *filename = NULL;
2843 if (tny_list_get_length (att_list) == 1) {
2845 iter = tny_list_create_iterator (att_list);
2846 part = (TnyMimePart *) tny_iterator_get_current (iter);
2847 g_object_unref (iter);
2848 if (TNY_IS_MSG (part)) {
2849 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2851 filename = tny_header_dup_subject (header);
2852 g_object_unref (header);
2854 if (filename == NULL) {
2855 filename = g_strdup (_("mail_va_no_subject"));
2858 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2860 g_object_unref (part);
2862 filename = g_strdup ("");
2864 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2865 "emev_nc_delete_attachments",
2866 tny_list_get_length (att_list)), filename);
2869 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2873 if (dialog_response != GTK_RESPONSE_OK) {
2874 g_object_unref (att_list);
2878 for (iter = tny_list_create_iterator (att_list);
2879 !tny_iterator_is_done (iter);
2880 tny_iterator_next (iter)) {
2881 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2882 const gchar *att_id;
2883 tny_list_remove (priv->attachments, (GObject *) mime_part);
2885 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2887 if (tny_list_get_length (priv->attachments) == 0)
2888 gtk_widget_hide (priv->attachments_caption);
2889 att_id = tny_mime_part_get_content_id (mime_part);
2891 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2893 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2894 g_object_unref (mime_part);
2896 g_object_unref (iter);
2899 g_object_unref (att_list);
2901 /* if the last attachment has been removed, focus the Subject: field */
2902 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2903 gtk_widget_grab_focus (priv->subject_field);
2907 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2910 ModestMsgEditWindowPrivate *priv;
2913 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2915 gtk_color_button_get_color (GTK_COLOR_BUTTON(priv->font_color_button), &new_color);
2917 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2919 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2922 #ifndef MODEST_TOOLKIT_HILDON2
2924 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2927 ModestMsgEditWindowPrivate *priv;
2928 gint new_font_index;
2929 ModestMsgEditWindow *window;
2932 window = MODEST_MSG_EDIT_WINDOW (userdata);
2933 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2934 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2936 if (gtk_check_menu_item_get_active (menu_item)) {
2939 label = gtk_bin_get_child (GTK_BIN (menu_item));
2941 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2943 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2944 GINT_TO_POINTER(new_font_index)))
2945 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2947 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2948 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2949 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2956 font_size_clicked (GtkToolButton *button,
2957 ModestMsgEditWindow *window)
2959 #ifdef MODEST_TOOLKIT_HILDON2
2960 ModestMsgEditWindowPrivate *priv;
2961 GtkWidget *selector, *dialog;
2963 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2965 selector = hildon_touch_selector_new ();
2966 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2967 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2969 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2970 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2971 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2973 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2977 WPTextBufferFormat format;
2979 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2981 memset (&format, 0, sizeof (format));
2982 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2984 format.cs.font_size = TRUE;
2985 format.cs.text_position = TRUE;
2986 format.cs.font = TRUE;
2987 format.font_size = new_index;
2988 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2990 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2991 GINT_TO_POINTER (new_index)))
2992 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2994 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2995 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2996 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2997 size_text, "</span>", NULL);
2999 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
3003 gtk_widget_destroy (dialog);
3005 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
3009 #ifdef MODEST_TOOLKIT_HILDON2
3011 font_face_clicked (GtkToolButton *button,
3012 ModestMsgEditWindow *window)
3014 ModestMsgEditWindowPrivate *priv;
3015 GtkWidget *selector, *dialog;
3016 GtkCellRenderer *renderer;
3018 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3020 selector = hildon_touch_selector_new ();
3021 renderer = gtk_cell_renderer_text_new ();
3022 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
3023 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
3024 renderer, "family", 0, "text", 0, NULL);
3025 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
3027 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
3028 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
3029 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
3031 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
3032 gint new_font_index;
3036 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
3037 path = gtk_tree_path_new_from_indices (new_font_index, -1);
3038 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
3042 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
3044 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
3045 GINT_TO_POINTER(new_font_index)))
3046 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
3048 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
3049 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
3051 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
3055 gtk_tree_path_free (path);
3058 gtk_widget_destroy (dialog);
3060 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
3065 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
3068 ModestMsgEditWindowPrivate *priv = NULL;
3069 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3071 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3072 if (!priv->update_caption_visibility)
3075 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
3077 gtk_widget_show (priv->cc_caption);
3079 gtk_widget_hide (priv->cc_caption);
3081 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
3085 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
3088 ModestMsgEditWindowPrivate *priv = NULL;
3089 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3091 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3092 if (!priv->update_caption_visibility)
3095 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
3097 gtk_widget_show (priv->bcc_caption);
3099 gtk_widget_hide (priv->bcc_caption);
3101 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
3105 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
3106 ModestRecptEditor *editor)
3108 ModestMsgEditWindowPrivate *priv;
3110 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3111 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
3113 /* we check for low-mem; in that case, show a warning, and don't allow
3114 * for the addressbook
3116 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3119 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3121 if (editor == NULL) {
3122 GtkWidget *view_focus, *parent;
3123 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
3125 /* This code should be kept in sync with ModestRecptEditor. The
3126 textview inside the recpt editor is the one that really gets the
3127 focus. As it's inside a scrolled window, and this one inside the
3128 hbox recpt editor inherits from, we'll need to go up in the
3129 hierarchy to know if the text view is part of the recpt editor
3130 or if it's a different text entry */
3131 parent = gtk_widget_get_parent (view_focus);
3132 if (parent && MODEST_IS_RECPT_EDITOR (parent))
3133 editor = MODEST_RECPT_EDITOR (parent);
3136 editor = MODEST_RECPT_EDITOR (priv->to_field);
3139 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
3143 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
3145 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3147 modest_msg_edit_window_open_addressbook (window, NULL);
3151 modest_msg_edit_window_show_toolbar (ModestWindow *self,
3152 gboolean show_toolbar)
3154 ModestWindowPrivate *parent_priv;
3155 ModestMsgEditWindowPrivate *priv;
3157 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
3158 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3159 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
3161 /* We can not just use the code of
3162 modest_msg_edit_window_setup_toolbar because it has a
3163 mixture of both initialization and creation code. */
3165 gint current_format;
3166 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3167 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3168 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3169 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3171 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
3174 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3176 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, show_toolbar, NULL);
3177 if (modest_togglable_get_active (priv->show_toolbar_button) != show_toolbar) {
3178 modest_togglable_set_active (priv->show_toolbar_button, show_toolbar);
3183 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
3184 TnyHeaderFlags priority_flags)
3186 ModestMsgEditWindowPrivate *priv;
3187 ModestWindowPrivate *parent_priv;
3189 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3191 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3192 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3194 if (priv->priority_flags != priority_flags) {
3195 GtkAction *priority_action = NULL;
3197 priv->priority_flags = priority_flags;
3199 switch (priority_flags) {
3200 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3201 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3202 MODEST_HEADER_ICON_HIGH,
3203 #ifdef MODEST_TOOLKIT_HILDON2
3204 HILDON_ICON_SIZE_SMALL
3206 GTK_ICON_SIZE_BUTTON
3209 gtk_widget_show (priv->priority_icon);
3210 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3211 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3213 case TNY_HEADER_FLAG_LOW_PRIORITY:
3214 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3215 MODEST_HEADER_ICON_LOW,
3216 #ifdef MODEST_TOOLKIT_HILDON2
3217 HILDON_ICON_SIZE_SMALL
3219 GTK_ICON_SIZE_BUTTON
3222 gtk_widget_show (priv->priority_icon);
3223 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3224 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3227 gtk_widget_hide (priv->priority_icon);
3228 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3229 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3232 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3233 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3235 gtk_widget_queue_resize (priv->subject_box);
3239 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3242 ModestMsgEditWindowPrivate *priv;
3243 ModestWindowPrivate *parent_priv;
3244 gint current_format;
3246 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3248 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3249 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3251 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3252 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3254 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3256 if (current_format != file_format) {
3257 switch (file_format) {
3258 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3259 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3260 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3261 update_signature (window, priv->last_from_account, priv->last_from_account);
3262 if (parent_priv->toolbar)
3263 on_show_toolbar_button_toggled (priv->show_toolbar_button,
3264 MODEST_MSG_EDIT_WINDOW (window));
3266 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3269 response = modest_platform_run_confirmation_dialog (NULL, _("emev_nc_formatting_lost"));
3270 if (response == GTK_RESPONSE_OK) {
3271 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3272 if (parent_priv->toolbar)
3273 on_show_toolbar_button_toggled (priv->show_toolbar_button,
3274 MODEST_MSG_EDIT_WINDOW (window));
3276 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3277 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3282 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3283 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3284 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3289 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3291 #ifdef MODEST_TOOLKIT_HILDON2
3293 ModestMsgEditWindowPrivate *priv;
3294 WPTextBufferFormat oldfmt, fmt;
3295 gint old_position = 0;
3299 GdkColor *color = NULL;
3300 gboolean bold, bold_set, italic, italic_set;
3301 gboolean underline, underline_set;
3302 gboolean strikethrough, strikethrough_set;
3303 gboolean position_set;
3304 gboolean font_size_set, font_set, color_set;
3307 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3308 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3310 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3311 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3312 GTK_WINDOW(dialog), GTK_WINDOW (window));
3314 /* First we get the currently selected font information */
3315 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3317 switch (oldfmt.text_position) {
3318 case TEXT_POSITION_NORMAL:
3321 case TEXT_POSITION_SUPERSCRIPT:
3329 g_object_set (G_OBJECT (dialog),
3330 "bold", oldfmt.bold != FALSE,
3331 "bold-set", !oldfmt.cs.bold,
3332 "underline", oldfmt.underline != FALSE,
3333 "underline-set", !oldfmt.cs.underline,
3334 "italic", oldfmt.italic != FALSE,
3335 "italic-set", !oldfmt.cs.italic,
3336 "strikethrough", oldfmt.strikethrough != FALSE,
3337 "strikethrough-set", !oldfmt.cs.strikethrough,
3338 "color", &oldfmt.color,
3339 "color-set", !oldfmt.cs.color,
3340 "size", wp_font_size[oldfmt.font_size],
3341 "size-set", !oldfmt.cs.font_size,
3342 "position", old_position,
3343 "position-set", !oldfmt.cs.text_position,
3344 "family", wp_get_font_name (oldfmt.font),
3345 "family-set", !oldfmt.cs.font,
3348 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3349 GTK_WINDOW (dialog), GTK_WINDOW (window));
3350 gtk_widget_show_all (dialog);
3351 priv->font_dialog = dialog;
3352 response = gtk_dialog_run (GTK_DIALOG (dialog));
3353 priv->font_dialog = NULL;
3354 if (response == GTK_RESPONSE_OK) {
3356 g_object_get( dialog,
3358 "bold-set", &bold_set,
3359 "underline", &underline,
3360 "underline-set", &underline_set,
3362 "italic-set", &italic_set,
3363 "strikethrough", &strikethrough,
3364 "strikethrough-set", &strikethrough_set,
3366 "color-set", &color_set,
3368 "size-set", &font_size_set,
3369 "family", &font_name,
3370 "family-set", &font_set,
3371 "position", &position,
3372 "position-set", &position_set,
3377 if (response == GTK_RESPONSE_OK) {
3378 memset(&fmt, 0, sizeof(fmt));
3384 fmt.italic = italic;
3385 fmt.cs.italic = TRUE;
3387 if (underline_set) {
3388 fmt.underline = underline;
3389 fmt.cs.underline = TRUE;
3391 if (strikethrough_set) {
3392 fmt.strikethrough = strikethrough;
3393 fmt.cs.strikethrough = TRUE;
3398 ? TEXT_POSITION_NORMAL
3399 : ( ( position == 1 )
3400 ? TEXT_POSITION_SUPERSCRIPT
3401 : TEXT_POSITION_SUBSCRIPT );
3402 fmt.cs.text_position = TRUE;
3403 fmt.font_size = oldfmt.font_size;
3407 fmt.cs.color = TRUE;
3410 fmt.font = wp_get_font_index(font_name,
3415 if (font_size_set) {
3416 fmt.cs.font_size = TRUE;
3417 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3419 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3420 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3422 gtk_widget_destroy (dialog);
3424 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3429 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3431 ModestMsgEditWindowPrivate *priv;
3432 ModestWindowPrivate *parent_priv;
3433 gboolean was_rich_text, is_rich_text;
3435 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3436 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3437 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3439 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3441 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3443 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3445 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3446 on_show_toolbar_button_toggled (priv->show_toolbar_button,
3447 MODEST_MSG_EDIT_WINDOW (window));
3450 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3451 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3455 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3457 ModestMsgEditWindowPrivate *priv;
3459 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3460 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3462 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3464 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3465 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3470 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3472 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3474 priv->can_undo = can_undo;
3478 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3480 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3482 priv->can_redo = can_redo;
3486 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3488 ModestMsgEditWindowPrivate *priv;
3489 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3490 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3492 return priv->can_undo;
3496 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3498 ModestMsgEditWindowPrivate *priv;
3499 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3500 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3502 return priv->can_redo;
3507 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3510 GtkTextIter match_start, match_end;
3512 if (image_id == NULL)
3515 gtk_text_buffer_get_start_iter (buffer, &iter);
3517 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3518 GSList *tags = gtk_text_iter_get_tags (&match_start);
3520 for (node = tags; node != NULL; node = g_slist_next (node)) {
3521 GtkTextTag *tag = (GtkTextTag *) node->data;
3522 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3523 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3524 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3526 offset = gtk_text_iter_get_offset (&match_start);
3527 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3528 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3532 gtk_text_iter_forward_char (&iter);
3537 message_is_empty (ModestMsgEditWindow *window)
3539 ModestMsgEditWindowPrivate *priv = NULL;
3541 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3542 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3544 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3545 * so we can ignore markup.
3547 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3550 count = gtk_text_buffer_get_char_count (buf);
3556 msg_body_focus (GtkWidget *focus,
3557 GdkEventFocus *event,
3561 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3562 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3563 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3568 recpt_field_changed (GtkTextBuffer *buffer,
3569 ModestMsgEditWindow *editor)
3571 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3572 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3576 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3578 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3579 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3583 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3586 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3587 GtkTextBuffer *buffer;
3589 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3590 gtk_text_buffer_set_modified (buffer, modified);
3591 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3592 gtk_text_buffer_set_modified (buffer, modified);
3593 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3594 gtk_text_buffer_set_modified (buffer, modified);
3595 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3599 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3601 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3602 const char *account_name;
3603 GtkTextBuffer *buffer;
3605 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3606 if (gtk_text_buffer_get_modified (buffer))
3608 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3609 if (gtk_text_buffer_get_modified (buffer))
3611 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3612 if (gtk_text_buffer_get_modified (buffer))
3614 if (gtk_text_buffer_get_modified (priv->text_buffer))
3617 account_name = modest_selector_get_active_id (priv->from_field);
3618 if (priv->original_mailbox) {
3619 if (!account_name || strcmp (account_name, priv->original_mailbox))
3621 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3632 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3634 ModestMsgEditWindowPrivate *priv = NULL;
3635 GSList *address_list = NULL;
3636 gboolean no_to, no_cc, no_bcc;
3638 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3639 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3641 /* check if there's no recipient added */
3642 no_to = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)));
3643 no_cc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field)));
3644 no_bcc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field)));
3647 if (no_to && no_cc && no_bcc) {
3648 /* no recipient contents, then select contacts */
3649 modest_msg_edit_window_open_addressbook (window, NULL);
3654 g_object_ref (window);
3655 if (!no_to && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3656 (add_to_addressbook) ? &address_list : NULL)) {
3657 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3658 g_object_unref (window);
3661 if (!no_cc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3662 (add_to_addressbook) ? &address_list : NULL)) {
3663 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3664 g_object_unref (window);
3667 if (!no_bcc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3668 (add_to_addressbook) ? &address_list : NULL)) {
3669 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3670 g_object_unref (window);
3674 /* Add contacts to address book */
3675 if (add_to_addressbook && address_list)
3676 modest_address_book_add_address_list (address_list);
3678 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3679 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3680 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3681 g_object_unref (window);
3688 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3690 GSList *recipients = NULL;
3691 ModestMsgEditWindowPrivate *priv;
3692 gchar *joined, *after_remove, *to, *cc, *bcc;
3694 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3696 /* First of all check names */
3697 if (!modest_msg_edit_window_check_names (self, FALSE))
3700 if (!modest_msg_edit_window_has_pending_addresses (self))
3703 /* Don't add the from obviously */
3704 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3705 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3706 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3708 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3713 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3716 recipients = modest_text_utils_split_addresses_list (after_remove);
3717 g_free (after_remove);
3720 /* Offer the user to add recipients to the address book */
3721 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3722 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3727 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3728 ModestMsgEditWindow *window)
3730 modest_msg_edit_window_offer_attach_file (window);
3734 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3736 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3738 return priv->clipboard_text;
3742 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3744 ModestMsgEditWindow *window)
3746 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3747 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3750 /* It could happen that the window was already closed */
3751 if (!GTK_WIDGET_VISIBLE (window))
3754 g_object_ref (window);
3755 text = gtk_clipboard_wait_for_text (selection_clipboard);
3757 if (priv->clipboard_text != NULL) {
3758 g_free (priv->clipboard_text);
3760 priv->clipboard_text = text;
3762 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3764 g_object_unref (window);
3767 static gboolean clipboard_owner_change_idle (gpointer userdata)
3769 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3770 ModestMsgEditWindowPrivate *priv;
3772 gdk_threads_enter ();
3773 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3774 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3776 priv->clipboard_owner_idle = 0;
3777 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3778 gdk_threads_leave ();
3784 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3786 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3787 if (priv->clipboard_owner_idle == 0) {
3788 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3789 clipboard_owner_change_idle,
3790 g_object_ref (window),
3796 subject_field_move_cursor (GtkEntry *entry,
3797 GtkMovementStep step,
3802 /* It could happen that the window was already closed */
3803 if (!GTK_WIDGET_VISIBLE (window))
3806 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3810 update_window_title (ModestMsgEditWindow *window)
3812 ModestMsgEditWindowPrivate *priv = NULL;
3813 const gchar *subject;
3815 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3816 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3817 if (subject == NULL || subject[0] == '\0')
3818 subject = _("mail_va_new_email");
3820 modest_window_set_title (MODEST_WINDOW (window), subject);
3826 body_insert_text (GtkTextBuffer *buffer,
3827 GtkTextIter *location,
3830 ModestMsgEditWindow *window)
3832 GtkTextIter end_iter;
3839 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3841 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3843 offset = gtk_text_iter_get_offset (&end_iter);
3844 line = gtk_text_iter_get_line (&end_iter);
3848 while (text_offset < text + len) {
3849 if (*text_offset == '\n')
3851 if (text_lines + line >= MAX_BODY_LINES) {
3852 len = text_offset - text;
3858 utf8_len = g_utf8_strlen (text, len);
3860 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3861 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3862 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3867 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3869 /* Prevent endless recursion */
3870 result = g_strndup (text, utf8_end - text);
3871 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3872 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3873 (gpointer) result, (gpointer) (utf8_end - text),
3875 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3879 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3880 if (priv->max_chars_banner == NULL) {
3881 #ifdef MODEST_TOOLKIT_HILDON2
3882 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3883 _CS_MAXIMUM_CHARACTERS_REACHED);
3884 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3891 subject_field_changed (GtkEditable *editable,
3892 ModestMsgEditWindow *window)
3894 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3895 update_window_title (window);
3896 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3897 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3898 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3901 subject_field_insert_text (GtkEditable *editable,
3903 gint new_text_length,
3905 ModestMsgEditWindow *window)
3907 GString *result = g_string_new ("");
3909 gint result_len = 0;
3910 const gchar *entry_text = NULL;
3913 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3914 old_length = g_utf8_strlen (entry_text, -1);
3916 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3917 gunichar c = g_utf8_get_char_validated (current, 8);
3918 /* Invalid unichar, stop */
3924 result = g_string_append_unichar (result, c);
3928 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3929 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3932 /* Prevent endless recursion */
3933 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3934 g_signal_emit_by_name (editable, "insert-text",
3935 (gpointer) result->str, (gpointer) result->len,
3936 (gpointer) position, (gpointer) window);
3937 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3941 if (result_len + old_length > 1000) {
3942 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3943 _CS_MAXIMUM_CHARACTERS_REACHED);
3945 g_string_free (result, TRUE);
3949 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3952 ModestMsgEditWindowPrivate *priv = NULL;
3954 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3955 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3957 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3960 gtk_widget_show_all (priv->isearch_toolbar);
3961 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3963 gtk_widget_hide_all (priv->isearch_toolbar);
3964 gtk_widget_grab_focus (priv->msg_body);
3969 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3971 GtkTextIter *match_start,
3972 GtkTextIter *match_end)
3974 GtkTextIter end_iter;
3975 gchar *str_casefold;
3978 gchar *range_casefold;
3981 gboolean result = FALSE;
3988 gtk_text_iter_forward_to_end (&end_iter);
3990 str_casefold = g_utf8_casefold (str, -1);
3991 str_chars_n = strlen (str);
3993 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3994 range_casefold = g_utf8_casefold (range_text, -1);
3995 range_chars_n = strlen (range_casefold);
3997 if (range_chars_n < str_chars_n) {
3998 g_free (str_casefold);
3999 g_free (range_text);
4000 g_free (range_casefold);
4004 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
4005 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
4006 if (!g_utf8_collate (range_subtext, str_casefold)) {
4007 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
4009 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
4010 match_start, match_end, NULL)) {
4011 g_debug ("Matched string with collate, but not matched in model");
4013 g_free (found_text);
4015 g_free (range_subtext);
4019 g_free (str_casefold);
4020 g_free (range_text);
4021 g_free (range_casefold);
4028 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
4029 ModestMsgEditWindow *window)
4031 const gchar *current_search = NULL;
4032 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4034 GtkTextIter selection_start, selection_end;
4035 GtkTextIter match_start, match_end;
4036 gboolean continue_search = FALSE;
4038 if (message_is_empty (window)) {
4039 g_free (priv->last_search);
4040 priv->last_search = NULL;
4041 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
4045 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
4046 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
4047 g_free (priv->last_search);
4048 priv->last_search = NULL;
4049 /* Information banner about empty search */
4050 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
4054 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
4055 continue_search = TRUE;
4057 g_free (priv->last_search);
4058 priv->last_search = g_strdup (current_search);
4061 if (continue_search) {
4062 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
4063 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
4064 &match_start, &match_end);
4066 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_COMPLETE);
4068 GtkTextIter buffer_start;
4069 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
4070 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
4071 &match_start, &match_end);
4073 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_NO_MATCHES);
4076 /* Mark as selected the string found in search */
4078 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
4079 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
4080 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
4082 g_free (priv->last_search);
4083 priv->last_search = NULL;
4088 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
4090 ModestMsgEditWindowPrivate *priv;
4092 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
4097 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
4100 ModestMsgEditWindowPrivate *priv;
4102 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
4107 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
4108 ModestMsgEditWindow *window)
4110 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
4114 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
4117 ModestMsgEditWindowPrivate *priv;
4118 TnyHeader *header = NULL;
4120 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4121 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
4123 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4125 if (priv->draft_msg != NULL) {
4126 g_object_unref (priv->draft_msg);
4129 if (draft != NULL) {
4130 g_object_ref (draft);
4131 header = tny_msg_get_header (draft);
4132 if (priv->msg_uid) {
4133 g_free (priv->msg_uid);
4134 priv->msg_uid = NULL;
4136 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
4139 priv->draft_msg = draft;
4143 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
4144 GtkTextIter *start, GtkTextIter *end,
4147 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
4148 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
4151 if (tag == NULL) return;
4152 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
4153 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
4154 replace_with_images (window, priv->images);
4159 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
4162 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4164 g_return_if_fail (TNY_IS_MIME_PART (part));
4165 tny_list_prepend (priv->attachments, (GObject *) part);
4166 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
4167 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
4168 gtk_widget_show_all (priv->attachments_caption);
4169 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
4173 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
4175 ModestMsgEditWindowPrivate *priv;
4177 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
4178 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4180 return priv->msg_uid;
4184 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
4185 ModestMsgEditWindowWidgetType widget_type)
4187 ModestMsgEditWindowPrivate *priv;
4189 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
4190 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
4192 switch (widget_type) {
4193 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
4194 return priv->msg_body;
4196 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
4197 return priv->to_field;
4199 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
4200 return priv->cc_field;
4202 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4203 return priv->bcc_field;
4205 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4206 return priv->subject_field;
4208 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4209 return priv->attachments_view;
4217 remove_tags (WPTextBuffer *buffer)
4219 GtkTextIter start, end;
4221 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4222 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4224 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4228 on_account_removed (TnyAccountStore *account_store,
4229 TnyAccount *account,
4232 /* Do nothing if it's a store account, because we use the
4233 transport to send the messages */
4234 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4235 const gchar *parent_acc = NULL;
4236 const gchar *our_acc = NULL;
4238 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4239 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4240 /* Close this window if I'm showing a message of the removed account */
4241 if (strcmp (parent_acc, our_acc) == 0)
4242 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4247 update_signature (ModestMsgEditWindow *self,
4248 const gchar *old_account,
4249 const gchar *new_account)
4251 ModestMsgEditWindowPrivate *priv;
4252 gboolean has_old_signature, has_new_signature;
4254 ModestAccountMgr *mgr;
4257 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4259 gtk_text_buffer_begin_user_action (priv->text_buffer);
4261 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4262 mgr = modest_runtime_get_account_mgr ();
4266 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4267 if (has_old_signature) {
4268 GtkTextIter match_start, match_end;
4270 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4271 seems that the search has some problems
4272 with the blank space at the end */
4273 if (gtk_text_iter_forward_search (&iter, "--",
4274 GTK_TEXT_SEARCH_TEXT_ONLY,
4275 &match_start, NULL, NULL)) {
4276 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4277 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4279 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4280 &match_start, &match_end, NULL)) {
4284 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4289 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4290 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4291 if (has_new_signature) {
4294 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4295 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4297 is_rich = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
4299 WPTextBufferFormat *fmt;
4300 GdkColor style_color;
4301 if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
4302 gdk_color_parse ("grey", &style_color);
4304 fmt = g_new0 (WPTextBufferFormat, 1);
4305 fmt->color = style_color;
4306 fmt->cs.color = 0x1;
4307 wp_text_buffer_insert_with_attribute (WP_TEXT_BUFFER (priv->text_buffer), &iter,
4311 g_free (full_signature);
4313 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4317 gtk_text_buffer_end_user_action (priv->text_buffer);
4320 static void update_branding (ModestMsgEditWindow *self,
4321 const gchar *new_account)
4323 ModestMsgEditWindowPrivate *priv;
4324 ModestAccountMgr *mgr;
4325 const GdkPixbuf *new_icon = NULL;
4326 gchar *new_label = NULL;
4327 gboolean show = FALSE;
4329 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4331 mgr = modest_runtime_get_account_mgr ();
4333 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4335 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4336 gtk_widget_show (priv->brand_icon);
4339 gtk_widget_hide (priv->brand_icon);
4342 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4343 gtk_widget_show (priv->brand_label);
4347 gtk_widget_hide (priv->brand_label);
4351 gtk_widget_show (priv->brand_container);
4353 gtk_widget_hide (priv->brand_container);
4357 from_field_changed (GtkWidget *button,
4358 ModestMsgEditWindow *self)
4360 ModestMsgEditWindowPrivate *priv;
4361 gchar *old_account, *new_account;
4363 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4365 old_account = priv->last_from_account;
4366 new_account = modest_selector_get_active_id (priv->from_field);
4369 g_warning ("%s, could not get the new account", __FUNCTION__);
4373 /* If the From is the same do nothing */
4374 if (old_account && new_account && !strcmp (old_account, new_account))
4377 priv->last_from_account = new_account;
4379 update_signature (self, old_account, new_account);
4380 update_branding (self, new_account);
4384 typedef struct _MessageSettingsHelper {
4385 ModestMsgEditWindow *window;
4386 GSList *priority_group;
4387 GSList *format_group;
4388 GtkToggleButton *current_priority;
4389 GtkToggleButton *current_format;
4390 } MessageSettingsHelper;
4393 on_priority_toggle (GtkToggleButton *button,
4394 MessageSettingsHelper *helper)
4397 ModestMsgEditWindowPrivate *priv;
4399 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4400 if (gtk_toggle_button_get_active (button)) {
4402 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4403 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4404 if ((node_button != button) &&
4405 gtk_toggle_button_get_active (node_button)) {
4406 gtk_toggle_button_set_active (node_button, FALSE);
4409 helper->current_priority = button;
4411 gboolean found = FALSE;
4412 /* If no one is active, activate it again */
4413 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4414 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4415 if (gtk_toggle_button_get_active (node_button)) {
4421 gtk_toggle_button_set_active (button, TRUE);
4427 on_format_toggle (GtkToggleButton *button,
4428 MessageSettingsHelper *helper)
4431 ModestMsgEditWindowPrivate *priv;
4433 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4434 if (gtk_toggle_button_get_active (button)) {
4436 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4437 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4438 if ((node_button != button) &&
4439 gtk_toggle_button_get_active (node_button)) {
4440 gtk_toggle_button_set_active (node_button, FALSE);
4443 helper->current_format = button;
4445 gboolean found = FALSE;
4446 /* If no one is active, activate it again */
4447 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4448 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4449 if (gtk_toggle_button_get_active (node_button)) {
4455 gtk_toggle_button_set_active (button, TRUE);
4462 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4467 GtkWidget *priority_hbox;
4468 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4469 GtkWidget *captioned;
4470 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4471 GtkWidget *format_hbox;
4472 GtkWidget *html_toggle, *text_toggle;
4473 ModestMsgEditWindowPrivate *priv;
4474 MessageSettingsHelper helper = {0,};
4476 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4477 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4478 helper.window = window;
4479 helper.priority_group = NULL;
4480 helper.format_group = NULL;
4482 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4483 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4485 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4486 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4487 _HL_DONE, GTK_RESPONSE_ACCEPT, NULL);
4488 vbox = gtk_vbox_new (FALSE, 0);
4489 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4490 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4491 gtk_container_add (GTK_CONTAINER (align), vbox);
4492 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4493 gtk_widget_show (align);
4494 gtk_widget_show (vbox);
4496 /* Priority toggles */
4497 priority_hbox = gtk_hbox_new (TRUE, 0);
4498 #ifdef MODEST_TOOLKIT_HILDON2
4499 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4501 high_toggle = gtk_toggle_button_new ();
4503 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4504 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4505 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4506 #ifdef MODEST_TOOLKIT_HILDON2
4507 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4509 medium_toggle = gtk_toggle_button_new ();
4511 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4512 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4513 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4514 #ifdef MODEST_TOOLKIT_HILDON2
4515 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4517 low_toggle = gtk_toggle_button_new ();
4519 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4520 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4521 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4522 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4523 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4524 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4525 gtk_widget_show_all (priority_hbox);
4526 captioned = modest_toolkit_utils_create_captioned (title_sizegroup, value_sizegroup,
4527 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4528 gtk_widget_show (captioned);
4529 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4531 /* format toggles */
4532 format_hbox = gtk_hbox_new (TRUE, 0);
4533 #ifdef MODEST_TOOLKIT_HILDON2
4534 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4536 html_toggle = gtk_toggle_button_new ();
4538 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4539 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4540 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4541 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4542 #ifdef MODEST_TOOLKIT_HILDON2
4543 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4545 text_toggle = gtk_toggle_button_new ();
4547 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4548 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4549 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4550 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4551 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4552 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4553 gtk_widget_show_all (format_hbox);
4554 gtk_widget_show (format_hbox);
4555 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4558 g_object_unref (title_sizegroup);
4559 g_object_unref (value_sizegroup);
4561 /* Set current values */
4562 switch (priv->priority_flags) {
4563 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4564 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4565 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4567 case TNY_HEADER_FLAG_LOW_PRIORITY:
4568 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4569 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4572 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4573 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4577 switch (modest_msg_edit_window_get_format (window)) {
4578 case MODEST_MSG_EDIT_FORMAT_TEXT:
4579 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4580 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4582 case MODEST_MSG_EDIT_FORMAT_HTML:
4584 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4585 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4589 /* Signal connects */
4590 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4591 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4592 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4593 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4594 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4596 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4597 GTK_WINDOW (dialog), GTK_WINDOW (window));
4599 /* Save settings if the user clicked on done */
4600 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4601 TnyHeaderFlags flags;
4602 ModestMsgEditFormat old_format, new_format;
4604 /* Set priority flags */
4605 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4606 if (priv->priority_flags != flags)
4607 modest_msg_edit_window_set_priority_flags (window, flags);
4609 /* Set edit format */
4610 old_format = modest_msg_edit_window_get_format (window);
4611 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4612 if (old_format != new_format) {
4613 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4614 modest_msg_edit_window_set_file_format (window, file_format);
4618 gtk_widget_destroy (dialog);
4619 g_slist_free (helper.priority_group);
4623 on_message_settings (GtkAction *action,
4624 ModestMsgEditWindow *window)
4626 modest_msg_edit_window_show_msg_settings_dialog (window);
4630 on_show_toolbar_button_toggled (GtkWidget *button,
4631 ModestMsgEditWindow *window)
4633 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4635 modest_msg_edit_window_show_toolbar (MODEST_WINDOW (window),
4636 modest_togglable_get_active (button));
4640 on_cc_button_toggled (GtkWidget *button,
4641 ModestMsgEditWindow *window)
4643 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4645 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4646 modest_togglable_get_active (button));
4650 on_bcc_button_toggled (GtkWidget *button,
4651 ModestMsgEditWindow *window)
4653 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4655 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4656 modest_togglable_get_active (button));
4660 setup_menu (ModestMsgEditWindow *self)
4662 ModestMsgEditWindowPrivate *priv = NULL;
4664 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4666 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4668 /* Settings menu buttons */
4669 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4670 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4672 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4673 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4674 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4675 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4676 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4677 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4679 priv->cc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4680 _("mcen_me_editor_showcc"));
4681 modest_togglable_set_active (priv->cc_button,
4683 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4684 gtk_widget_show (priv->cc_button);
4685 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4686 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4688 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4689 _("mcen_me_editor_showbcc"));
4690 gtk_widget_show (priv->bcc_button);
4691 modest_togglable_set_active (priv->bcc_button,
4693 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4695 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4696 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4698 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4699 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4700 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4701 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4702 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4704 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4705 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4706 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4707 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4708 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4710 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4711 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4714 priv->show_toolbar_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4715 _("mcen_bd_show_toolbar"));
4716 modest_togglable_set_active (priv->show_toolbar_button,
4718 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->show_toolbar_button,
4719 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_show_toolbar));
4720 gtk_widget_show (priv->show_toolbar_button);
4721 g_signal_connect (G_OBJECT (priv->show_toolbar_button), "toggled",
4722 G_CALLBACK (on_show_toolbar_button_toggled), (gpointer) self);
4727 emit_open_addressbook (GtkButton *button,
4728 ModestRecptEditor *editor)
4730 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4734 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4735 const gchar *label, GtkWidget *control)
4737 GtkWidget *abook_button;
4740 GtkWidget *label_widget;
4742 box = gtk_hbox_new (FALSE, 0);
4744 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4745 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4747 #ifdef MODEST_TOOLKIT_HILDON2
4748 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4750 abook_button = gtk_button_new ();
4752 label_widget = gtk_label_new (label);
4753 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4754 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4756 gtk_container_add (GTK_CONTAINER (align), abook_button);
4757 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4758 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4759 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4760 if (title_size_group)
4761 gtk_size_group_add_widget (title_size_group, label_widget);
4762 if (value_size_group)
4763 gtk_size_group_add_widget (value_size_group, control);
4765 g_signal_connect (G_OBJECT (abook_button), "clicked",
4766 G_CALLBACK (emit_open_addressbook), control);
4772 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4774 ModestMsgEditWindowPrivate *priv = NULL;
4776 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4778 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4779 priv->max_chars_banner = NULL;
4783 has_pending_addresses (ModestRecptEditor *recpt_editor)
4785 const gchar *recipients = NULL;
4786 GSList *start_indexes = NULL, *end_indexes = NULL;
4787 GSList *current_start, *current_end;
4788 GtkTextBuffer *buffer;
4789 gint offset_delta = 0;
4791 gboolean has_recipients_to_add = FALSE;
4793 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4794 last_length = g_utf8_strlen (recipients, -1);
4795 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4800 current_start = start_indexes;
4801 current_end = end_indexes;
4802 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4804 while (current_start && !has_recipients_to_add) {
4806 gchar *start_ptr, *end_ptr;
4807 gint start_pos, end_pos;
4809 start_pos = (*((gint*) current_start->data)) + offset_delta;
4810 end_pos = (*((gint*) current_end->data)) + offset_delta;
4812 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4813 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4815 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4817 if (modest_text_utils_validate_recipient (address, NULL)) {
4818 if (!modest_address_book_has_address (address)) {
4819 has_recipients_to_add = TRUE;
4822 current_start = g_slist_next (current_start);
4823 current_end = g_slist_next (current_end);
4825 return has_recipients_to_add;
4829 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4831 ModestMsgEditWindowPrivate *priv = NULL;
4833 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4835 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4837 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4838 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4839 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))