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 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
137 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
138 ModestRecptEditor *editor);
139 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
140 ModestMsgEditWindow *window);
142 /* ModestWindow methods implementation */
143 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
144 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
145 gboolean show_toolbar);
146 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
148 ModestMsgEditWindow *window);
149 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
150 static void subject_field_move_cursor (GtkEntry *entry,
151 GtkMovementStep step,
155 static void update_window_title (ModestMsgEditWindow *window);
158 static void modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
159 ModestMsgEditWindow *window);
160 static void modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
161 ModestMsgEditWindow *window);
162 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
164 GtkTextIter *match_start,
165 GtkTextIter *match_end);
167 static void remove_tags (WPTextBuffer *buffer);
169 static void on_account_removed (TnyAccountStore *account_store,
173 static void init_window (ModestMsgEditWindow *obj);
175 gboolean scroll_drag_timeout (gpointer userdata);
176 static void correct_scroll (ModestMsgEditWindow *w);
177 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
178 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
179 ModestMsgEditWindow *userdata);
180 static void text_buffer_mark_set (GtkTextBuffer *buffer,
183 ModestMsgEditWindow *userdata);
184 static void on_message_settings (GtkAction *action,
185 ModestMsgEditWindow *window);
186 static void setup_menu (ModestMsgEditWindow *self);
188 static void from_field_changed (GtkWidget *button,
189 ModestMsgEditWindow *self);
190 static void font_size_clicked (GtkToolButton *button,
191 ModestMsgEditWindow *window);
192 static void font_face_clicked (GtkToolButton *button,
193 ModestMsgEditWindow *window);
194 static void update_signature (ModestMsgEditWindow *self,
195 const gchar *old_account,
196 const gchar *new_account);
197 static void update_branding (ModestMsgEditWindow *self,
198 const gchar *new_account);
199 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
200 const gchar *label, GtkWidget *control);
201 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
202 static void DEBUG_BUFFER (WPTextBuffer *buffer)
206 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
208 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
209 while (!gtk_text_iter_is_end (&iter)) {
210 GString *output = g_string_new ("");
211 GSList *toggled_tags;
214 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
215 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
216 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
217 GtkTextTag *tag = (GtkTextTag *) node->data;
219 g_object_get (G_OBJECT (tag), "name", &name, NULL);
220 output = g_string_append (output, name);
221 g_string_append (output, " ");
223 output = g_string_append (output, "] OPENED [ ");
224 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
225 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
226 GtkTextTag *tag = (GtkTextTag *) node->data;
228 g_object_get (G_OBJECT (tag), "name", &name, NULL);
229 output = g_string_append (output, name);
230 g_string_append (output, " ");
232 output = g_string_append (output, "]\n");
233 g_debug ("%s", output->str);
234 g_string_free (output, TRUE);
235 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
237 g_debug ("END BUFFER");
241 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
242 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
246 /* static gboolean */
247 /* on_key_pressed (GtkWidget *self, */
248 /* GdkEventKey *event, */
249 /* gpointer user_data); */
251 /* list my signals */
258 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
259 struct _ModestMsgEditWindowPrivate {
261 GtkWidget *header_box;
263 ModestPairList *from_field_protos;
264 GtkWidget *from_field;
265 gchar *last_from_account;
266 gchar *original_account_name;
271 gchar *original_mailbox;
275 GtkWidget *bcc_field;
276 GtkWidget *subject_field;
277 GtkWidget *attachments_view;
278 GtkWidget *priority_icon;
279 GtkWidget *subject_box;
280 GtkWidget *send_button;
282 GtkWidget *cc_caption;
283 GtkWidget *bcc_caption;
284 gboolean update_caption_visibility;
285 GtkWidget *attachments_caption;
287 GtkTextBuffer *text_buffer;
289 GtkWidget *font_size_toolitem;
290 GtkWidget *font_face_toolitem;
291 GtkWidget *font_color_button;
292 GtkWidget *font_color_toolitem;
293 GSList *font_items_group;
294 GtkTreeModel *faces_model;
295 gint current_face_index;
296 GtkWidget *font_tool_button_label;
297 GtkTreeModel *sizes_model;
298 gint current_size_index;
299 GtkWidget *size_tool_button_label;
301 GtkWidget *isearch_toolbar;
304 GtkWidget *font_dialog;
306 GtkWidget *scrollable;
307 guint correct_scroll_idle;
308 guint scroll_drag_timeout_id;
312 TnyList *attachments;
317 TnyHeaderFlags priority_flags;
319 gboolean can_undo, can_redo;
320 gulong clipboard_change_handler_id;
321 gulong default_clipboard_change_handler_id;
322 gulong account_removed_handler_id;
323 guint clipboard_owner_idle;
324 gchar *clipboard_text;
333 GtkWidget *cc_button;
334 GtkWidget *bcc_button;
336 GtkWidget *max_chars_banner;
338 GtkWidget *brand_icon;
339 GtkWidget *brand_label;
340 GtkWidget *brand_container;
343 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
344 MODEST_TYPE_MSG_EDIT_WINDOW, \
345 ModestMsgEditWindowPrivate))
347 static GtkWindowClass *parent_class = NULL;
349 /* uncomment the following if you have defined any signals */
350 /* static guint signals[LAST_SIGNAL] = {0}; */
353 modest_msg_edit_window_get_type (void)
355 static GType my_type = 0;
357 static const GTypeInfo my_info = {
358 sizeof(ModestMsgEditWindowClass),
359 NULL, /* base init */
360 NULL, /* base finalize */
361 (GClassInitFunc) modest_msg_edit_window_class_init,
362 NULL, /* class finalize */
363 NULL, /* class data */
364 sizeof(ModestMsgEditWindow),
366 (GInstanceInitFunc) modest_msg_edit_window_init,
369 my_type = g_type_register_static (
370 #ifdef MODEST_TOOLKIT_HILDON2
371 MODEST_TYPE_HILDON2_WINDOW,
373 MODEST_TYPE_SHELL_WINDOW,
375 "ModestMsgEditWindow",
383 save_state (ModestWindow *self)
385 modest_widget_memory_save (modest_runtime_get_conf(),
386 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
391 restore_settings (ModestMsgEditWindow *self)
393 ModestConf *conf = NULL;
395 conf = modest_runtime_get_conf ();
397 /* Dim at start clipboard actions */
398 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
403 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
405 GObjectClass *gobject_class;
406 ModestWindowClass *modest_window_class;
407 gobject_class = (GObjectClass*) klass;
408 modest_window_class = (ModestWindowClass*) klass;
410 parent_class = g_type_class_peek_parent (klass);
411 gobject_class->finalize = modest_msg_edit_window_finalize;
413 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
414 modest_window_class->save_state_func = save_state;
415 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
417 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
421 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
423 ModestMsgEditWindowPrivate *priv;
424 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
426 priv->msg_body = NULL;
427 priv->from_field = NULL;
428 priv->to_field = NULL;
429 priv->cc_field = NULL;
430 priv->bcc_field = NULL;
431 priv->subject_field = NULL;
432 priv->attachments = TNY_LIST (tny_simple_list_new ());
433 priv->images = TNY_LIST (tny_simple_list_new ());
434 priv->images_size = 0;
435 priv->images_count = 0;
438 priv->cc_caption = NULL;
439 priv->bcc_caption = NULL;
440 priv->update_caption_visibility = FALSE;
442 priv->priority_flags = 0;
444 priv->isearch_toolbar = NULL;
445 priv->last_search = NULL;
447 priv->draft_msg = NULL;
448 priv->outbox_msg = NULL;
449 priv->msg_uid = NULL;
451 priv->can_undo = FALSE;
452 priv->can_redo = FALSE;
453 priv->clipboard_change_handler_id = 0;
454 priv->default_clipboard_change_handler_id = 0;
455 priv->account_removed_handler_id = 0;
456 priv->clipboard_owner_idle = 0;
457 priv->clipboard_text = NULL;
460 priv->scroll_drag_timeout_id = 0;
461 priv->correct_scroll_idle = 0;
462 priv->last_upper = 0.0;
464 priv->font_dialog = NULL;
465 priv->app_menu = NULL;
467 priv->references = NULL;
468 priv->in_reply_to = NULL;
469 priv->max_chars_banner = NULL;
471 if (!is_wp_text_buffer_started) {
472 is_wp_text_buffer_started = TRUE;
473 wp_text_buffer_library_init ();
477 #ifdef MODEST_TOOLKIT_HILDON2
478 hildon_program_add_window (hildon_program_get_instance(),
484 multimailbox_get_default_mailbox (const gchar *account_name)
486 gchar *transport_account;
487 gchar *result = NULL;
489 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
491 TNY_ACCOUNT_TYPE_TRANSPORT);
492 if (transport_account) {
494 ModestProtocolRegistry *registry;
496 registry = modest_runtime_get_protocol_registry ();
498 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
499 MODEST_ACCOUNT_PROTO, TRUE);
501 ModestProtocol *protocol =
502 modest_protocol_registry_get_protocol_by_name (registry,
503 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
505 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
506 ModestPairList *pair_list;
508 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
511 ModestPair *pair = (ModestPair *) pair_list->data;
512 result = g_strdup ((const gchar *) pair->first);
513 modest_pair_list_free (pair_list);
524 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
526 static ModestPairList*
527 get_transports (void)
529 GSList *transports = NULL;
531 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
532 GSList *accounts = modest_account_mgr_account_names (account_mgr,
533 TRUE /* only enabled accounts. */);
535 GSList *cursor = accounts;
537 gchar *account_name = cursor->data;
540 gchar *transport_account;
541 gboolean multi_mailbox = FALSE;
542 ModestProtocol *protocol = NULL;
544 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
546 transport_account = modest_account_mgr_get_server_account_name
547 (modest_runtime_get_account_mgr (),
549 TNY_ACCOUNT_TYPE_TRANSPORT);
550 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
551 ModestPairList *pair_list;
552 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
555 transports = g_slist_concat (transports, pair_list);
556 multi_mailbox = TRUE;
561 if (!multi_mailbox) {
562 gchar *from_string = NULL;
564 from_string = modest_account_mgr_get_from_string (account_mgr,
566 if (from_string && account_name) {
567 gchar *name = account_name;
568 ModestPair *pair = modest_pair_new ((gpointer) name,
569 (gpointer) from_string , TRUE);
570 transports = g_slist_prepend (transports, pair);
575 cursor = cursor->next;
577 g_slist_free (accounts); /* only free the accounts, not the elements,
578 * because they are used in the pairlist */
582 static void window_focus (GtkWindow *window,
586 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
590 scroll_drag_timeout (gpointer userdata)
592 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
593 ModestMsgEditWindowPrivate *priv;
595 /* It could happen that the window was already closed */
596 if (!GTK_WIDGET_VISIBLE (win))
599 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
601 correct_scroll_without_drag_check (win, TRUE);
603 priv->scroll_drag_timeout_id = 0;
609 correct_scroll_without_drag_check_idle (gpointer userdata)
611 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
612 ModestMsgEditWindowPrivate *priv;
614 GdkRectangle rectangle;
615 gint offset_min, offset_max;
619 /* It could happen that the window was already closed */
620 if (!GTK_WIDGET_VISIBLE (w))
623 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
625 insert = gtk_text_buffer_get_insert (priv->text_buffer);
626 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
628 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
629 offset_min = priv->msg_body->allocation.y + rectangle.y;
630 offset_max = offset_min + rectangle.height;
632 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
633 offset_min = MAX (offset_min - 48, 0);
634 offset_max = MIN (offset_max + 48, vadj->upper);
636 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
638 priv->correct_scroll_idle = 0;
643 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
645 ModestMsgEditWindowPrivate *priv;
647 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
649 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
652 if (priv->correct_scroll_idle > 0) {
656 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
657 (GSourceFunc) correct_scroll_without_drag_check_idle,
663 correct_scroll (ModestMsgEditWindow *w)
665 ModestMsgEditWindowPrivate *priv;
667 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
668 if (gtk_grab_get_current () == priv->msg_body) {
669 if (priv->scroll_drag_timeout_id == 0) {
670 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
672 (GSourceFunc) scroll_drag_timeout,
679 correct_scroll_without_drag_check (w, TRUE);
683 text_buffer_end_user_action (GtkTextBuffer *buffer,
684 ModestMsgEditWindow *userdata)
687 correct_scroll (userdata);
691 text_buffer_mark_set (GtkTextBuffer *buffer,
694 ModestMsgEditWindow *userdata)
696 gtk_text_buffer_begin_user_action (buffer);
697 gtk_text_buffer_end_user_action (buffer);
701 cut_clipboard_check (GtkTextView *text_view,
704 GtkTextBuffer *buffer;
706 buffer = gtk_text_view_get_buffer (text_view);
707 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
708 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
713 copy_clipboard_check (GtkTextView *text_view,
716 GtkTextBuffer *buffer;
718 buffer = gtk_text_view_get_buffer (text_view);
719 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
720 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
725 attachment_deleted (ModestAttachmentsView *attachments_view,
728 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
733 body_size_request (GtkWidget *body,
737 /* Make sure the body always get at least 70 pixels */
738 if (req->height < 70)
743 connect_signals (ModestMsgEditWindow *obj)
745 ModestMsgEditWindowPrivate *priv;
747 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
749 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
750 G_CALLBACK (text_buffer_refresh_attributes), obj);
751 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
752 G_CALLBACK (text_buffer_can_undo), obj);
753 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
754 G_CALLBACK (text_buffer_can_redo), obj);
755 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
756 G_CALLBACK (body_changed), obj);
757 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
758 G_CALLBACK (body_insert_text), obj);
759 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
760 G_CALLBACK (body_changed), obj);
761 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
762 G_CALLBACK (text_buffer_end_user_action), obj);
763 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
764 G_CALLBACK (text_buffer_mark_set), obj);
765 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
766 G_CALLBACK (text_buffer_apply_tag), obj);
767 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
768 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
769 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
770 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
771 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
772 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
774 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
775 G_CALLBACK (modest_ui_actions_on_send), obj);
777 if (GTK_IS_COMBO_BOX (priv->from_field)) {
778 g_signal_connect (G_OBJECT (priv->from_field), "changed",
779 G_CALLBACK (from_field_changed), obj);
781 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
782 G_CALLBACK (from_field_changed), obj);
785 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
786 G_CALLBACK (msg_body_focus), obj);
787 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
788 G_CALLBACK (msg_body_focus), obj);
789 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
790 G_CALLBACK (body_size_request), obj);
791 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
792 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
793 "changed", G_CALLBACK (recpt_field_changed), obj);
794 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
795 "changed", G_CALLBACK (recpt_field_changed), obj);
796 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
797 "changed", G_CALLBACK (recpt_field_changed), obj);
798 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
799 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
800 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
802 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
803 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
804 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
805 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_close), obj);
807 priv->clipboard_change_handler_id =
808 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
809 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
810 priv->default_clipboard_change_handler_id =
811 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
812 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
814 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
815 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
816 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
820 init_wp_text_view_style ()
822 static gboolean initialized = FALSE;
825 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
831 init_window (ModestMsgEditWindow *obj)
833 GtkWidget *to_caption, *subject_caption;
834 GtkWidget *main_vbox;
835 ModestMsgEditWindowPrivate *priv;
836 GtkActionGroup *action_group;
837 ModestWindowPrivate *parent_priv;
838 GError *error = NULL;
840 GtkSizeGroup *title_size_group;
841 GtkSizeGroup *value_size_group;
842 GtkWidget *window_box;
843 GtkWidget *window_align;
844 #if (GTK_MINOR_VERSION >= 10)
845 GdkAtom deserialize_type;
847 GtkWidget *from_send_hbox;
848 GtkWidget *send_icon;
849 GtkWidget *attachments_label;
850 GtkWidget *branding_box;
851 GtkWidget *from_caption;
853 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
854 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
856 parent_priv->ui_manager = gtk_ui_manager_new();
857 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
858 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
860 /* Add common actions */
861 gtk_action_group_add_actions (action_group,
862 modest_msg_edit_action_entries,
863 G_N_ELEMENTS (modest_msg_edit_action_entries),
865 gtk_action_group_add_actions (action_group,
866 hildon2_msg_edit_action_entries,
867 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
869 gtk_action_group_add_toggle_actions (action_group,
870 modest_msg_edit_toggle_action_entries,
871 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
873 gtk_action_group_add_radio_actions (action_group,
874 modest_msg_edit_alignment_radio_action_entries,
875 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
877 G_CALLBACK (modest_ui_actions_on_change_justify),
879 gtk_action_group_add_radio_actions (action_group,
880 modest_msg_edit_priority_action_entries,
881 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
883 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
885 gtk_action_group_add_radio_actions (action_group,
886 modest_msg_edit_file_format_action_entries,
887 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
888 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
889 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
891 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
892 g_object_unref (action_group);
894 /* Load the UI definition */
895 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
898 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
899 g_clear_error (&error);
902 parent_priv->menubar = NULL;
904 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
905 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
907 /* Note: This ModestPairList* must exist for as long as the picker
908 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
909 * so it can't know how to manage its memory. */
910 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
912 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
913 if (GTK_IS_COMBO_BOX (priv->from_field)) {
914 from_caption = modest_toolkit_utils_create_captioned (title_size_group, NULL,
915 _("mail_va_from"), FALSE,
917 gtk_widget_show (from_caption);
919 #ifdef MODEST_TOOLKIT_HILDON2
920 modest_toolkit_utils_set_hbutton_layout (title_size_group, NULL,
921 _("mail_va_from"), priv->from_field);
922 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
923 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
924 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
925 from_caption = priv->from_field;
929 priv->to_field = modest_recpt_editor_new ();
930 priv->cc_field = modest_recpt_editor_new ();
931 priv->bcc_field = modest_recpt_editor_new ();
932 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
933 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
934 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
935 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
936 priv->priority_icon = gtk_image_new ();
937 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
938 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
939 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
940 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
941 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
943 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
944 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
946 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
947 priv->attachments_view = modest_attachments_view_new (NULL);
948 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
949 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
951 priv->header_box = gtk_vbox_new (FALSE, 0);
953 to_caption = _create_addressbook_box
954 (title_size_group, value_size_group,
955 _("mail_va_to"), priv->to_field);
956 priv->cc_caption = _create_addressbook_box
957 (title_size_group, value_size_group,
958 _("mail_va_cc"), priv->cc_field);
959 priv->bcc_caption = _create_addressbook_box
960 (title_size_group, value_size_group,
961 _("mail_va_hotfix1"), priv->bcc_field);
962 subject_caption = modest_toolkit_utils_create_captioned (title_size_group, value_size_group,
963 _("mail_va_subject"), FALSE, priv->subject_box);
964 priv->attachments_caption = modest_toolkit_utils_create_captioned_with_size_type (NULL, NULL,
965 _("mail_va_attachment"),
967 priv->attachments_view,
968 #ifdef MODEST_TOOLKIT_HILDON2
969 HILDON_SIZE_AUTO_WIDTH |
970 HILDON_SIZE_AUTO_HEIGHT
975 attachments_label = modest_toolkit_utils_captioned_get_label_widget (priv->attachments_caption);
977 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
981 #ifdef MODEST_TOOLKIT_HILDON2
982 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
983 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
985 priv->send_button = gtk_button_new ();
986 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, GTK_ICON_SIZE_BUTTON);
988 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
989 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
991 g_object_unref (title_size_group);
992 g_object_unref (value_size_group);
994 priv->brand_icon = gtk_image_new ();
995 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
996 priv->brand_label = gtk_label_new (NULL);
997 #ifdef MODEST_TOOLKIT_HILDON2
998 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
1000 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
1001 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
1002 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
1004 from_send_hbox = gtk_hbox_new (FALSE, 0);
1005 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
1006 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
1008 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
1009 gtk_widget_show (branding_box);
1010 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
1011 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
1013 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
1014 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1015 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
1016 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
1019 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
1020 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
1021 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
1022 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
1023 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
1024 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
1025 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
1026 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1028 init_wp_text_view_style ();
1030 priv->msg_body = modest_wp_text_view_new ();
1033 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1034 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1035 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1036 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1037 #if (GTK_MINOR_VERSION >= 10)
1038 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1039 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1041 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1042 deserialize_type, TRUE);
1044 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1046 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1048 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1050 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1052 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1054 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1056 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1057 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1058 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1060 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1061 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1062 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1064 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1065 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1067 window_box = gtk_vbox_new (FALSE, 0);
1068 gtk_container_add (GTK_CONTAINER(obj), window_box);
1070 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1075 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1077 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1079 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1080 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1081 priv->clipboard_change_handler_id))
1082 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1083 priv->clipboard_change_handler_id);
1084 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1085 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1086 priv->default_clipboard_change_handler_id))
1087 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1088 priv->default_clipboard_change_handler_id);
1090 if (priv->account_removed_handler_id &&
1091 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1092 priv->account_removed_handler_id))
1093 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1094 priv->account_removed_handler_id);
1098 modest_msg_edit_window_finalize (GObject *obj)
1100 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1102 if (priv->max_chars_banner) {
1103 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1104 priv->max_chars_banner = FALSE;
1107 /* Sanity check: shouldn't be needed, the window mgr should
1108 call this function before */
1109 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1111 if (priv->font_dialog != NULL) {
1112 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1115 if (priv->clipboard_text != NULL) {
1116 g_free (priv->clipboard_text);
1117 priv->clipboard_text = NULL;
1120 if (priv->draft_msg != NULL) {
1121 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1122 if (TNY_IS_HEADER (header)) {
1123 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1124 modest_window_mgr_unregister_header (mgr, header);
1126 g_object_unref (priv->draft_msg);
1127 priv->draft_msg = NULL;
1129 if (priv->outbox_msg != NULL) {
1130 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1131 if (TNY_IS_HEADER (header)) {
1132 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1133 modest_window_mgr_unregister_header (mgr, header);
1135 g_object_unref (priv->outbox_msg);
1136 priv->outbox_msg = NULL;
1138 if (priv->correct_scroll_idle > 0) {
1139 g_source_remove (priv->correct_scroll_idle);
1140 priv->correct_scroll_idle = 0;
1142 if (priv->scroll_drag_timeout_id > 0) {
1143 g_source_remove (priv->scroll_drag_timeout_id);
1144 priv->scroll_drag_timeout_id = 0;
1146 if (priv->clipboard_owner_idle > 0) {
1147 g_source_remove (priv->clipboard_owner_idle);
1148 priv->clipboard_owner_idle = 0;
1150 if (priv->original_account_name)
1151 g_free (priv->original_account_name);
1152 if (priv->original_mailbox)
1153 g_free (priv->original_mailbox);
1154 g_free (priv->msg_uid);
1155 g_free (priv->last_search);
1156 g_free (priv->references);
1157 g_free (priv->in_reply_to);
1158 g_object_unref (priv->attachments);
1159 g_object_unref (priv->images);
1161 /* This had to stay alive for as long as the picker that used it: */
1162 modest_pair_list_free (priv->from_field_protos);
1164 G_OBJECT_CLASS(parent_class)->finalize (obj);
1168 pixbuf_size_prepared (GdkPixbufLoader *loader,
1171 ModestMsgEditWindow *self)
1173 gint new_height, new_width;
1176 new_height = height;
1180 if (width > IMAGE_MAX_WIDTH) {
1181 new_height = height * IMAGE_MAX_WIDTH / width;
1182 new_width = IMAGE_MAX_WIDTH;
1185 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1189 pixbuf_from_stream (TnyStream *stream,
1190 const gchar *mime_type,
1191 guint64 *stream_size,
1192 ModestMsgEditWindow *self)
1194 GdkPixbufLoader *loader;
1197 GError *error = NULL;
1201 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1203 if (loader == NULL) {
1208 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1210 modest_window_show_progress (MODEST_WINDOW (self), TRUE);
1212 tny_stream_reset (TNY_STREAM (stream));
1213 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1214 unsigned char read_buffer[128];
1216 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1218 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1221 /* Allow some UI responsiveness */
1222 while (gtk_events_pending ())
1223 gtk_main_iteration ();
1225 modest_window_show_progress (MODEST_WINDOW (self), FALSE);
1227 gdk_pixbuf_loader_close (loader, &error);
1230 g_error_free (error);
1231 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1233 g_object_ref (pixbuf);
1234 g_object_unref (loader);
1239 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1240 GdkPixbuf *new_pixbuf;
1242 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1243 gdk_pixbuf_get_width (pixbuf);
1244 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1245 g_object_unref (pixbuf);
1246 pixbuf = new_pixbuf;
1250 *stream_size = size;
1256 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1258 ModestMsgEditWindowPrivate *priv;
1261 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1263 g_object_ref (self);
1264 for (iter = tny_list_create_iterator (attachments);
1265 !tny_iterator_is_done (iter);
1266 tny_iterator_next (iter)) {
1267 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1268 const gchar *cid = tny_mime_part_get_content_id (part);
1269 const gchar *mime_type = tny_mime_part_get_content_type (part);
1270 if ((cid != NULL)&&(mime_type != NULL)) {
1271 guint64 stream_size;
1272 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1273 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1276 g_object_unref (stream);
1278 if (pixbuf != NULL) {
1279 priv->images_count ++;
1280 priv->images_size += stream_size;
1281 #ifndef MODEST_HAVE_LIBWPEDITOR_PLUS
1282 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1284 g_object_unref (pixbuf);
1287 g_object_unref (part);
1289 g_object_unref (iter);
1290 g_object_unref (self);
1294 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1296 TnyMimePart *parent = NULL;
1297 const gchar *content_type = NULL;
1298 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1300 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1302 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1303 parent = g_object_ref (msg);
1304 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1305 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1308 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1309 iter = tny_list_create_iterator (parts);
1310 while (!tny_iterator_is_done (iter)) {
1312 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1313 content_type = tny_mime_part_get_content_type (part);
1314 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1318 g_object_unref (part);
1320 tny_iterator_next (iter);
1322 g_object_unref (iter);
1323 g_object_unref (parts);
1326 if (parent != NULL) {
1327 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1330 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1331 iter = tny_list_create_iterator (parts);
1332 while (!tny_iterator_is_done (iter)) {
1334 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1335 content_type = tny_mime_part_get_content_type (part);
1336 if (content_type && g_str_has_prefix (content_type, "image/")) {
1337 tny_list_prepend (priv->images, (GObject *) part);
1339 g_object_unref (part);
1340 tny_iterator_next (iter);
1342 g_object_unref (iter);
1343 g_object_unref (parts);
1344 g_object_unref (parent);
1349 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1352 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1354 for (iter = tny_list_create_iterator (attachments) ;
1355 !tny_iterator_is_done (iter);
1356 tny_iterator_next (iter)) {
1357 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1358 const gchar *cid = tny_mime_part_get_content_id (part);
1360 char *invalid = NULL;
1361 gint int_cid = strtol (cid, &invalid, 10);
1362 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1363 priv->next_cid = int_cid + 1;
1366 g_object_unref (part);
1368 g_object_unref (iter);
1372 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1375 gchar *to, *cc, *bcc, *subject;
1377 ModestMsgEditWindowPrivate *priv;
1378 ModestWindowPrivate *parent_priv;
1380 TnyHeaderFlags priority_flags;
1381 TnyFolder *msg_folder;
1382 gboolean is_html = FALSE;
1383 gboolean field_view_set;
1385 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1386 g_return_if_fail (TNY_IS_MSG (msg));
1388 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1389 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1391 header = tny_msg_get_header (msg);
1392 to = tny_header_dup_to (header);
1393 cc = tny_header_dup_cc (header);
1394 bcc = tny_header_dup_bcc (header);
1395 subject = tny_header_dup_subject (header);
1397 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1398 priority_flags = tny_header_get_priority (header);
1401 gchar *quoted_names = modest_text_utils_quote_names (to);
1402 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1403 g_free (quoted_names);
1406 field_view_set = TRUE;
1408 gchar *quoted_names = modest_text_utils_quote_names (cc);
1409 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1410 g_free (quoted_names);
1411 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1412 gtk_widget_show (priv->cc_caption);
1413 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1414 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1415 gtk_widget_hide (priv->cc_caption);
1416 field_view_set = FALSE;
1418 modest_togglable_set_active (priv->cc_button, field_view_set);
1420 field_view_set = TRUE;
1422 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1423 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1424 g_free (quoted_names);
1425 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1426 gtk_widget_show (priv->bcc_caption);
1427 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1428 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1429 gtk_widget_hide (priv->bcc_caption);
1430 field_view_set = FALSE;
1432 modest_togglable_set_active (priv->bcc_button, field_view_set);
1436 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1437 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1440 update_window_title (self);
1442 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1443 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1445 if ((body == NULL)||(body[0] == '\0')) {
1447 body = modest_text_utils_convert_to_html ("");
1450 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1451 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1454 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1457 /* Add attachments to the view */
1458 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1459 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1460 if (tny_list_get_length (priv->attachments) == 0) {
1461 gtk_widget_hide (priv->attachments_caption);
1463 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1464 gtk_widget_show_all (priv->attachments_caption);
1466 get_related_images (self, msg);
1467 update_next_cid (self, priv->attachments);
1468 update_next_cid (self, priv->images);
1469 replace_with_images (self, priv->images);
1471 if (preserve_is_rich && !is_html) {
1472 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1473 /* Get the default format required from configuration */
1474 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1475 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1478 /* Set the default focus depending on having already a To: field or not */
1479 if ((!to)||(*to == '\0')) {
1480 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1482 gtk_widget_grab_focus (priv->msg_body);
1485 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1487 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1488 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1490 modest_msg_edit_window_set_modified (self, FALSE);
1492 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1493 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1494 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1495 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1497 if (priv->msg_uid) {
1498 g_free (priv->msg_uid);
1499 priv->msg_uid = NULL;
1502 /* we should set a reference to the incoming message if it is a draft */
1503 msg_folder = tny_msg_get_folder (msg);
1505 if (modest_tny_folder_is_local_folder (msg_folder)) {
1506 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1507 if (type == TNY_FOLDER_TYPE_INVALID)
1508 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1510 if (type == TNY_FOLDER_TYPE_DRAFTS)
1511 priv->draft_msg = g_object_ref(msg);
1512 if (type == TNY_FOLDER_TYPE_OUTBOX)
1513 priv->outbox_msg = g_object_ref(msg);
1514 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1516 g_object_unref (msg_folder);
1526 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1528 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1529 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1530 GtkWidget *placeholder;
1531 GtkWidget *tool_item;
1536 GtkWidget *sizes_menu;
1537 GtkWidget *fonts_menu;
1543 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1544 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1545 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar),
1546 #ifdef MODEST_TOOLKIT_HILDON2
1547 HILDON_ICON_SIZE_FINGER
1549 GTK_ICON_SIZE_LARGE_TOOLBAR
1552 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1554 /* Font color placeholder */
1555 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1556 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1559 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1560 #ifdef MODEST_TOOLKIT_HILDON2
1561 priv->font_color_button = modest_color_button_new ();
1563 priv->font_color_button = gtk_color_button_new ();
1565 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1566 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1567 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1568 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1569 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1570 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1571 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1572 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1574 G_CALLBACK (modest_msg_edit_window_color_button_change),
1577 /* Font size and face placeholder */
1578 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1579 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1581 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1582 priv->size_tool_button_label = gtk_label_new (NULL);
1583 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1584 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1585 size_text, "</span>", NULL);
1586 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1587 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1589 #ifdef MODEST_TOOLKIT_HILDON2
1590 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1592 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1593 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1594 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1595 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1596 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1597 gtk_widget_set_sensitive (arrow, FALSE);
1598 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1599 sizes_menu = gtk_menu_new ();
1600 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1601 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1604 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1605 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1607 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1611 if (wp_font_size[size_index] == 12)
1612 priv->current_size_index = size_index;
1616 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1617 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1618 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1619 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1620 priv->font_size_toolitem = tool_item;
1623 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1624 priv->font_tool_button_label = gtk_label_new (NULL);
1625 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1626 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1627 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1629 #ifdef MODEST_TOOLKIT_HILDON2
1630 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1632 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1633 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1634 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1635 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1636 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1637 gtk_widget_set_sensitive (arrow, FALSE);
1638 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1639 fonts_menu = gtk_menu_new ();
1640 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1641 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1644 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1646 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1647 0, wp_get_font_name (font_index),
1650 if (font_index == DEFAULT_FONT)
1651 priv->current_face_index = font_index;
1653 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1654 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1655 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1656 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1657 priv->font_face_toolitem = tool_item;
1659 /* Set expand and homogeneous for remaining items */
1660 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1661 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1662 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1663 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1664 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1665 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1667 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1668 will not show the tool items added to the placeholders) */
1669 gtk_widget_show_all (parent_priv->toolbar);
1671 /* Set the no show all *after* showing all items. We do not
1672 want the toolbar to be shown with a show all because it
1673 could go agains the gconf setting regarding showing or not
1674 the toolbar of the editor window */
1675 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1681 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1684 ModestWindowPrivate *parent_priv;
1685 ModestMsgEditWindowPrivate *priv;
1686 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1687 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1688 ModestWindowMgr *mgr = NULL;
1690 g_return_val_if_fail (msg, NULL);
1691 g_return_val_if_fail (account_name, NULL);
1693 mgr = modest_runtime_get_window_mgr ();
1695 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1697 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1698 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1700 /* Menubar. Update the state of some toggles */
1701 priv->from_field_protos = get_transports ();
1702 priv->original_mailbox = NULL;
1703 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1704 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1705 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1706 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1707 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1708 priv->original_mailbox = g_strdup (mailbox);
1709 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1710 /* We set the first mailbox as the active mailbox */
1711 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1712 if (priv->original_mailbox != NULL)
1713 modest_selector_set_active_id (priv->from_field,
1714 (gpointer) priv->original_mailbox);
1716 modest_selector_set_active_id (priv->from_field,
1717 (gpointer) account_name);
1719 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1721 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1722 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1723 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1724 #ifdef HILDON_TOOLKIT_HILDON2
1725 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1727 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1728 hildon_touch_selector_get_current_text
1729 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1732 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1733 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1736 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1738 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1740 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1741 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1743 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1745 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1746 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1747 /* Add common dimming rules */
1748 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1749 modest_msg_edit_window_toolbar_dimming_entries,
1750 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1751 MODEST_WINDOW (obj));
1752 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1753 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1754 MODEST_WINDOW (obj));
1755 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1756 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1757 MODEST_WINDOW (obj));
1758 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1759 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1760 MODEST_WINDOW (obj));
1761 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1762 G_CALLBACK (modest_ui_dimming_rules_on_send),
1763 MODEST_WINDOW (obj));
1764 /* Insert dimming rules group for this window */
1765 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1766 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1768 /* Setup app menu */
1769 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1771 /* Checks the dimming rules */
1772 g_object_unref (toolbar_rules_group);
1773 g_object_unref (clipboard_rules_group);
1774 gtk_widget_hide (priv->priority_icon);
1775 gtk_widget_queue_resize (priv->subject_box);
1776 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1778 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1780 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1781 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1782 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1783 priv->update_caption_visibility = TRUE;
1785 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1787 /* Track account-removed signal, this window should be closed
1788 in the case we're creating a mail associated to the account
1790 priv->account_removed_handler_id =
1791 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1793 G_CALLBACK(on_account_removed),
1796 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1798 return (ModestWindow*) obj;
1802 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1804 GString **string_buffer = (GString **) user_data;
1806 *string_buffer = g_string_append (*string_buffer, buffer);
1812 * @result: A new string which should be freed with g_free().
1815 get_formatted_data (ModestMsgEditWindow *edit_window)
1817 ModestMsgEditWindowPrivate *priv;
1818 GString *string_buffer = g_string_new ("");
1820 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1822 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1824 modest_text_utils_hyperlinkify (string_buffer);
1826 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1828 return g_string_free (string_buffer, FALSE);
1833 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1836 const gchar *account_name;
1837 ModestMsgEditWindowPrivate *priv;
1838 TnyIterator *att_iter;
1839 const gchar *picker_active_id;
1841 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1843 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1845 picker_active_id = modest_selector_get_active_id (priv->from_field);
1846 g_return_val_if_fail (picker_active_id, NULL);
1847 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1849 /* don't free these (except from) */
1850 data = g_slice_new0 (MsgData);
1851 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1852 data->account_name = g_strdup (account_name);
1853 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1854 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1855 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1856 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1857 data->references = g_strdup (priv->references);
1858 data->in_reply_to = g_strdup (priv->in_reply_to);
1859 if (priv->draft_msg) {
1860 data->draft_msg = g_object_ref (priv->draft_msg);
1861 } else if (priv->outbox_msg) {
1862 data->draft_msg = g_object_ref (priv->outbox_msg);
1864 data->draft_msg = NULL;
1867 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1869 gtk_text_buffer_get_bounds (buf, &b, &e);
1870 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1872 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1873 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1875 data->html_body = NULL;
1877 /* deep-copy the data */
1878 att_iter = tny_list_create_iterator (priv->attachments);
1879 data->attachments = NULL;
1880 while (!tny_iterator_is_done (att_iter)) {
1881 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1882 if (!(TNY_IS_MIME_PART(part))) {
1883 g_warning ("strange data in attachment list");
1884 g_object_unref (part);
1885 tny_iterator_next (att_iter);
1888 data->attachments = g_list_append (data->attachments,
1890 tny_iterator_next (att_iter);
1892 g_object_unref (att_iter);
1894 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1895 att_iter = tny_list_create_iterator (priv->images);
1896 data->images = NULL;
1897 while (!tny_iterator_is_done (att_iter)) {
1898 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1900 if (!(TNY_IS_MIME_PART(part))) {
1901 g_warning ("strange data in attachment list");
1902 g_object_unref (part);
1903 tny_iterator_next (att_iter);
1906 cid = tny_mime_part_get_content_id (part);
1908 gchar *image_tag_id;
1909 GtkTextTag *image_tag;
1911 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1912 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1913 g_free (image_tag_id);
1915 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1917 ((gtk_text_iter_has_tag (&iter, image_tag))||
1918 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1919 data->images = g_list_append (data->images,
1920 g_object_ref (part));
1922 g_object_unref (part);
1923 tny_iterator_next (att_iter);
1925 g_object_unref (att_iter);
1927 data->priority_flags = priv->priority_flags;
1934 unref_gobject (GObject *obj, gpointer data)
1936 if (!G_IS_OBJECT(obj))
1938 g_object_unref (obj);
1942 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1945 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1953 g_free (data->from);
1954 g_free (data->subject);
1955 g_free (data->plain_body);
1956 g_free (data->html_body);
1957 g_free (data->account_name);
1958 g_free (data->references);
1959 g_free (data->in_reply_to);
1961 if (data->draft_msg != NULL) {
1962 g_object_unref (data->draft_msg);
1963 data->draft_msg = NULL;
1966 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1967 g_list_free (data->attachments);
1968 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1969 g_list_free (data->images);
1971 g_slice_free (MsgData, data);
1975 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1977 guint64 *parts_size)
1979 ModestMsgEditWindowPrivate *priv;
1981 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1983 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1985 /* TODO: add images */
1986 *parts_size += priv->images_size;
1987 *parts_count += priv->images_count;
1992 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1995 ModestMsgEditWindowPrivate *priv = NULL;
1996 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1998 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2000 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2002 return MODEST_MSG_EDIT_FORMAT_HTML;
2004 return MODEST_MSG_EDIT_FORMAT_TEXT;
2008 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
2009 ModestMsgEditFormat format)
2011 ModestMsgEditWindowPrivate *priv;
2012 ModestWindowPrivate *parent_priv;
2014 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2015 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2016 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2019 case MODEST_MSG_EDIT_FORMAT_HTML:
2020 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2021 update_signature (self, priv->last_from_account, priv->last_from_account);
2022 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
2024 case MODEST_MSG_EDIT_FORMAT_TEXT:
2025 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2026 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
2029 g_return_if_reached ();
2033 ModestMsgEditFormatState *
2034 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2036 ModestMsgEditFormatState *format_state = NULL;
2037 ModestMsgEditWindowPrivate *priv;
2038 WPTextBufferFormat *buffer_format;
2040 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2042 buffer_format = g_new0 (WPTextBufferFormat, 1);
2043 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2045 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2047 format_state = g_new0 (ModestMsgEditFormatState, 1);
2048 format_state->bold = buffer_format->bold&0x1;
2049 format_state->italics = buffer_format->italic&0x1;
2050 format_state->bullet = buffer_format->bullet&0x1;
2051 format_state->color = buffer_format->color;
2052 format_state->font_size = buffer_format->font_size;
2053 format_state->font_family = wp_get_font_name (buffer_format->font);
2054 format_state->justification = buffer_format->justification;
2055 g_free (buffer_format);
2057 return format_state;
2062 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2063 const ModestMsgEditFormatState *format_state)
2065 ModestMsgEditWindowPrivate *priv;
2066 WPTextBufferFormat *buffer_format;
2067 WPTextBufferFormat *current_format;
2069 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2070 g_return_if_fail (format_state != NULL);
2072 buffer_format = g_new0 (WPTextBufferFormat, 1);
2073 current_format = g_new0 (WPTextBufferFormat, 1);
2075 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2076 gtk_widget_grab_focus (priv->msg_body);
2077 buffer_format->bold = (format_state->bold != FALSE);
2078 buffer_format->italic = (format_state->italics != FALSE);
2079 buffer_format->color = format_state->color;
2080 buffer_format->font_size = format_state->font_size;
2081 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2082 buffer_format->justification = format_state->justification;
2083 buffer_format->bullet = format_state->bullet;
2085 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2087 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2088 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2089 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2090 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2091 buffer_format->cs.font = (buffer_format->font != current_format->font);
2092 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2093 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2095 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2096 if (buffer_format->cs.bold) {
2097 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2098 GINT_TO_POINTER (buffer_format->bold&0x1));
2100 if (buffer_format->cs.italic) {
2101 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2102 GINT_TO_POINTER (buffer_format->italic&0x1));
2104 if (buffer_format->cs.color) {
2105 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2106 GINT_TO_POINTER (&(buffer_format->color)));
2108 if (buffer_format->cs.font_size) {
2109 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2110 GINT_TO_POINTER (buffer_format->font_size));
2112 if (buffer_format->cs.justification) {
2113 switch (buffer_format->justification) {
2114 case GTK_JUSTIFY_LEFT:
2115 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2116 GINT_TO_POINTER(TRUE));
2118 case GTK_JUSTIFY_CENTER:
2119 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2120 GINT_TO_POINTER(TRUE));
2122 case GTK_JUSTIFY_RIGHT:
2123 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2124 GINT_TO_POINTER(TRUE));
2131 if (buffer_format->cs.font) {
2132 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2133 GINT_TO_POINTER (buffer_format->font));
2135 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2136 if (buffer_format->cs.bullet) {
2137 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2138 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2140 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2142 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2144 g_free (buffer_format);
2145 g_free (current_format);
2147 /* Check dimming rules */
2148 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2149 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2153 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2155 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2157 ModestWindowPrivate *parent_priv;
2158 ModestMsgEditWindowPrivate *priv;
2160 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2161 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2163 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2164 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2165 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2166 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2168 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2169 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2170 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2173 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2175 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2176 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2178 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2179 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2181 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2182 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2185 switch (buffer_format->justification)
2187 case GTK_JUSTIFY_LEFT:
2188 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2190 case GTK_JUSTIFY_CENTER:
2191 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2193 case GTK_JUSTIFY_RIGHT:
2194 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2201 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2203 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2204 G_CALLBACK (modest_msg_edit_window_color_button_change),
2206 #ifdef MODEST_TOOLKIT_HILDON2
2207 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2209 gtk_color_button_set_color (GTK_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2211 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2212 G_CALLBACK (modest_msg_edit_window_color_button_change),
2215 if (priv->current_size_index != buffer_format->font_size) {
2219 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2220 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2224 priv->current_size_index = buffer_format->font_size;
2226 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2227 markup = g_strconcat ("<span font_family='Sans'>",
2228 size_text, "</span>", NULL);
2230 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2234 gtk_tree_path_free (path);
2237 if (priv->current_face_index != buffer_format->font) {
2241 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2242 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2246 priv->current_face_index = buffer_format->font;
2247 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2248 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2249 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2256 g_free (buffer_format);
2262 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2264 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2265 ModestMsgEditWindowPrivate *priv;
2266 GtkWidget *dialog = NULL;
2268 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2269 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2271 #ifdef MODEST_TOOLKIT_HILDON2
2272 dialog = hildon_color_chooser_new ();
2273 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2274 g_free (buffer_format);
2276 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2278 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2279 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2282 gtk_widget_destroy (dialog);
2284 dialog = gtk_color_selection_dialog_new (NULL);
2285 GtkWidget *selection;
2287 g_object_get (G_OBJECT (dialog), "color_selection", &selection, NULL);
2288 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2289 gtk_color_selection_set_previous_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2290 g_free (buffer_format);
2292 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2294 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION(selection), &col);
2295 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2298 gtk_widget_destroy (dialog);
2305 create_stream_for_uri (const gchar* uri)
2310 TnyStream *result = NULL;
2312 GnomeVFSHandle *handle = NULL;
2313 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2314 if (test == GNOME_VFS_OK) {
2315 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2316 /* Streams over OBEX (Bluetooth) are not seekable but
2317 * we expect them to be (we might need to read them
2318 * several times). So if this is a Bluetooth URI just
2319 * read the whole file into memory (this is not a fast
2320 * protocol so we can assume that these files are not
2321 * going to be very big) */
2322 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2323 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2324 TnyStream *memstream = tny_camel_mem_stream_new ();
2325 tny_stream_write_to_stream (vfssstream, memstream);
2326 g_object_unref (vfssstream);
2329 result = vfssstream;
2337 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2340 ModestMsgEditWindowPrivate *priv;
2341 GtkWidget *dialog = NULL;
2343 GSList *uris = NULL;
2344 GSList *uri_node = NULL;
2346 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2348 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2349 _("mcen_ia_select_inline_image_title"),
2350 (GtkWindow *) window,
2351 GTK_FILE_CHOOSER_ACTION_OPEN);
2352 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2354 #ifdef MODEST_TOOLKIT_HILDON2
2355 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2358 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2359 GTK_WINDOW (dialog), GTK_WINDOW (window));
2361 response = gtk_dialog_run (GTK_DIALOG (dialog));
2363 case GTK_RESPONSE_OK:
2365 gchar *current_folder;
2366 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2367 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2368 if (current_folder && current_folder != '\0') {
2370 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2371 current_folder, &err);
2373 g_debug ("Error storing latest used folder: %s", err->message);
2377 g_free (current_folder);
2383 gtk_widget_destroy (dialog);
2385 g_object_ref (window);
2386 /* The operation could take some time so allow the dialog to be closed */
2387 while (gtk_events_pending ())
2388 gtk_main_iteration ();
2390 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2392 GnomeVFSHandle *handle = NULL;
2393 GnomeVFSResult result;
2394 GtkTextIter position;
2395 GtkTextMark *insert_mark;
2397 uri = (const gchar *) uri_node->data;
2398 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2399 if (result == GNOME_VFS_OK) {
2401 GnomeVFSFileInfo *info;
2402 gchar *filename, *basename, *escaped_filename;
2403 TnyMimePart *mime_part;
2405 const gchar *mime_type = NULL;
2406 GnomeVFSURI *vfs_uri;
2407 guint64 stream_size;
2409 gnome_vfs_close (handle);
2410 vfs_uri = gnome_vfs_uri_new (uri);
2412 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2413 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2414 g_free (escaped_filename);
2415 gnome_vfs_uri_unref (vfs_uri);
2416 info = gnome_vfs_file_info_new ();
2418 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2419 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2421 mime_type = gnome_vfs_file_info_get_mime_type (info);
2423 mime_part = tny_platform_factory_new_mime_part
2424 (modest_runtime_get_platform_factory ());
2426 TnyStream *stream = create_stream_for_uri (uri);
2428 if (stream == NULL) {
2430 modest_platform_information_banner (NULL, NULL,
2431 _FM_OPENING_NOT_ALLOWED);
2433 g_object_unref (mime_part);
2434 gnome_vfs_file_info_unref (info);
2438 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2440 content_id = g_strdup_printf ("%d", priv->next_cid);
2441 tny_mime_part_set_content_id (mime_part, content_id);
2442 g_free (content_id);
2445 basename = g_path_get_basename (filename);
2446 tny_mime_part_set_filename (mime_part, basename);
2449 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2451 if (pixbuf != NULL) {
2452 priv->images_size += stream_size;
2453 priv->images_count ++;
2454 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2455 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2456 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2457 tny_mime_part_get_content_id (mime_part), pixbuf);
2458 g_object_unref (pixbuf);
2460 tny_list_prepend (priv->images, (GObject *) mime_part);
2461 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2463 modest_platform_information_banner (NULL, NULL,
2464 _("mail_ib_file_operation_failed"));
2468 g_object_unref (mime_part);
2469 gnome_vfs_file_info_unref (info);
2473 g_object_unref (window);
2477 on_attach_file_response (GtkDialog *dialog,
2481 GSList *uris = NULL;
2483 GnomeVFSFileSize total_size, allowed_size;
2484 ModestMsgEditWindow *window;
2485 ModestMsgEditWindowPrivate *priv;
2490 case GTK_RESPONSE_OK:
2492 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_ATTACH_FILE_PATH,
2499 current_folder, &err);
2501 g_debug ("Error storing latest used folder: %s", err->message);
2505 g_free (current_folder);
2512 window = MODEST_MSG_EDIT_WINDOW (user_data);
2513 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2515 /* allowed size is the maximum size - what's already there */
2516 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2517 &att_num, &att_size);
2518 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2521 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2523 const gchar *uri = (const gchar *) uri_node->data;
2526 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2528 if (total_size > allowed_size) {
2529 g_debug ("%s: total size: %u",
2530 __FUNCTION__, (unsigned int)total_size);
2533 allowed_size -= total_size;
2535 g_slist_foreach (uris, (GFunc) g_free, NULL);
2536 g_slist_free (uris);
2538 gtk_widget_destroy (GTK_WIDGET (dialog));
2542 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2544 GtkWidget *dialog = NULL;
2545 ModestMsgEditWindowPrivate *priv;
2548 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2550 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2552 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2555 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2556 _("mcen_ia_select_attachment_title"),
2557 (GtkWindow *) window,
2558 GTK_FILE_CHOOSER_ACTION_OPEN);
2559 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2560 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2561 if (conf_folder && conf_folder[0] != '\0') {
2562 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2565 /* Set the default folder to documents folder */
2566 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2567 #ifdef MODEST_TOOLKIT_HILDON2
2570 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2571 ".documents", NULL);
2574 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2575 g_free (docs_folder);
2577 g_free (conf_folder);
2578 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2579 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2580 GTK_WINDOW (dialog), GTK_WINDOW (window));
2582 /* Connect to response & show */
2583 g_signal_connect (dialog, "response",
2584 G_CALLBACK (on_attach_file_response), window);
2585 gtk_widget_show (dialog);
2590 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2592 GnomeVFSFileSize allowed_size)
2595 GnomeVFSHandle *handle = NULL;
2596 ModestMsgEditWindowPrivate *priv;
2597 GnomeVFSResult result;
2598 GnomeVFSFileSize size = 0;
2599 g_return_val_if_fail (window, 0);
2600 g_return_val_if_fail (uri, 0);
2602 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2604 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2605 if (result == GNOME_VFS_OK) {
2606 TnyMimePart *mime_part;
2608 const gchar *mime_type = NULL;
2610 gchar *escaped_filename;
2613 GnomeVFSFileInfo *info;
2614 GnomeVFSURI *vfs_uri;
2616 gnome_vfs_close (handle);
2617 vfs_uri = gnome_vfs_uri_new (uri);
2620 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2621 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2622 g_free (escaped_filename);
2623 gnome_vfs_uri_unref (vfs_uri);
2625 info = gnome_vfs_file_info_new ();
2627 if (gnome_vfs_get_file_info (uri,
2629 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2631 mime_type = gnome_vfs_file_info_get_mime_type (info);
2632 mime_part = tny_platform_factory_new_mime_part
2633 (modest_runtime_get_platform_factory ());
2635 /* try to get the attachment's size; this may fail for weird
2636 * file systems, like obex, upnp... */
2637 if (allowed_size != 0 &&
2638 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2640 if (size > allowed_size) {
2641 modest_platform_information_banner (NULL, NULL,
2642 _("mail_ib_error_attachment_size"));
2647 g_debug ("%s: could not get attachment size", __FUNCTION__);
2649 stream = create_stream_for_uri (uri);
2651 if (stream == NULL) {
2653 modest_platform_information_banner (NULL, NULL, _FM_OPENING_NOT_ALLOWED);
2655 g_object_unref (mime_part);
2657 gnome_vfs_file_info_unref (info);
2661 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2662 g_object_unref (stream);
2664 content_id = g_strdup_printf ("%d", priv->next_cid);
2665 tny_mime_part_set_content_id (mime_part, content_id);
2666 g_free (content_id);
2669 basename = g_path_get_basename (filename);
2670 tny_mime_part_set_filename (mime_part, basename);
2673 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2674 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2676 info->size == 0, info->size);
2677 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2678 gtk_widget_show_all (priv->attachments_caption);
2679 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2681 g_object_unref (mime_part);
2682 gnome_vfs_file_info_unref (info);
2689 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2692 ModestMsgEditWindowPrivate *priv;
2695 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2696 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2698 if (att_list == NULL) {
2699 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2700 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2701 g_object_unref (att_list);
2705 g_object_ref (att_list);
2708 if (tny_list_get_length (att_list) == 0) {
2709 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2711 gboolean dialog_response;
2712 gchar *message = NULL;
2713 gchar *filename = NULL;
2715 if (tny_list_get_length (att_list) == 1) {
2717 iter = tny_list_create_iterator (att_list);
2718 part = (TnyMimePart *) tny_iterator_get_current (iter);
2719 g_object_unref (iter);
2720 if (TNY_IS_MSG (part)) {
2721 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2723 filename = tny_header_dup_subject (header);
2724 g_object_unref (header);
2726 if (filename == NULL) {
2727 filename = g_strdup (_("mail_va_no_subject"));
2730 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2732 g_object_unref (part);
2734 filename = g_strdup ("");
2736 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2737 "emev_nc_delete_attachments",
2738 tny_list_get_length (att_list)), filename);
2741 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2745 if (dialog_response != GTK_RESPONSE_OK) {
2746 g_object_unref (att_list);
2750 for (iter = tny_list_create_iterator (att_list);
2751 !tny_iterator_is_done (iter);
2752 tny_iterator_next (iter)) {
2753 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2754 const gchar *att_id;
2755 tny_list_remove (priv->attachments, (GObject *) mime_part);
2757 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2759 if (tny_list_get_length (priv->attachments) == 0)
2760 gtk_widget_hide (priv->attachments_caption);
2761 att_id = tny_mime_part_get_content_id (mime_part);
2763 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2765 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2766 g_object_unref (mime_part);
2768 g_object_unref (iter);
2771 g_object_unref (att_list);
2773 /* if the last attachment has been removed, focus the Subject: field */
2774 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2775 gtk_widget_grab_focus (priv->subject_field);
2779 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2782 ModestMsgEditWindowPrivate *priv;
2785 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2787 gtk_color_button_get_color (GTK_COLOR_BUTTON(priv->font_color_button), &new_color);
2789 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2791 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2795 font_size_clicked (GtkToolButton *button,
2796 ModestMsgEditWindow *window)
2798 #ifdef MODEST_TOOLKIT_HILDON2
2799 ModestMsgEditWindowPrivate *priv;
2800 GtkWidget *selector, *dialog;
2802 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2804 selector = hildon_touch_selector_new ();
2805 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2806 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2808 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2809 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2810 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2812 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2816 WPTextBufferFormat format;
2818 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2820 memset (&format, 0, sizeof (format));
2821 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2823 format.cs.font_size = TRUE;
2824 format.cs.text_position = TRUE;
2825 format.cs.font = TRUE;
2826 format.font_size = new_index;
2827 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2829 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2830 GINT_TO_POINTER (new_index)))
2831 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2833 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2834 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2835 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2836 size_text, "</span>", NULL);
2838 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2842 gtk_widget_destroy (dialog);
2844 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2849 font_face_clicked (GtkToolButton *button,
2850 ModestMsgEditWindow *window)
2852 #ifdef MODEST_TOOLKIT_HILDON2
2853 ModestMsgEditWindowPrivate *priv;
2854 GtkWidget *selector, *dialog;
2855 GtkCellRenderer *renderer;
2857 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2859 selector = hildon_touch_selector_new ();
2860 renderer = gtk_cell_renderer_text_new ();
2861 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2862 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2863 renderer, "family", 0, "text", 0, NULL);
2864 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2866 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2867 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2868 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2870 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2871 gint new_font_index;
2875 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2876 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2877 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2881 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2883 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2884 GINT_TO_POINTER(new_font_index)))
2885 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2887 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2888 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2890 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2894 gtk_tree_path_free (path);
2897 gtk_widget_destroy (dialog);
2899 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2904 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2907 ModestMsgEditWindowPrivate *priv = NULL;
2908 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2910 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2911 if (!priv->update_caption_visibility)
2914 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2916 gtk_widget_show (priv->cc_caption);
2918 gtk_widget_hide (priv->cc_caption);
2920 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2924 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2927 ModestMsgEditWindowPrivate *priv = NULL;
2928 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2930 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2931 if (!priv->update_caption_visibility)
2934 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2936 gtk_widget_show (priv->bcc_caption);
2938 gtk_widget_hide (priv->bcc_caption);
2940 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2944 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2945 ModestRecptEditor *editor)
2947 ModestMsgEditWindowPrivate *priv;
2949 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2950 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2952 /* we check for low-mem; in that case, show a warning, and don't allow
2953 * for the addressbook
2955 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2958 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2960 if (editor == NULL) {
2961 GtkWidget *view_focus, *parent;
2962 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2964 /* This code should be kept in sync with ModestRecptEditor. The
2965 textview inside the recpt editor is the one that really gets the
2966 focus. As it's inside a scrolled window, and this one inside the
2967 hbox recpt editor inherits from, we'll need to go up in the
2968 hierarchy to know if the text view is part of the recpt editor
2969 or if it's a different text entry */
2970 parent = gtk_widget_get_parent (view_focus);
2971 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2972 editor = MODEST_RECPT_EDITOR (parent);
2975 editor = MODEST_RECPT_EDITOR (priv->to_field);
2978 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2982 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2984 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2986 modest_msg_edit_window_open_addressbook (window, NULL);
2990 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2991 gboolean show_toolbar)
2993 ModestWindowPrivate *parent_priv;
2994 ModestMsgEditWindowPrivate *priv;
2996 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2997 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2998 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
3000 /* We can not just use the code of
3001 modest_msg_edit_window_setup_toolbar because it has a
3002 mixture of both initialization and creation code. */
3004 gint current_format;
3005 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3006 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3007 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3008 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3010 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
3013 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3018 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
3019 TnyHeaderFlags priority_flags)
3021 ModestMsgEditWindowPrivate *priv;
3022 ModestWindowPrivate *parent_priv;
3024 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3026 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3027 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3029 if (priv->priority_flags != priority_flags) {
3030 GtkAction *priority_action = NULL;
3032 priv->priority_flags = priority_flags;
3034 switch (priority_flags) {
3035 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3036 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3037 MODEST_HEADER_ICON_HIGH,
3038 #ifdef MODEST_TOOLKIT_HILDON2
3039 HILDON_ICON_SIZE_SMALL
3041 GTK_ICON_SIZE_BUTTON
3044 gtk_widget_show (priv->priority_icon);
3045 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3046 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3048 case TNY_HEADER_FLAG_LOW_PRIORITY:
3049 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3050 MODEST_HEADER_ICON_LOW,
3051 #ifdef MODEST_TOOLKIT_HILDON2
3052 HILDON_ICON_SIZE_SMALL
3054 GTK_ICON_SIZE_BUTTON
3057 gtk_widget_show (priv->priority_icon);
3058 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3059 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3062 gtk_widget_hide (priv->priority_icon);
3063 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3064 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3067 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3068 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3070 gtk_widget_queue_resize (priv->subject_box);
3074 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3077 ModestMsgEditWindowPrivate *priv;
3078 ModestWindowPrivate *parent_priv;
3079 gint current_format;
3081 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3083 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3084 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3086 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3087 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3089 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3091 if (current_format != file_format) {
3092 switch (file_format) {
3093 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3094 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3095 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3096 update_signature (window, priv->last_from_account, priv->last_from_account);
3097 if (parent_priv->toolbar)
3098 gtk_widget_show (parent_priv->toolbar);
3100 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3103 response = modest_platform_run_confirmation_dialog (NULL, _("emev_nc_formatting_lost"));
3104 if (response == GTK_RESPONSE_OK) {
3105 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3106 if (parent_priv->toolbar)
3107 gtk_widget_hide (parent_priv->toolbar);
3109 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3110 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3115 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3116 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3117 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3122 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3124 #ifdef MODEST_TOOLKIT_HILDON2
3126 ModestMsgEditWindowPrivate *priv;
3127 WPTextBufferFormat oldfmt, fmt;
3128 gint old_position = 0;
3132 GdkColor *color = NULL;
3133 gboolean bold, bold_set, italic, italic_set;
3134 gboolean underline, underline_set;
3135 gboolean strikethrough, strikethrough_set;
3136 gboolean position_set;
3137 gboolean font_size_set, font_set, color_set;
3140 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3141 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3143 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3144 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3145 GTK_WINDOW(dialog), GTK_WINDOW (window));
3147 /* First we get the currently selected font information */
3148 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3150 switch (oldfmt.text_position) {
3151 case TEXT_POSITION_NORMAL:
3154 case TEXT_POSITION_SUPERSCRIPT:
3162 g_object_set (G_OBJECT (dialog),
3163 "bold", oldfmt.bold != FALSE,
3164 "bold-set", !oldfmt.cs.bold,
3165 "underline", oldfmt.underline != FALSE,
3166 "underline-set", !oldfmt.cs.underline,
3167 "italic", oldfmt.italic != FALSE,
3168 "italic-set", !oldfmt.cs.italic,
3169 "strikethrough", oldfmt.strikethrough != FALSE,
3170 "strikethrough-set", !oldfmt.cs.strikethrough,
3171 "color", &oldfmt.color,
3172 "color-set", !oldfmt.cs.color,
3173 "size", wp_font_size[oldfmt.font_size],
3174 "size-set", !oldfmt.cs.font_size,
3175 "position", old_position,
3176 "position-set", !oldfmt.cs.text_position,
3177 "family", wp_get_font_name (oldfmt.font),
3178 "family-set", !oldfmt.cs.font,
3181 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3182 GTK_WINDOW (dialog), GTK_WINDOW (window));
3183 gtk_widget_show_all (dialog);
3184 priv->font_dialog = dialog;
3185 response = gtk_dialog_run (GTK_DIALOG (dialog));
3186 priv->font_dialog = NULL;
3187 if (response == GTK_RESPONSE_OK) {
3189 g_object_get( dialog,
3191 "bold-set", &bold_set,
3192 "underline", &underline,
3193 "underline-set", &underline_set,
3195 "italic-set", &italic_set,
3196 "strikethrough", &strikethrough,
3197 "strikethrough-set", &strikethrough_set,
3199 "color-set", &color_set,
3201 "size-set", &font_size_set,
3202 "family", &font_name,
3203 "family-set", &font_set,
3204 "position", &position,
3205 "position-set", &position_set,
3210 if (response == GTK_RESPONSE_OK) {
3211 memset(&fmt, 0, sizeof(fmt));
3217 fmt.italic = italic;
3218 fmt.cs.italic = TRUE;
3220 if (underline_set) {
3221 fmt.underline = underline;
3222 fmt.cs.underline = TRUE;
3224 if (strikethrough_set) {
3225 fmt.strikethrough = strikethrough;
3226 fmt.cs.strikethrough = TRUE;
3231 ? TEXT_POSITION_NORMAL
3232 : ( ( position == 1 )
3233 ? TEXT_POSITION_SUPERSCRIPT
3234 : TEXT_POSITION_SUBSCRIPT );
3235 fmt.cs.text_position = TRUE;
3236 fmt.font_size = oldfmt.font_size;
3240 fmt.cs.color = TRUE;
3243 fmt.font = wp_get_font_index(font_name,
3248 if (font_size_set) {
3249 fmt.cs.font_size = TRUE;
3250 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3252 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3253 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3255 gtk_widget_destroy (dialog);
3257 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3262 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3264 ModestMsgEditWindowPrivate *priv;
3265 ModestWindowPrivate *parent_priv;
3266 gboolean was_rich_text, is_rich_text;
3268 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3269 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3270 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3272 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3274 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3276 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3278 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3280 gtk_widget_show (parent_priv->toolbar);
3282 gtk_widget_hide (parent_priv->toolbar);
3285 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3286 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3290 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3292 ModestMsgEditWindowPrivate *priv;
3294 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3295 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3297 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3299 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3300 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3305 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3307 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3309 priv->can_undo = can_undo;
3313 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3315 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3317 priv->can_redo = can_redo;
3321 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3323 ModestMsgEditWindowPrivate *priv;
3324 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3325 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3327 return priv->can_undo;
3331 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3333 ModestMsgEditWindowPrivate *priv;
3334 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3335 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3337 return priv->can_redo;
3342 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3345 GtkTextIter match_start, match_end;
3347 if (image_id == NULL)
3350 gtk_text_buffer_get_start_iter (buffer, &iter);
3352 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3353 GSList *tags = gtk_text_iter_get_tags (&match_start);
3355 for (node = tags; node != NULL; node = g_slist_next (node)) {
3356 GtkTextTag *tag = (GtkTextTag *) node->data;
3357 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3358 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3359 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3361 offset = gtk_text_iter_get_offset (&match_start);
3362 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3363 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3367 gtk_text_iter_forward_char (&iter);
3372 message_is_empty (ModestMsgEditWindow *window)
3374 ModestMsgEditWindowPrivate *priv = NULL;
3376 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3377 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3379 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3380 * so we can ignore markup.
3382 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3385 count = gtk_text_buffer_get_char_count (buf);
3391 msg_body_focus (GtkWidget *focus,
3392 GdkEventFocus *event,
3396 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3397 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3398 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3403 recpt_field_changed (GtkTextBuffer *buffer,
3404 ModestMsgEditWindow *editor)
3406 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3407 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3411 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3413 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3414 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3418 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3421 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3422 GtkTextBuffer *buffer;
3424 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3425 gtk_text_buffer_set_modified (buffer, modified);
3426 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3427 gtk_text_buffer_set_modified (buffer, modified);
3428 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3429 gtk_text_buffer_set_modified (buffer, modified);
3430 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3434 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3436 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3437 const char *account_name;
3438 GtkTextBuffer *buffer;
3440 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3441 if (gtk_text_buffer_get_modified (buffer))
3443 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3444 if (gtk_text_buffer_get_modified (buffer))
3446 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3447 if (gtk_text_buffer_get_modified (buffer))
3449 if (gtk_text_buffer_get_modified (priv->text_buffer))
3452 account_name = modest_selector_get_active_id (priv->from_field);
3453 if (priv->original_mailbox) {
3454 if (!account_name || strcmp (account_name, priv->original_mailbox))
3456 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3467 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3469 ModestMsgEditWindowPrivate *priv = NULL;
3470 GSList *address_list = NULL;
3472 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3473 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3475 /* check if there's no recipient added */
3476 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3477 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3478 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3479 /* no recipient contents, then select contacts */
3480 modest_msg_edit_window_open_addressbook (window, NULL);
3485 g_object_ref (window);
3486 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3487 (add_to_addressbook) ? &address_list : NULL)) {
3488 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3489 g_object_unref (window);
3492 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3493 (add_to_addressbook) ? &address_list : NULL)) {
3494 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3495 g_object_unref (window);
3498 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3499 (add_to_addressbook) ? &address_list : NULL)) {
3500 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3501 g_object_unref (window);
3505 /* Add contacts to address book */
3506 if (add_to_addressbook && address_list)
3507 modest_address_book_add_address_list (address_list);
3509 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3510 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3511 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3512 g_object_unref (window);
3519 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3521 GSList *recipients = NULL;
3522 ModestMsgEditWindowPrivate *priv;
3523 gchar *joined, *after_remove, *to, *cc, *bcc;
3525 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3527 /* First of all check names */
3528 if (!modest_msg_edit_window_check_names (self, FALSE))
3531 if (!modest_msg_edit_window_has_pending_addresses (self))
3534 /* Don't add the from obviously */
3535 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3536 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3537 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3539 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3544 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3547 recipients = modest_text_utils_split_addresses_list (after_remove);
3548 g_free (after_remove);
3551 /* Offer the user to add recipients to the address book */
3552 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3553 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3558 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3559 ModestMsgEditWindow *window)
3561 modest_msg_edit_window_offer_attach_file (window);
3565 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3567 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3569 return priv->clipboard_text;
3573 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3575 ModestMsgEditWindow *window)
3577 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3578 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3581 /* It could happen that the window was already closed */
3582 if (!GTK_WIDGET_VISIBLE (window))
3585 g_object_ref (window);
3586 text = gtk_clipboard_wait_for_text (selection_clipboard);
3588 if (priv->clipboard_text != NULL) {
3589 g_free (priv->clipboard_text);
3591 priv->clipboard_text = text;
3593 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3595 g_object_unref (window);
3598 static gboolean clipboard_owner_change_idle (gpointer userdata)
3600 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3601 ModestMsgEditWindowPrivate *priv;
3603 gdk_threads_enter ();
3604 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3605 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3607 priv->clipboard_owner_idle = 0;
3608 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3609 gdk_threads_leave ();
3615 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3617 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3618 if (priv->clipboard_owner_idle == 0) {
3619 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3620 clipboard_owner_change_idle,
3621 g_object_ref (window),
3627 subject_field_move_cursor (GtkEntry *entry,
3628 GtkMovementStep step,
3633 /* It could happen that the window was already closed */
3634 if (!GTK_WIDGET_VISIBLE (window))
3637 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3641 update_window_title (ModestMsgEditWindow *window)
3643 ModestMsgEditWindowPrivate *priv = NULL;
3644 const gchar *subject;
3646 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3647 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3648 if (subject == NULL || subject[0] == '\0')
3649 subject = _("mail_va_new_email");
3651 modest_window_set_title (MODEST_WINDOW (window), subject);
3657 body_insert_text (GtkTextBuffer *buffer,
3658 GtkTextIter *location,
3661 ModestMsgEditWindow *window)
3663 GtkTextIter end_iter;
3670 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3672 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3674 offset = gtk_text_iter_get_offset (&end_iter);
3675 line = gtk_text_iter_get_line (&end_iter);
3679 while (text_offset < text + len) {
3680 if (*text_offset == '\n')
3682 if (text_lines + line >= MAX_BODY_LINES) {
3683 len = text_offset - text;
3689 utf8_len = g_utf8_strlen (text, len);
3691 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3692 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3693 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3698 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3700 /* Prevent endless recursion */
3701 result = g_strndup (text, utf8_end - text);
3702 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3703 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3704 (gpointer) result, (gpointer) (utf8_end - text),
3706 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3710 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3711 if (priv->max_chars_banner == NULL) {
3712 #ifdef MODEST_TOOLKIT_HILDON2
3713 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3714 _CS_MAXIMUM_CHARACTERS_REACHED);
3715 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3722 subject_field_changed (GtkEditable *editable,
3723 ModestMsgEditWindow *window)
3725 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3726 update_window_title (window);
3727 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3728 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3729 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3732 subject_field_insert_text (GtkEditable *editable,
3734 gint new_text_length,
3736 ModestMsgEditWindow *window)
3738 GString *result = g_string_new ("");
3740 gint result_len = 0;
3741 const gchar *entry_text = NULL;
3744 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3745 old_length = g_utf8_strlen (entry_text, -1);
3747 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3748 gunichar c = g_utf8_get_char_validated (current, 8);
3749 /* Invalid unichar, stop */
3755 result = g_string_append_unichar (result, c);
3759 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3760 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3763 /* Prevent endless recursion */
3764 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3765 g_signal_emit_by_name (editable, "insert-text",
3766 (gpointer) result->str, (gpointer) result->len,
3767 (gpointer) position, (gpointer) window);
3768 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3772 if (result_len + old_length > 1000) {
3773 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3774 _CS_MAXIMUM_CHARACTERS_REACHED);
3776 g_string_free (result, TRUE);
3780 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3783 ModestMsgEditWindowPrivate *priv = NULL;
3785 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3786 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3788 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3791 gtk_widget_show_all (priv->isearch_toolbar);
3792 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3794 gtk_widget_hide_all (priv->isearch_toolbar);
3795 gtk_widget_grab_focus (priv->msg_body);
3800 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3802 GtkTextIter *match_start,
3803 GtkTextIter *match_end)
3805 GtkTextIter end_iter;
3806 gchar *str_casefold;
3809 gchar *range_casefold;
3812 gboolean result = FALSE;
3819 gtk_text_iter_forward_to_end (&end_iter);
3821 str_casefold = g_utf8_casefold (str, -1);
3822 str_chars_n = strlen (str);
3824 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3825 range_casefold = g_utf8_casefold (range_text, -1);
3826 range_chars_n = strlen (range_casefold);
3828 if (range_chars_n < str_chars_n) {
3829 g_free (str_casefold);
3830 g_free (range_text);
3831 g_free (range_casefold);
3835 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3836 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3837 if (!g_utf8_collate (range_subtext, str_casefold)) {
3838 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3840 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3841 match_start, match_end, NULL)) {
3842 g_debug ("Matched string with collate, but not matched in model");
3844 g_free (found_text);
3846 g_free (range_subtext);
3850 g_free (str_casefold);
3851 g_free (range_text);
3852 g_free (range_casefold);
3859 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
3860 ModestMsgEditWindow *window)
3862 const gchar *current_search = NULL;
3863 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3865 GtkTextIter selection_start, selection_end;
3866 GtkTextIter match_start, match_end;
3867 gboolean continue_search = FALSE;
3869 if (message_is_empty (window)) {
3870 g_free (priv->last_search);
3871 priv->last_search = NULL;
3872 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3876 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
3877 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3878 g_free (priv->last_search);
3879 priv->last_search = NULL;
3880 /* Information banner about empty search */
3881 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
3885 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3886 continue_search = TRUE;
3888 g_free (priv->last_search);
3889 priv->last_search = g_strdup (current_search);
3892 if (continue_search) {
3893 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3894 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3895 &match_start, &match_end);
3897 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_COMPLETE);
3899 GtkTextIter buffer_start;
3900 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3901 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3902 &match_start, &match_end);
3904 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_NO_MATCHES);
3907 /* Mark as selected the string found in search */
3909 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3910 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3911 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3913 g_free (priv->last_search);
3914 priv->last_search = NULL;
3919 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3921 ModestMsgEditWindowPrivate *priv;
3923 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3928 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3931 ModestMsgEditWindowPrivate *priv;
3933 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3938 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
3939 ModestMsgEditWindow *window)
3941 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
3945 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3948 ModestMsgEditWindowPrivate *priv;
3949 TnyHeader *header = NULL;
3951 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3952 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3954 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3956 if (priv->draft_msg != NULL) {
3957 g_object_unref (priv->draft_msg);
3960 if (draft != NULL) {
3961 g_object_ref (draft);
3962 header = tny_msg_get_header (draft);
3963 if (priv->msg_uid) {
3964 g_free (priv->msg_uid);
3965 priv->msg_uid = NULL;
3967 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3970 priv->draft_msg = draft;
3974 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3975 GtkTextIter *start, GtkTextIter *end,
3978 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3979 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3982 if (tag == NULL) return;
3983 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3984 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3985 replace_with_images (window, priv->images);
3990 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3993 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3995 g_return_if_fail (TNY_IS_MIME_PART (part));
3996 tny_list_prepend (priv->attachments, (GObject *) part);
3997 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3998 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3999 gtk_widget_show_all (priv->attachments_caption);
4000 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
4004 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
4006 ModestMsgEditWindowPrivate *priv;
4008 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
4009 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4011 return priv->msg_uid;
4015 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
4016 ModestMsgEditWindowWidgetType widget_type)
4018 ModestMsgEditWindowPrivate *priv;
4020 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
4021 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
4023 switch (widget_type) {
4024 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
4025 return priv->msg_body;
4027 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
4028 return priv->to_field;
4030 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
4031 return priv->cc_field;
4033 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4034 return priv->bcc_field;
4036 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4037 return priv->subject_field;
4039 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4040 return priv->attachments_view;
4048 remove_tags (WPTextBuffer *buffer)
4050 GtkTextIter start, end;
4052 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4053 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4055 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4059 on_account_removed (TnyAccountStore *account_store,
4060 TnyAccount *account,
4063 /* Do nothing if it's a store account, because we use the
4064 transport to send the messages */
4065 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4066 const gchar *parent_acc = NULL;
4067 const gchar *our_acc = NULL;
4069 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4070 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4071 /* Close this window if I'm showing a message of the removed account */
4072 if (strcmp (parent_acc, our_acc) == 0)
4073 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4078 update_signature (ModestMsgEditWindow *self,
4079 const gchar *old_account,
4080 const gchar *new_account)
4082 ModestMsgEditWindowPrivate *priv;
4083 gboolean has_old_signature, has_new_signature;
4085 ModestAccountMgr *mgr;
4088 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4090 gtk_text_buffer_begin_user_action (priv->text_buffer);
4092 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4093 mgr = modest_runtime_get_account_mgr ();
4097 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4098 if (has_old_signature) {
4099 GtkTextIter match_start, match_end;
4101 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4102 seems that the search has some problems
4103 with the blank space at the end */
4104 if (gtk_text_iter_forward_search (&iter, "--",
4105 GTK_TEXT_SEARCH_TEXT_ONLY,
4106 &match_start, NULL, NULL)) {
4107 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4108 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4110 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4111 &match_start, &match_end, NULL)) {
4115 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4120 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4121 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4122 if (has_new_signature) {
4125 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4126 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4128 is_rich = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
4130 WPTextBufferFormat *fmt;
4131 GdkColor style_color;
4132 if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
4133 gdk_color_parse ("grey", &style_color);
4135 fmt = g_new0 (WPTextBufferFormat, 1);
4136 fmt->color = style_color;
4137 fmt->cs.color = 0x1;
4138 wp_text_buffer_insert_with_attribute (WP_TEXT_BUFFER (priv->text_buffer), &iter,
4142 g_free (full_signature);
4144 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4148 gtk_text_buffer_end_user_action (priv->text_buffer);
4151 static void update_branding (ModestMsgEditWindow *self,
4152 const gchar *new_account)
4154 ModestMsgEditWindowPrivate *priv;
4155 ModestAccountMgr *mgr;
4156 const GdkPixbuf *new_icon = NULL;
4157 gchar *new_label = NULL;
4158 gboolean show = FALSE;
4160 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4162 mgr = modest_runtime_get_account_mgr ();
4164 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4166 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4167 gtk_widget_show (priv->brand_icon);
4170 gtk_widget_hide (priv->brand_icon);
4173 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4174 gtk_widget_show (priv->brand_label);
4178 gtk_widget_hide (priv->brand_label);
4182 gtk_widget_show (priv->brand_container);
4184 gtk_widget_hide (priv->brand_container);
4188 from_field_changed (GtkWidget *button,
4189 ModestMsgEditWindow *self)
4191 ModestMsgEditWindowPrivate *priv;
4192 gchar *old_account, *new_account;
4194 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4196 old_account = priv->last_from_account;
4197 new_account = modest_selector_get_active_id (priv->from_field);
4200 g_warning ("%s, could not get the new account", __FUNCTION__);
4204 /* If the From is the same do nothing */
4205 if (old_account && new_account && !strcmp (old_account, new_account))
4208 priv->last_from_account = new_account;
4210 update_signature (self, old_account, new_account);
4211 update_branding (self, new_account);
4215 typedef struct _MessageSettingsHelper {
4216 ModestMsgEditWindow *window;
4217 GSList *priority_group;
4218 GSList *format_group;
4219 GtkToggleButton *current_priority;
4220 GtkToggleButton *current_format;
4221 } MessageSettingsHelper;
4224 on_priority_toggle (GtkToggleButton *button,
4225 MessageSettingsHelper *helper)
4228 ModestMsgEditWindowPrivate *priv;
4230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4231 if (gtk_toggle_button_get_active (button)) {
4233 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4234 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4235 if ((node_button != button) &&
4236 gtk_toggle_button_get_active (node_button)) {
4237 gtk_toggle_button_set_active (node_button, FALSE);
4240 helper->current_priority = button;
4242 gboolean found = FALSE;
4243 /* If no one is active, activate it again */
4244 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4245 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4246 if (gtk_toggle_button_get_active (node_button)) {
4252 gtk_toggle_button_set_active (button, TRUE);
4258 on_format_toggle (GtkToggleButton *button,
4259 MessageSettingsHelper *helper)
4262 ModestMsgEditWindowPrivate *priv;
4264 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4265 if (gtk_toggle_button_get_active (button)) {
4267 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4268 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4269 if ((node_button != button) &&
4270 gtk_toggle_button_get_active (node_button)) {
4271 gtk_toggle_button_set_active (node_button, FALSE);
4274 helper->current_format = button;
4276 gboolean found = FALSE;
4277 /* If no one is active, activate it again */
4278 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4279 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4280 if (gtk_toggle_button_get_active (node_button)) {
4286 gtk_toggle_button_set_active (button, TRUE);
4293 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4298 GtkWidget *priority_hbox;
4299 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4300 GtkWidget *captioned;
4301 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4302 GtkWidget *format_hbox;
4303 GtkWidget *html_toggle, *text_toggle;
4304 ModestMsgEditWindowPrivate *priv;
4305 MessageSettingsHelper helper = {0,};
4307 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4308 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4309 helper.window = window;
4310 helper.priority_group = NULL;
4311 helper.format_group = NULL;
4313 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4314 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4316 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4317 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4318 _HL_DONE, GTK_RESPONSE_ACCEPT, NULL);
4319 vbox = gtk_vbox_new (FALSE, 0);
4320 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4321 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4322 gtk_container_add (GTK_CONTAINER (align), vbox);
4323 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4324 gtk_widget_show (align);
4325 gtk_widget_show (vbox);
4327 /* Priority toggles */
4328 priority_hbox = gtk_hbox_new (TRUE, 0);
4329 #ifdef MODEST_TOOLKIT_HILDON2
4330 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4332 high_toggle = gtk_toggle_button_new ();
4334 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4335 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4336 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4337 #ifdef MODEST_TOOLKIT_HILDON2
4338 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4340 medium_toggle = gtk_toggle_button_new ();
4342 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4343 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4344 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4345 #ifdef MODEST_TOOLKIT_HILDON2
4346 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4348 low_toggle = gtk_toggle_button_new ();
4350 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4351 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4352 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4353 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4354 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4355 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4356 gtk_widget_show_all (priority_hbox);
4357 captioned = modest_toolkit_utils_create_captioned (title_sizegroup, value_sizegroup,
4358 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4359 gtk_widget_show (captioned);
4360 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4362 /* format toggles */
4363 format_hbox = gtk_hbox_new (TRUE, 0);
4364 #ifdef MODEST_TOOLKIT_HILDON2
4365 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4367 html_toggle = gtk_toggle_button_new ();
4369 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4370 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4371 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4372 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4373 #ifdef MODEST_TOOLKIT_HILDON2
4374 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4376 text_toggle = gtk_toggle_button_new ();
4378 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4379 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4380 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4381 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4382 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4383 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4384 gtk_widget_show_all (format_hbox);
4385 gtk_widget_show (format_hbox);
4386 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4389 g_object_unref (title_sizegroup);
4390 g_object_unref (value_sizegroup);
4392 /* Set current values */
4393 switch (priv->priority_flags) {
4394 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4395 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4396 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4398 case TNY_HEADER_FLAG_LOW_PRIORITY:
4399 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4400 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4403 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4404 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4408 switch (modest_msg_edit_window_get_format (window)) {
4409 case MODEST_MSG_EDIT_FORMAT_TEXT:
4410 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4411 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4413 case MODEST_MSG_EDIT_FORMAT_HTML:
4415 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4416 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4420 /* Signal connects */
4421 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4422 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4423 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4424 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4425 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4427 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4428 GTK_WINDOW (dialog), GTK_WINDOW (window));
4430 /* Save settings if the user clicked on done */
4431 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4432 TnyHeaderFlags flags;
4433 ModestMsgEditFormat old_format, new_format;
4435 /* Set priority flags */
4436 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4437 if (priv->priority_flags != flags)
4438 modest_msg_edit_window_set_priority_flags (window, flags);
4440 /* Set edit format */
4441 old_format = modest_msg_edit_window_get_format (window);
4442 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4443 if (old_format != new_format) {
4444 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4445 modest_msg_edit_window_set_file_format (window, file_format);
4449 gtk_widget_destroy (dialog);
4450 g_slist_free (helper.priority_group);
4454 on_message_settings (GtkAction *action,
4455 ModestMsgEditWindow *window)
4457 modest_msg_edit_window_show_msg_settings_dialog (window);
4461 on_cc_button_toggled (GtkWidget *button,
4462 ModestMsgEditWindow *window)
4464 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4466 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4467 modest_togglable_get_active (button));
4471 on_bcc_button_toggled (GtkWidget *button,
4472 ModestMsgEditWindow *window)
4474 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4476 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4477 modest_togglable_get_active (button));
4481 setup_menu (ModestMsgEditWindow *self)
4483 ModestMsgEditWindowPrivate *priv = NULL;
4485 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4487 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4489 /* Settings menu buttons */
4490 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4491 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4493 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4494 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4495 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4496 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4497 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4498 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4500 priv->cc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4501 _("mcen_me_editor_showcc"));
4502 modest_togglable_set_active (priv->cc_button,
4504 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4505 gtk_widget_show (priv->cc_button);
4506 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4507 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4509 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4510 _("mcen_me_editor_showbcc"));
4511 gtk_widget_show (priv->bcc_button);
4512 modest_togglable_set_active (priv->bcc_button,
4514 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4516 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4517 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4519 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4520 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4521 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4522 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4523 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4525 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4526 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4527 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4528 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4529 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4531 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4532 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4537 emit_open_addressbook (GtkButton *button,
4538 ModestRecptEditor *editor)
4540 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4544 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4545 const gchar *label, GtkWidget *control)
4547 GtkWidget *abook_button;
4550 GtkWidget *label_widget;
4552 box = gtk_hbox_new (FALSE, 0);
4554 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4555 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4557 #ifdef MODEST_TOOLKIT_HILDON2
4558 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4560 abook_button = gtk_button_new ();
4562 label_widget = gtk_label_new (label);
4563 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4564 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4566 gtk_container_add (GTK_CONTAINER (align), abook_button);
4567 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4568 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4569 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4570 if (title_size_group)
4571 gtk_size_group_add_widget (title_size_group, label_widget);
4572 if (value_size_group)
4573 gtk_size_group_add_widget (value_size_group, control);
4575 g_signal_connect (G_OBJECT (abook_button), "clicked",
4576 G_CALLBACK (emit_open_addressbook), control);
4582 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4584 ModestMsgEditWindowPrivate *priv = NULL;
4586 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4588 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4589 priv->max_chars_banner = NULL;
4593 has_pending_addresses (ModestRecptEditor *recpt_editor)
4595 const gchar *recipients = NULL;
4596 GSList *start_indexes = NULL, *end_indexes = NULL;
4597 GSList *current_start, *current_end;
4598 GtkTextBuffer *buffer;
4599 gint offset_delta = 0;
4601 gboolean has_recipients_to_add = FALSE;
4603 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4604 last_length = g_utf8_strlen (recipients, -1);
4605 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4610 current_start = start_indexes;
4611 current_end = end_indexes;
4612 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4614 while (current_start && !has_recipients_to_add) {
4616 gchar *start_ptr, *end_ptr;
4617 gint start_pos, end_pos;
4619 start_pos = (*((gint*) current_start->data)) + offset_delta;
4620 end_pos = (*((gint*) current_end->data)) + offset_delta;
4622 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4623 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4625 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4627 if (modest_text_utils_validate_recipient (address, NULL)) {
4628 if (!modest_address_book_has_address (address)) {
4629 has_recipients_to_add = TRUE;
4632 current_start = g_slist_next (current_start);
4633 current_end = g_slist_next (current_end);
4635 return has_recipients_to_add;
4639 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4641 ModestMsgEditWindowPrivate *priv = NULL;
4643 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4645 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4647 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4648 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4649 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))