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_FONT_SIZE 3
87 #define DEFAULT_FONT 2
88 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
89 #define DEFAULT_MAIN_VBOX_SPACING 0
90 #define SUBJECT_MAX_LENGTH 1000
91 #define IMAGE_MAX_WIDTH 560
92 #define DEFAULT_FONT_SCALE 1.5
93 #define ATTACHMENT_BUTTON_WIDTH 118
94 #define MAX_FROM_VALUE 36
95 #define MAX_BODY_LENGTH 128*1024
96 #define MAX_BODY_LINES 2048
98 static gboolean is_wp_text_buffer_started = FALSE;
100 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
101 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
102 static void modest_msg_edit_window_finalize (GObject *obj);
104 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
105 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
106 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
108 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
109 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
110 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
111 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
112 GtkTextIter *start, GtkTextIter *end,
114 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
115 static void body_insert_text (GtkTextBuffer *buffer,
116 GtkTextIter *location,
119 ModestMsgEditWindow *window);
120 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
121 static void subject_field_insert_text (GtkEditable *editable,
123 gint new_text_length,
125 ModestMsgEditWindow *window);
126 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
128 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
130 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
131 ModestRecptEditor *editor);
132 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
133 ModestMsgEditWindow *window);
135 /* ModestWindow methods implementation */
136 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
137 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
138 gboolean show_toolbar);
139 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
141 ModestMsgEditWindow *window);
142 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
143 static void subject_field_move_cursor (GtkEntry *entry,
144 GtkMovementStep step,
148 static void update_window_title (ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
152 ModestMsgEditWindow *window);
153 static void modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
154 ModestMsgEditWindow *window);
155 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
157 GtkTextIter *match_start,
158 GtkTextIter *match_end);
160 static void remove_tags (WPTextBuffer *buffer);
162 static void on_account_removed (TnyAccountStore *account_store,
166 static void init_window (ModestMsgEditWindow *obj);
168 gboolean scroll_drag_timeout (gpointer userdata);
169 static void correct_scroll (ModestMsgEditWindow *w);
170 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
171 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
172 ModestMsgEditWindow *userdata);
173 static void text_buffer_mark_set (GtkTextBuffer *buffer,
176 ModestMsgEditWindow *userdata);
177 static void on_message_settings (GtkAction *action,
178 ModestMsgEditWindow *window);
179 static void setup_menu (ModestMsgEditWindow *self);
181 static void from_field_changed (GtkWidget *button,
182 ModestMsgEditWindow *self);
183 static void font_size_clicked (GtkToolButton *button,
184 ModestMsgEditWindow *window);
185 static void font_face_clicked (GtkToolButton *button,
186 ModestMsgEditWindow *window);
187 static void update_signature (ModestMsgEditWindow *self,
188 const gchar *old_account,
189 const gchar *new_account);
190 static void update_branding (ModestMsgEditWindow *self,
191 const gchar *new_account);
192 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
193 const gchar *label, GtkWidget *control);
194 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
195 static void DEBUG_BUFFER (WPTextBuffer *buffer)
199 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
201 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
202 while (!gtk_text_iter_is_end (&iter)) {
203 GString *output = g_string_new ("");
204 GSList *toggled_tags;
207 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
208 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
209 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
210 GtkTextTag *tag = (GtkTextTag *) node->data;
212 g_object_get (G_OBJECT (tag), "name", &name, NULL);
213 output = g_string_append (output, name);
214 g_string_append (output, " ");
216 output = g_string_append (output, "] OPENED [ ");
217 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
218 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
219 GtkTextTag *tag = (GtkTextTag *) node->data;
221 g_object_get (G_OBJECT (tag), "name", &name, NULL);
222 output = g_string_append (output, name);
223 g_string_append (output, " ");
225 output = g_string_append (output, "]\n");
226 g_debug ("%s", output->str);
227 g_string_free (output, TRUE);
228 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
230 g_debug ("END BUFFER");
234 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
235 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
239 /* static gboolean */
240 /* on_key_pressed (GtkWidget *self, */
241 /* GdkEventKey *event, */
242 /* gpointer user_data); */
244 /* list my signals */
251 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
252 struct _ModestMsgEditWindowPrivate {
254 GtkWidget *header_box;
256 ModestPairList *from_field_protos;
257 GtkWidget *from_field;
258 gchar *last_from_account;
259 gchar *original_account_name;
264 gchar *original_mailbox;
268 GtkWidget *bcc_field;
269 GtkWidget *subject_field;
270 GtkWidget *attachments_view;
271 GtkWidget *priority_icon;
272 GtkWidget *subject_box;
273 GtkWidget *send_button;
275 GtkWidget *cc_caption;
276 GtkWidget *bcc_caption;
277 gboolean update_caption_visibility;
278 GtkWidget *attachments_caption;
280 GtkTextBuffer *text_buffer;
282 GtkWidget *font_size_toolitem;
283 GtkWidget *font_face_toolitem;
284 GtkWidget *font_color_button;
285 GtkWidget *font_color_toolitem;
286 GSList *font_items_group;
287 GtkTreeModel *faces_model;
288 gint current_face_index;
289 GtkWidget *font_tool_button_label;
290 GtkTreeModel *sizes_model;
291 gint current_size_index;
292 GtkWidget *size_tool_button_label;
294 GtkWidget *isearch_toolbar;
297 GtkWidget *font_dialog;
299 GtkWidget *scrollable;
300 guint correct_scroll_idle;
301 guint scroll_drag_timeout_id;
305 TnyList *attachments;
310 TnyHeaderFlags priority_flags;
312 gboolean can_undo, can_redo;
313 gulong clipboard_change_handler_id;
314 gulong default_clipboard_change_handler_id;
315 gulong account_removed_handler_id;
316 guint clipboard_owner_idle;
317 gchar *clipboard_text;
326 GtkWidget *cc_button;
327 GtkWidget *bcc_button;
329 GtkWidget *max_chars_banner;
331 GtkWidget *brand_icon;
332 GtkWidget *brand_label;
333 GtkWidget *brand_container;
336 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
337 MODEST_TYPE_MSG_EDIT_WINDOW, \
338 ModestMsgEditWindowPrivate))
340 static GtkWindowClass *parent_class = NULL;
342 /* uncomment the following if you have defined any signals */
343 /* static guint signals[LAST_SIGNAL] = {0}; */
346 modest_msg_edit_window_get_type (void)
348 static GType my_type = 0;
350 static const GTypeInfo my_info = {
351 sizeof(ModestMsgEditWindowClass),
352 NULL, /* base init */
353 NULL, /* base finalize */
354 (GClassInitFunc) modest_msg_edit_window_class_init,
355 NULL, /* class finalize */
356 NULL, /* class data */
357 sizeof(ModestMsgEditWindow),
359 (GInstanceInitFunc) modest_msg_edit_window_init,
362 my_type = g_type_register_static (
363 #ifdef MODEST_TOOLKIT_HILDON2
364 MODEST_TYPE_HILDON2_WINDOW,
368 "ModestMsgEditWindow",
376 save_state (ModestWindow *self)
378 modest_widget_memory_save (modest_runtime_get_conf(),
379 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
384 restore_settings (ModestMsgEditWindow *self)
386 ModestConf *conf = NULL;
388 conf = modest_runtime_get_conf ();
390 /* Dim at start clipboard actions */
391 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
396 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
398 GObjectClass *gobject_class;
399 ModestWindowClass *modest_window_class;
400 gobject_class = (GObjectClass*) klass;
401 modest_window_class = (ModestWindowClass*) klass;
403 parent_class = g_type_class_peek_parent (klass);
404 gobject_class->finalize = modest_msg_edit_window_finalize;
406 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
407 modest_window_class->save_state_func = save_state;
408 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
410 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
414 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
416 ModestMsgEditWindowPrivate *priv;
417 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
419 priv->msg_body = NULL;
420 priv->from_field = NULL;
421 priv->to_field = NULL;
422 priv->cc_field = NULL;
423 priv->bcc_field = NULL;
424 priv->subject_field = NULL;
425 priv->attachments = TNY_LIST (tny_simple_list_new ());
426 priv->images = TNY_LIST (tny_simple_list_new ());
427 priv->images_size = 0;
428 priv->images_count = 0;
431 priv->cc_caption = NULL;
432 priv->bcc_caption = NULL;
433 priv->update_caption_visibility = FALSE;
435 priv->priority_flags = 0;
437 priv->isearch_toolbar = NULL;
438 priv->last_search = NULL;
440 priv->draft_msg = NULL;
441 priv->outbox_msg = NULL;
442 priv->msg_uid = NULL;
444 priv->can_undo = FALSE;
445 priv->can_redo = FALSE;
446 priv->clipboard_change_handler_id = 0;
447 priv->default_clipboard_change_handler_id = 0;
448 priv->account_removed_handler_id = 0;
449 priv->clipboard_owner_idle = 0;
450 priv->clipboard_text = NULL;
453 priv->scroll_drag_timeout_id = 0;
454 priv->correct_scroll_idle = 0;
455 priv->last_upper = 0.0;
457 priv->font_dialog = NULL;
458 priv->app_menu = NULL;
460 priv->references = NULL;
461 priv->in_reply_to = NULL;
462 priv->max_chars_banner = NULL;
464 if (!is_wp_text_buffer_started) {
465 is_wp_text_buffer_started = TRUE;
466 wp_text_buffer_library_init ();
470 #ifdef MODEST_TOOLKIT_HILDON2
471 hildon_program_add_window (hildon_program_get_instance(),
477 multimailbox_get_default_mailbox (const gchar *account_name)
479 gchar *transport_account;
480 gchar *result = NULL;
482 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
484 TNY_ACCOUNT_TYPE_TRANSPORT);
485 if (transport_account) {
487 ModestProtocolRegistry *registry;
489 registry = modest_runtime_get_protocol_registry ();
491 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
492 MODEST_ACCOUNT_PROTO, TRUE);
494 ModestProtocol *protocol =
495 modest_protocol_registry_get_protocol_by_name (registry,
496 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
498 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
499 ModestPairList *pair_list;
501 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
504 ModestPair *pair = (ModestPair *) pair_list->data;
505 result = g_strdup ((const gchar *) pair->first);
506 modest_pair_list_free (pair_list);
517 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
519 static ModestPairList*
520 get_transports (void)
522 GSList *transports = NULL;
524 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
525 GSList *accounts = modest_account_mgr_account_names (account_mgr,
526 TRUE /* only enabled accounts. */);
528 GSList *cursor = accounts;
530 gchar *account_name = cursor->data;
533 gchar *transport_account;
534 gboolean multi_mailbox = FALSE;
535 ModestProtocol *protocol = NULL;
537 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
539 transport_account = modest_account_mgr_get_server_account_name
540 (modest_runtime_get_account_mgr (),
542 TNY_ACCOUNT_TYPE_TRANSPORT);
543 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
544 ModestPairList *pair_list;
545 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
548 transports = g_slist_concat (transports, pair_list);
549 multi_mailbox = TRUE;
554 if (!multi_mailbox) {
555 gchar *from_string = NULL;
557 from_string = modest_account_mgr_get_from_string (account_mgr,
559 if (from_string && account_name) {
560 gchar *name = account_name;
561 ModestPair *pair = modest_pair_new ((gpointer) name,
562 (gpointer) from_string , TRUE);
563 transports = g_slist_prepend (transports, pair);
568 cursor = cursor->next;
570 g_slist_free (accounts); /* only free the accounts, not the elements,
571 * because they are used in the pairlist */
575 static void window_focus (GtkWindow *window,
579 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
583 scroll_drag_timeout (gpointer userdata)
585 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
586 ModestMsgEditWindowPrivate *priv;
588 /* It could happen that the window was already closed */
589 if (!GTK_WIDGET_VISIBLE (win))
592 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
594 correct_scroll_without_drag_check (win, TRUE);
596 priv->scroll_drag_timeout_id = 0;
602 correct_scroll_without_drag_check_idle (gpointer userdata)
604 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
605 ModestMsgEditWindowPrivate *priv;
607 GdkRectangle rectangle;
608 gint offset_min, offset_max;
612 /* It could happen that the window was already closed */
613 if (!GTK_WIDGET_VISIBLE (w))
616 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
618 insert = gtk_text_buffer_get_insert (priv->text_buffer);
619 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
621 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
622 offset_min = priv->msg_body->allocation.y + rectangle.y;
623 offset_max = offset_min + rectangle.height;
625 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
626 offset_min = MAX (offset_min - 48, 0);
627 offset_max = MIN (offset_max + 48, vadj->upper);
629 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
631 priv->correct_scroll_idle = 0;
636 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
638 ModestMsgEditWindowPrivate *priv;
640 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
642 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
645 if (priv->correct_scroll_idle > 0) {
649 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
650 (GSourceFunc) correct_scroll_without_drag_check_idle,
656 correct_scroll (ModestMsgEditWindow *w)
658 ModestMsgEditWindowPrivate *priv;
660 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
661 if (gtk_grab_get_current () == priv->msg_body) {
662 if (priv->scroll_drag_timeout_id == 0) {
663 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
665 (GSourceFunc) scroll_drag_timeout,
672 correct_scroll_without_drag_check (w, TRUE);
676 text_buffer_end_user_action (GtkTextBuffer *buffer,
677 ModestMsgEditWindow *userdata)
680 correct_scroll (userdata);
684 text_buffer_mark_set (GtkTextBuffer *buffer,
687 ModestMsgEditWindow *userdata)
689 gtk_text_buffer_begin_user_action (buffer);
690 gtk_text_buffer_end_user_action (buffer);
694 cut_clipboard_check (GtkTextView *text_view,
697 GtkTextBuffer *buffer;
699 buffer = gtk_text_view_get_buffer (text_view);
700 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
701 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
706 copy_clipboard_check (GtkTextView *text_view,
709 GtkTextBuffer *buffer;
711 buffer = gtk_text_view_get_buffer (text_view);
712 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
713 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
718 attachment_deleted (ModestAttachmentsView *attachments_view,
721 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
726 body_size_request (GtkWidget *body,
730 /* Make sure the body always get at least 70 pixels */
731 if (req->height < 70)
736 connect_signals (ModestMsgEditWindow *obj)
738 ModestMsgEditWindowPrivate *priv;
740 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
742 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
743 G_CALLBACK (text_buffer_refresh_attributes), obj);
744 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
745 G_CALLBACK (text_buffer_can_undo), obj);
746 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
747 G_CALLBACK (text_buffer_can_redo), obj);
748 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
749 G_CALLBACK (body_changed), obj);
750 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
751 G_CALLBACK (body_insert_text), obj);
752 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
753 G_CALLBACK (body_changed), obj);
754 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
755 G_CALLBACK (text_buffer_end_user_action), obj);
756 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
757 G_CALLBACK (text_buffer_mark_set), obj);
758 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
759 G_CALLBACK (text_buffer_apply_tag), obj);
760 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
761 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
762 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
763 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
764 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
765 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
767 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
768 G_CALLBACK (modest_ui_actions_on_send), obj);
770 if (GTK_IS_COMBO_BOX (priv->from_field)) {
771 g_signal_connect (G_OBJECT (priv->from_field), "changed",
772 G_CALLBACK (from_field_changed), obj);
774 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
775 G_CALLBACK (from_field_changed), obj);
778 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
779 G_CALLBACK (msg_body_focus), obj);
780 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
781 G_CALLBACK (msg_body_focus), obj);
782 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
783 G_CALLBACK (body_size_request), obj);
784 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
785 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
786 "changed", G_CALLBACK (recpt_field_changed), obj);
787 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
788 "changed", G_CALLBACK (recpt_field_changed), obj);
789 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
790 "changed", G_CALLBACK (recpt_field_changed), obj);
791 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
792 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
793 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
795 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
796 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
797 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
798 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_close), obj);
800 priv->clipboard_change_handler_id =
801 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
802 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
803 priv->default_clipboard_change_handler_id =
804 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
805 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
807 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
808 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
809 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
813 init_wp_text_view_style ()
815 static gboolean initialized = FALSE;
818 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
824 init_window (ModestMsgEditWindow *obj)
826 GtkWidget *to_caption, *subject_caption;
827 GtkWidget *main_vbox;
828 ModestMsgEditWindowPrivate *priv;
829 GtkActionGroup *action_group;
830 ModestWindowPrivate *parent_priv;
831 GError *error = NULL;
833 GtkSizeGroup *title_size_group;
834 GtkSizeGroup *value_size_group;
835 GtkWidget *window_box;
836 GtkWidget *window_align;
837 #if (GTK_MINOR_VERSION >= 10)
838 GdkAtom deserialize_type;
840 GtkWidget *from_send_hbox;
841 GtkWidget *send_icon;
842 GtkWidget *attachments_label;
843 GtkWidget *branding_box;
844 GtkWidget *from_caption;
846 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
847 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
849 parent_priv->ui_manager = gtk_ui_manager_new();
850 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
851 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
853 /* Add common actions */
854 gtk_action_group_add_actions (action_group,
855 modest_msg_edit_action_entries,
856 G_N_ELEMENTS (modest_msg_edit_action_entries),
858 gtk_action_group_add_actions (action_group,
859 hildon2_msg_edit_action_entries,
860 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
862 gtk_action_group_add_toggle_actions (action_group,
863 modest_msg_edit_toggle_action_entries,
864 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
866 gtk_action_group_add_radio_actions (action_group,
867 modest_msg_edit_alignment_radio_action_entries,
868 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
870 G_CALLBACK (modest_ui_actions_on_change_justify),
872 gtk_action_group_add_radio_actions (action_group,
873 modest_msg_edit_priority_action_entries,
874 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
876 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
878 gtk_action_group_add_radio_actions (action_group,
879 modest_msg_edit_file_format_action_entries,
880 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
881 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
882 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
884 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
885 g_object_unref (action_group);
887 /* Load the UI definition */
888 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
891 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
892 g_clear_error (&error);
895 /* Add accelerators */
896 gtk_window_add_accel_group (GTK_WINDOW (obj),
897 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
899 parent_priv->menubar = NULL;
901 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
902 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
904 /* Note: This ModestPairList* must exist for as long as the picker
905 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
906 * so it can't know how to manage its memory. */
907 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
909 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
910 if (GTK_IS_COMBO_BOX (priv->from_field)) {
911 from_caption = modest_toolkit_utils_create_captioned (title_size_group, NULL,
912 _("mail_va_from"), FALSE,
914 gtk_widget_show (from_caption);
916 #ifdef MODEST_TOOLKIT_HILDON2
917 modest_toolkit_utils_set_hbutton_layout (title_size_group, NULL,
918 _("mail_va_from"), priv->from_field);
919 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
920 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
921 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
922 from_caption = priv->from_field;
926 priv->to_field = modest_recpt_editor_new ();
927 priv->cc_field = modest_recpt_editor_new ();
928 priv->bcc_field = modest_recpt_editor_new ();
929 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
930 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
931 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
932 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
933 priv->priority_icon = gtk_image_new ();
934 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
935 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
936 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
937 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
938 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
940 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
941 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
943 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
944 priv->attachments_view = modest_attachments_view_new (NULL);
945 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
946 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
948 priv->header_box = gtk_vbox_new (FALSE, 0);
950 to_caption = _create_addressbook_box
951 (title_size_group, value_size_group,
952 _("mail_va_to"), priv->to_field);
953 priv->cc_caption = _create_addressbook_box
954 (title_size_group, value_size_group,
955 _("mail_va_cc"), priv->cc_field);
956 priv->bcc_caption = _create_addressbook_box
957 (title_size_group, value_size_group,
958 _("mail_va_hotfix1"), priv->bcc_field);
959 subject_caption = modest_toolkit_utils_create_captioned (title_size_group, value_size_group,
960 _("mail_va_subject"), FALSE, priv->subject_box);
961 priv->attachments_caption = modest_toolkit_utils_create_captioned_with_size_type (NULL, NULL,
962 _("mail_va_attachment"),
964 priv->attachments_view,
965 #ifdef MODEST_TOOLKIT_HILDON2
966 HILDON_SIZE_AUTO_WIDTH |
967 HILDON_SIZE_AUTO_HEIGHT
972 attachments_label = modest_toolkit_utils_captioned_get_label_widget (priv->attachments_caption);
974 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
978 #ifdef MODEST_TOOLKIT_HILDON2
979 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
980 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
982 priv->send_button = gtk_button_new ();
983 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, GTK_ICON_SIZE_BUTTON);
985 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
986 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
988 g_object_unref (title_size_group);
989 g_object_unref (value_size_group);
991 priv->brand_icon = gtk_image_new ();
992 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
993 priv->brand_label = gtk_label_new (NULL);
994 #ifdef MODEST_TOOLKIT_HILDON2
995 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
997 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
998 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
999 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
1001 from_send_hbox = gtk_hbox_new (FALSE, 0);
1002 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
1003 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
1005 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
1006 gtk_widget_show (branding_box);
1007 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
1008 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
1010 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
1011 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1012 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
1013 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
1016 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
1017 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
1018 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
1019 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
1020 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
1021 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
1022 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
1023 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1025 init_wp_text_view_style ();
1027 priv->msg_body = modest_wp_text_view_new ();
1030 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1031 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1032 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1033 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1034 #if (GTK_MINOR_VERSION >= 10)
1035 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1036 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1038 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1039 deserialize_type, TRUE);
1041 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1043 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1045 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1047 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1049 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1051 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1053 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1054 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1055 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1057 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1058 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1059 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1061 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1062 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1064 window_box = gtk_vbox_new (FALSE, 0);
1065 gtk_container_add (GTK_CONTAINER(obj), window_box);
1067 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1072 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1074 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1076 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1077 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1078 priv->clipboard_change_handler_id))
1079 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1080 priv->clipboard_change_handler_id);
1081 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1082 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1083 priv->default_clipboard_change_handler_id))
1084 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1085 priv->default_clipboard_change_handler_id);
1087 if (priv->account_removed_handler_id &&
1088 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1089 priv->account_removed_handler_id))
1090 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1091 priv->account_removed_handler_id);
1095 modest_msg_edit_window_finalize (GObject *obj)
1097 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1099 if (priv->max_chars_banner) {
1100 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1101 priv->max_chars_banner = FALSE;
1104 /* Sanity check: shouldn't be needed, the window mgr should
1105 call this function before */
1106 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1108 if (priv->font_dialog != NULL) {
1109 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1112 if (priv->clipboard_text != NULL) {
1113 g_free (priv->clipboard_text);
1114 priv->clipboard_text = NULL;
1117 if (priv->draft_msg != NULL) {
1118 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1119 if (TNY_IS_HEADER (header)) {
1120 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1121 modest_window_mgr_unregister_header (mgr, header);
1123 g_object_unref (priv->draft_msg);
1124 priv->draft_msg = NULL;
1126 if (priv->outbox_msg != NULL) {
1127 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1128 if (TNY_IS_HEADER (header)) {
1129 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1130 modest_window_mgr_unregister_header (mgr, header);
1132 g_object_unref (priv->outbox_msg);
1133 priv->outbox_msg = NULL;
1135 if (priv->correct_scroll_idle > 0) {
1136 g_source_remove (priv->correct_scroll_idle);
1137 priv->correct_scroll_idle = 0;
1139 if (priv->scroll_drag_timeout_id > 0) {
1140 g_source_remove (priv->scroll_drag_timeout_id);
1141 priv->scroll_drag_timeout_id = 0;
1143 if (priv->clipboard_owner_idle > 0) {
1144 g_source_remove (priv->clipboard_owner_idle);
1145 priv->clipboard_owner_idle = 0;
1147 if (priv->original_account_name)
1148 g_free (priv->original_account_name);
1149 if (priv->original_mailbox)
1150 g_free (priv->original_mailbox);
1151 g_free (priv->msg_uid);
1152 g_free (priv->last_search);
1153 g_free (priv->references);
1154 g_free (priv->in_reply_to);
1155 g_object_unref (priv->attachments);
1156 g_object_unref (priv->images);
1158 /* This had to stay alive for as long as the picker that used it: */
1159 modest_pair_list_free (priv->from_field_protos);
1161 G_OBJECT_CLASS(parent_class)->finalize (obj);
1165 pixbuf_size_prepared (GdkPixbufLoader *loader,
1168 ModestMsgEditWindow *self)
1170 gint new_height, new_width;
1173 new_height = height;
1177 if (width > IMAGE_MAX_WIDTH) {
1178 new_height = height * IMAGE_MAX_WIDTH / width;
1179 new_width = IMAGE_MAX_WIDTH;
1182 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1186 pixbuf_from_stream (TnyStream *stream,
1187 const gchar *mime_type,
1188 guint64 *stream_size,
1189 ModestMsgEditWindow *self)
1191 GdkPixbufLoader *loader;
1194 GError *error = NULL;
1198 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1200 if (loader == NULL) {
1205 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1207 modest_window_show_progress (MODEST_WINDOW (self), TRUE);
1209 tny_stream_reset (TNY_STREAM (stream));
1210 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1211 unsigned char read_buffer[128];
1213 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1215 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1218 /* Allow some UI responsiveness */
1219 while (gtk_events_pending ())
1220 gtk_main_iteration ();
1222 modest_window_show_progress (MODEST_WINDOW (self), FALSE);
1224 gdk_pixbuf_loader_close (loader, &error);
1227 g_error_free (error);
1228 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1230 g_object_ref (pixbuf);
1231 g_object_unref (loader);
1236 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1237 GdkPixbuf *new_pixbuf;
1239 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1240 gdk_pixbuf_get_width (pixbuf);
1241 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1242 g_object_unref (pixbuf);
1243 pixbuf = new_pixbuf;
1247 *stream_size = size;
1253 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1255 ModestMsgEditWindowPrivate *priv;
1258 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1260 g_object_ref (self);
1261 for (iter = tny_list_create_iterator (attachments);
1262 !tny_iterator_is_done (iter);
1263 tny_iterator_next (iter)) {
1264 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1265 const gchar *cid = tny_mime_part_get_content_id (part);
1266 const gchar *mime_type = tny_mime_part_get_content_type (part);
1267 if ((cid != NULL)&&(mime_type != NULL)) {
1268 guint64 stream_size;
1269 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1270 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1273 g_object_unref (stream);
1275 if (pixbuf != NULL) {
1276 priv->images_count ++;
1277 priv->images_size += stream_size;
1278 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1279 g_object_unref (pixbuf);
1282 g_object_unref (part);
1284 g_object_unref (iter);
1285 g_object_unref (self);
1289 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1291 TnyMimePart *parent = NULL;
1292 const gchar *content_type = NULL;
1293 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1295 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1297 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1298 parent = g_object_ref (msg);
1299 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1300 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1303 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1304 iter = tny_list_create_iterator (parts);
1305 while (!tny_iterator_is_done (iter)) {
1307 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1308 content_type = tny_mime_part_get_content_type (part);
1309 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1313 g_object_unref (part);
1315 tny_iterator_next (iter);
1317 g_object_unref (iter);
1318 g_object_unref (parts);
1321 if (parent != NULL) {
1322 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1325 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1326 iter = tny_list_create_iterator (parts);
1327 while (!tny_iterator_is_done (iter)) {
1329 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1330 content_type = tny_mime_part_get_content_type (part);
1331 if (content_type && g_str_has_prefix (content_type, "image/")) {
1332 tny_list_prepend (priv->images, (GObject *) part);
1334 g_object_unref (part);
1335 tny_iterator_next (iter);
1337 g_object_unref (iter);
1338 g_object_unref (parts);
1339 g_object_unref (parent);
1344 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1347 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1349 for (iter = tny_list_create_iterator (attachments) ;
1350 !tny_iterator_is_done (iter);
1351 tny_iterator_next (iter)) {
1352 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1353 const gchar *cid = tny_mime_part_get_content_id (part);
1355 char *invalid = NULL;
1356 gint int_cid = strtol (cid, &invalid, 10);
1357 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1358 priv->next_cid = int_cid + 1;
1361 g_object_unref (part);
1363 g_object_unref (iter);
1367 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1370 gchar *to, *cc, *bcc, *subject;
1372 ModestMsgEditWindowPrivate *priv;
1373 ModestWindowPrivate *parent_priv;
1375 TnyHeaderFlags priority_flags;
1376 TnyFolder *msg_folder;
1377 gboolean is_html = FALSE;
1378 gboolean field_view_set;
1380 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1381 g_return_if_fail (TNY_IS_MSG (msg));
1383 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1384 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1386 header = tny_msg_get_header (msg);
1387 to = tny_header_dup_to (header);
1388 cc = tny_header_dup_cc (header);
1389 bcc = tny_header_dup_bcc (header);
1390 subject = tny_header_dup_subject (header);
1392 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1393 priority_flags = tny_header_get_priority (header);
1396 gchar *quoted_names = modest_text_utils_quote_names (to);
1397 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1398 g_free (quoted_names);
1401 field_view_set = TRUE;
1403 gchar *quoted_names = modest_text_utils_quote_names (cc);
1404 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1405 g_free (quoted_names);
1406 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1407 gtk_widget_show (priv->cc_caption);
1408 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1409 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1410 gtk_widget_hide (priv->cc_caption);
1411 field_view_set = FALSE;
1413 modest_togglable_set_active (priv->cc_button, field_view_set);
1415 field_view_set = TRUE;
1417 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1418 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1419 g_free (quoted_names);
1420 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1421 gtk_widget_show (priv->bcc_caption);
1422 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1423 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1424 gtk_widget_hide (priv->bcc_caption);
1425 field_view_set = FALSE;
1427 modest_togglable_set_active (priv->bcc_button, field_view_set);
1431 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1432 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1435 update_window_title (self);
1437 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1438 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1440 if ((body == NULL)||(body[0] == '\0')) {
1442 body = modest_text_utils_convert_to_html ("");
1445 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1446 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1449 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1452 /* Add attachments to the view */
1453 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1454 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1455 if (tny_list_get_length (priv->attachments) == 0) {
1456 gtk_widget_hide (priv->attachments_caption);
1458 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1459 gtk_widget_show_all (priv->attachments_caption);
1461 get_related_images (self, msg);
1462 update_next_cid (self, priv->attachments);
1463 update_next_cid (self, priv->images);
1464 replace_with_images (self, priv->images);
1466 if (preserve_is_rich && !is_html) {
1467 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1468 /* Get the default format required from configuration */
1469 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1470 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1473 /* Set the default focus depending on having already a To: field or not */
1474 if ((!to)||(*to == '\0')) {
1475 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1477 gtk_widget_grab_focus (priv->msg_body);
1480 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1482 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1483 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1485 modest_msg_edit_window_set_modified (self, FALSE);
1487 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1488 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1489 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1490 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1492 if (priv->msg_uid) {
1493 g_free (priv->msg_uid);
1494 priv->msg_uid = NULL;
1497 /* we should set a reference to the incoming message if it is a draft */
1498 msg_folder = tny_msg_get_folder (msg);
1500 if (modest_tny_folder_is_local_folder (msg_folder)) {
1501 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1502 if (type == TNY_FOLDER_TYPE_INVALID)
1503 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1505 if (type == TNY_FOLDER_TYPE_DRAFTS)
1506 priv->draft_msg = g_object_ref(msg);
1507 if (type == TNY_FOLDER_TYPE_OUTBOX)
1508 priv->outbox_msg = g_object_ref(msg);
1509 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1511 g_object_unref (msg_folder);
1521 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1523 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1524 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1525 GtkWidget *placeholder;
1526 GtkWidget *tool_item;
1531 GtkWidget *sizes_menu;
1532 GtkWidget *fonts_menu;
1538 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1539 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1540 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar),
1541 #ifdef MODEST_TOOLKIT_HILDON2
1542 HILDON_ICON_SIZE_FINGER
1544 GTK_ICON_SIZE_LARGE_TOOLBAR
1547 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1549 /* Font color placeholder */
1550 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1551 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1554 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1555 #ifdef MODEST_TOOLKIT_HILDON2
1556 priv->font_color_button = modest_color_button_new ();
1558 priv->font_color_button = gtk_color_button_new ();
1560 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1561 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1562 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1563 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1564 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1565 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1566 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1567 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1569 G_CALLBACK (modest_msg_edit_window_color_button_change),
1572 /* Font size and face placeholder */
1573 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1574 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1576 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1577 priv->size_tool_button_label = gtk_label_new (NULL);
1578 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1579 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1580 size_text, "</span>", NULL);
1581 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1582 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1584 #ifdef MODEST_TOOLKIT_HILDON2
1585 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1587 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1588 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1589 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1590 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1591 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1592 gtk_widget_set_sensitive (arrow, FALSE);
1593 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1594 sizes_menu = gtk_menu_new ();
1595 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1596 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1599 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1600 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1602 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1606 if (wp_font_size[size_index] == 12)
1607 priv->current_size_index = size_index;
1611 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1612 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1613 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1614 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1615 priv->font_size_toolitem = tool_item;
1618 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1619 priv->font_tool_button_label = gtk_label_new (NULL);
1620 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1621 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1622 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1624 #ifdef MODEST_TOOLKIT_HILDON2
1625 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1627 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1628 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1629 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1630 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1631 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1632 gtk_widget_set_sensitive (arrow, FALSE);
1633 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1634 fonts_menu = gtk_menu_new ();
1635 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1636 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1639 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1641 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1642 0, wp_get_font_name (font_index),
1645 if (font_index == DEFAULT_FONT)
1646 priv->current_face_index = font_index;
1648 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1649 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1650 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1651 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1652 priv->font_face_toolitem = tool_item;
1654 /* Set expand and homogeneous for remaining items */
1655 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1656 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1657 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1658 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1659 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1660 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1662 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1663 will not show the tool items added to the placeholders) */
1664 gtk_widget_show_all (parent_priv->toolbar);
1666 /* Set the no show all *after* showing all items. We do not
1667 want the toolbar to be shown with a show all because it
1668 could go agains the gconf setting regarding showing or not
1669 the toolbar of the editor window */
1670 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1676 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1679 ModestWindowPrivate *parent_priv;
1680 ModestMsgEditWindowPrivate *priv;
1681 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1682 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1683 ModestWindowMgr *mgr = NULL;
1685 g_return_val_if_fail (msg, NULL);
1686 g_return_val_if_fail (account_name, NULL);
1688 mgr = modest_runtime_get_window_mgr ();
1690 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1692 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1693 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1695 /* Menubar. Update the state of some toggles */
1696 priv->from_field_protos = get_transports ();
1697 priv->original_mailbox = NULL;
1698 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1699 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1700 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1701 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1702 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1703 priv->original_mailbox = g_strdup (mailbox);
1704 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1705 /* We set the first mailbox as the active mailbox */
1706 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1707 if (priv->original_mailbox != NULL)
1708 modest_selector_set_active_id (priv->from_field,
1709 (gpointer) priv->original_mailbox);
1711 modest_selector_set_active_id (priv->from_field,
1712 (gpointer) account_name);
1714 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1716 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1717 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1718 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1719 #ifdef HILDON_TOOLKIT_HILDON2
1720 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1722 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1723 hildon_touch_selector_get_current_text
1724 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1727 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1728 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1731 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1733 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1735 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1736 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1738 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1740 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1741 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1742 /* Add common dimming rules */
1743 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1744 modest_msg_edit_window_toolbar_dimming_entries,
1745 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1746 MODEST_WINDOW (obj));
1747 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1748 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1749 MODEST_WINDOW (obj));
1750 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1751 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1752 MODEST_WINDOW (obj));
1753 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1754 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1755 MODEST_WINDOW (obj));
1756 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1757 G_CALLBACK (modest_ui_dimming_rules_on_send),
1758 MODEST_WINDOW (obj));
1759 /* Insert dimming rules group for this window */
1760 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1761 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1763 /* Setup app menu */
1764 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1766 /* Checks the dimming rules */
1767 g_object_unref (toolbar_rules_group);
1768 g_object_unref (clipboard_rules_group);
1769 gtk_widget_hide (priv->priority_icon);
1770 gtk_widget_queue_resize (priv->subject_box);
1771 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1773 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1775 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1776 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1777 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1778 priv->update_caption_visibility = TRUE;
1780 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1782 /* Track account-removed signal, this window should be closed
1783 in the case we're creating a mail associated to the account
1785 priv->account_removed_handler_id =
1786 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1788 G_CALLBACK(on_account_removed),
1791 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1793 return (ModestWindow*) obj;
1797 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1799 GString **string_buffer = (GString **) user_data;
1801 *string_buffer = g_string_append (*string_buffer, buffer);
1807 * @result: A new string which should be freed with g_free().
1810 get_formatted_data (ModestMsgEditWindow *edit_window)
1812 ModestMsgEditWindowPrivate *priv;
1813 GString *string_buffer = g_string_new ("");
1815 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1817 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1819 modest_text_utils_hyperlinkify (string_buffer);
1821 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1823 return g_string_free (string_buffer, FALSE);
1828 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1831 const gchar *account_name;
1832 ModestMsgEditWindowPrivate *priv;
1833 TnyIterator *att_iter;
1834 const gchar *picker_active_id;
1836 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1838 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1840 picker_active_id = modest_selector_get_active_id (priv->from_field);
1841 g_return_val_if_fail (picker_active_id, NULL);
1842 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1844 /* don't free these (except from) */
1845 data = g_slice_new0 (MsgData);
1846 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1847 data->account_name = g_strdup (account_name);
1848 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1849 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1850 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1851 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1852 data->references = g_strdup (priv->references);
1853 data->in_reply_to = g_strdup (priv->in_reply_to);
1854 if (priv->draft_msg) {
1855 data->draft_msg = g_object_ref (priv->draft_msg);
1856 } else if (priv->outbox_msg) {
1857 data->draft_msg = g_object_ref (priv->outbox_msg);
1859 data->draft_msg = NULL;
1862 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1864 gtk_text_buffer_get_bounds (buf, &b, &e);
1865 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1867 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1868 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1870 data->html_body = NULL;
1872 /* deep-copy the data */
1873 att_iter = tny_list_create_iterator (priv->attachments);
1874 data->attachments = NULL;
1875 while (!tny_iterator_is_done (att_iter)) {
1876 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1877 if (!(TNY_IS_MIME_PART(part))) {
1878 g_warning ("strange data in attachment list");
1879 g_object_unref (part);
1880 tny_iterator_next (att_iter);
1883 data->attachments = g_list_append (data->attachments,
1885 tny_iterator_next (att_iter);
1887 g_object_unref (att_iter);
1889 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1890 att_iter = tny_list_create_iterator (priv->images);
1891 data->images = NULL;
1892 while (!tny_iterator_is_done (att_iter)) {
1893 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1895 if (!(TNY_IS_MIME_PART(part))) {
1896 g_warning ("strange data in attachment list");
1897 g_object_unref (part);
1898 tny_iterator_next (att_iter);
1901 cid = tny_mime_part_get_content_id (part);
1903 gchar *image_tag_id;
1904 GtkTextTag *image_tag;
1906 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1907 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1908 g_free (image_tag_id);
1910 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1912 ((gtk_text_iter_has_tag (&iter, image_tag))||
1913 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1914 data->images = g_list_append (data->images,
1915 g_object_ref (part));
1917 g_object_unref (part);
1918 tny_iterator_next (att_iter);
1920 g_object_unref (att_iter);
1922 data->priority_flags = priv->priority_flags;
1929 unref_gobject (GObject *obj, gpointer data)
1931 if (!G_IS_OBJECT(obj))
1933 g_object_unref (obj);
1937 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1940 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1948 g_free (data->from);
1949 g_free (data->subject);
1950 g_free (data->plain_body);
1951 g_free (data->html_body);
1952 g_free (data->account_name);
1953 g_free (data->references);
1954 g_free (data->in_reply_to);
1956 if (data->draft_msg != NULL) {
1957 g_object_unref (data->draft_msg);
1958 data->draft_msg = NULL;
1961 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1962 g_list_free (data->attachments);
1963 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1964 g_list_free (data->images);
1966 g_slice_free (MsgData, data);
1970 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1972 guint64 *parts_size)
1974 ModestMsgEditWindowPrivate *priv;
1976 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1978 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1980 /* TODO: add images */
1981 *parts_size += priv->images_size;
1982 *parts_count += priv->images_count;
1987 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1990 ModestMsgEditWindowPrivate *priv = NULL;
1991 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1993 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1995 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1997 return MODEST_MSG_EDIT_FORMAT_HTML;
1999 return MODEST_MSG_EDIT_FORMAT_TEXT;
2003 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
2004 ModestMsgEditFormat format)
2006 ModestMsgEditWindowPrivate *priv;
2007 ModestWindowPrivate *parent_priv;
2009 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2010 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2011 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2014 case MODEST_MSG_EDIT_FORMAT_HTML:
2015 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2016 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
2018 case MODEST_MSG_EDIT_FORMAT_TEXT:
2019 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2020 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
2023 g_return_if_reached ();
2027 ModestMsgEditFormatState *
2028 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2030 ModestMsgEditFormatState *format_state = NULL;
2031 ModestMsgEditWindowPrivate *priv;
2032 WPTextBufferFormat *buffer_format;
2034 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2036 buffer_format = g_new0 (WPTextBufferFormat, 1);
2037 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2039 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2041 format_state = g_new0 (ModestMsgEditFormatState, 1);
2042 format_state->bold = buffer_format->bold&0x1;
2043 format_state->italics = buffer_format->italic&0x1;
2044 format_state->bullet = buffer_format->bullet&0x1;
2045 format_state->color = buffer_format->color;
2046 format_state->font_size = buffer_format->font_size;
2047 format_state->font_family = wp_get_font_name (buffer_format->font);
2048 format_state->justification = buffer_format->justification;
2049 g_free (buffer_format);
2051 return format_state;
2056 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2057 const ModestMsgEditFormatState *format_state)
2059 ModestMsgEditWindowPrivate *priv;
2060 WPTextBufferFormat *buffer_format;
2061 WPTextBufferFormat *current_format;
2063 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2064 g_return_if_fail (format_state != NULL);
2066 buffer_format = g_new0 (WPTextBufferFormat, 1);
2067 current_format = g_new0 (WPTextBufferFormat, 1);
2069 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2070 gtk_widget_grab_focus (priv->msg_body);
2071 buffer_format->bold = (format_state->bold != FALSE);
2072 buffer_format->italic = (format_state->italics != FALSE);
2073 buffer_format->color = format_state->color;
2074 buffer_format->font_size = format_state->font_size;
2075 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2076 buffer_format->justification = format_state->justification;
2077 buffer_format->bullet = format_state->bullet;
2079 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2081 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2082 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2083 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2084 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2085 buffer_format->cs.font = (buffer_format->font != current_format->font);
2086 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2087 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2089 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2090 if (buffer_format->cs.bold) {
2091 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2092 GINT_TO_POINTER (buffer_format->bold&0x1));
2094 if (buffer_format->cs.italic) {
2095 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2096 GINT_TO_POINTER (buffer_format->italic&0x1));
2098 if (buffer_format->cs.color) {
2099 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2100 GINT_TO_POINTER (&(buffer_format->color)));
2102 if (buffer_format->cs.font_size) {
2103 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2104 GINT_TO_POINTER (buffer_format->font_size));
2106 if (buffer_format->cs.justification) {
2107 switch (buffer_format->justification) {
2108 case GTK_JUSTIFY_LEFT:
2109 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2110 GINT_TO_POINTER(TRUE));
2112 case GTK_JUSTIFY_CENTER:
2113 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2114 GINT_TO_POINTER(TRUE));
2116 case GTK_JUSTIFY_RIGHT:
2117 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2118 GINT_TO_POINTER(TRUE));
2125 if (buffer_format->cs.font) {
2126 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2127 GINT_TO_POINTER (buffer_format->font));
2129 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2130 if (buffer_format->cs.bullet) {
2131 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2132 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2134 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2136 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2138 g_free (buffer_format);
2139 g_free (current_format);
2141 /* Check dimming rules */
2142 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2143 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2147 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2149 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2151 ModestWindowPrivate *parent_priv;
2152 ModestMsgEditWindowPrivate *priv;
2154 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2155 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2157 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2158 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2159 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2160 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2162 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2163 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2164 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2167 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2169 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2170 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2172 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2173 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2175 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2176 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2179 switch (buffer_format->justification)
2181 case GTK_JUSTIFY_LEFT:
2182 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2184 case GTK_JUSTIFY_CENTER:
2185 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2187 case GTK_JUSTIFY_RIGHT:
2188 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2195 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2197 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2198 G_CALLBACK (modest_msg_edit_window_color_button_change),
2200 #ifdef MODEST_TOOLKIT_HILDON2
2201 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2203 gtk_color_button_set_color (GTK_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2205 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2206 G_CALLBACK (modest_msg_edit_window_color_button_change),
2209 if (priv->current_size_index != buffer_format->font_size) {
2213 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2214 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2218 priv->current_size_index = buffer_format->font_size;
2220 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2221 markup = g_strconcat ("<span font_family='Sans'>",
2222 size_text, "</span>", NULL);
2224 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2228 gtk_tree_path_free (path);
2231 if (priv->current_face_index != buffer_format->font) {
2235 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2236 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2240 priv->current_face_index = buffer_format->font;
2241 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2242 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2243 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2250 g_free (buffer_format);
2256 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2258 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2259 ModestMsgEditWindowPrivate *priv;
2260 GtkWidget *dialog = NULL;
2262 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2263 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2265 #ifdef MODEST_TOOLKIT_HILDON2
2266 dialog = hildon_color_chooser_new ();
2267 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2268 g_free (buffer_format);
2270 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2272 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2273 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2276 gtk_widget_destroy (dialog);
2278 dialog = gtk_color_selection_dialog_new (NULL);
2279 GtkWidget *selection;
2281 g_object_get (G_OBJECT (dialog), "color_selection", &selection, NULL);
2282 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2283 gtk_color_selection_set_previous_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2284 g_free (buffer_format);
2286 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2288 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION(selection), &col);
2289 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2292 gtk_widget_destroy (dialog);
2299 create_stream_for_uri (const gchar* uri)
2304 TnyStream *result = NULL;
2306 GnomeVFSHandle *handle = NULL;
2307 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2308 if (test == GNOME_VFS_OK) {
2309 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2310 /* Streams over OBEX (Bluetooth) are not seekable but
2311 * we expect them to be (we might need to read them
2312 * several times). So if this is a Bluetooth URI just
2313 * read the whole file into memory (this is not a fast
2314 * protocol so we can assume that these files are not
2315 * going to be very big) */
2316 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2317 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2318 TnyStream *memstream = tny_camel_mem_stream_new ();
2319 tny_stream_write_to_stream (vfssstream, memstream);
2320 g_object_unref (vfssstream);
2323 result = vfssstream;
2331 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2334 ModestMsgEditWindowPrivate *priv;
2335 GtkWidget *dialog = NULL;
2337 GSList *uris = NULL;
2338 GSList *uri_node = NULL;
2340 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2342 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2343 _("mcen_ia_select_inline_image_title"),
2344 (GtkWindow *) window,
2345 GTK_FILE_CHOOSER_ACTION_OPEN);
2346 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2348 #ifdef MODEST_TOOLKIT_HILDON2
2349 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2352 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2353 GTK_WINDOW (dialog), GTK_WINDOW (window));
2355 response = gtk_dialog_run (GTK_DIALOG (dialog));
2357 case GTK_RESPONSE_OK:
2359 gchar *current_folder;
2360 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2361 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2362 if (current_folder && current_folder != '\0') {
2364 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2365 current_folder, &err);
2367 g_debug ("Error storing latest used folder: %s", err->message);
2371 g_free (current_folder);
2377 gtk_widget_destroy (dialog);
2379 g_object_ref (window);
2380 /* The operation could take some time so allow the dialog to be closed */
2381 while (gtk_events_pending ())
2382 gtk_main_iteration ();
2384 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2386 GnomeVFSHandle *handle = NULL;
2387 GnomeVFSResult result;
2388 GtkTextIter position;
2389 GtkTextMark *insert_mark;
2391 uri = (const gchar *) uri_node->data;
2392 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2393 if (result == GNOME_VFS_OK) {
2395 GnomeVFSFileInfo *info;
2396 gchar *filename, *basename, *escaped_filename;
2397 TnyMimePart *mime_part;
2399 const gchar *mime_type = NULL;
2400 GnomeVFSURI *vfs_uri;
2401 guint64 stream_size;
2403 gnome_vfs_close (handle);
2404 vfs_uri = gnome_vfs_uri_new (uri);
2406 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2407 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2408 g_free (escaped_filename);
2409 gnome_vfs_uri_unref (vfs_uri);
2410 info = gnome_vfs_file_info_new ();
2412 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2413 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2415 mime_type = gnome_vfs_file_info_get_mime_type (info);
2417 mime_part = tny_platform_factory_new_mime_part
2418 (modest_runtime_get_platform_factory ());
2420 TnyStream *stream = create_stream_for_uri (uri);
2422 if (stream == NULL) {
2424 modest_platform_information_banner (NULL, NULL,
2425 _FM("sfil_ib_opening_not_allowed"));
2427 g_object_unref (mime_part);
2428 gnome_vfs_file_info_unref (info);
2432 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2434 content_id = g_strdup_printf ("%d", priv->next_cid);
2435 tny_mime_part_set_content_id (mime_part, content_id);
2436 g_free (content_id);
2439 basename = g_path_get_basename (filename);
2440 tny_mime_part_set_filename (mime_part, basename);
2443 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2445 if (pixbuf != NULL) {
2446 priv->images_size += stream_size;
2447 priv->images_count ++;
2448 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2449 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2450 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2451 tny_mime_part_get_content_id (mime_part), pixbuf);
2452 g_object_unref (pixbuf);
2454 tny_list_prepend (priv->images, (GObject *) mime_part);
2455 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2457 modest_platform_information_banner (NULL, NULL,
2458 _("mail_ib_file_operation_failed"));
2462 g_object_unref (mime_part);
2463 gnome_vfs_file_info_unref (info);
2467 g_object_unref (window);
2471 on_attach_file_response (GtkDialog *dialog,
2475 GSList *uris = NULL;
2477 GnomeVFSFileSize total_size, allowed_size;
2478 ModestMsgEditWindow *window;
2479 ModestMsgEditWindowPrivate *priv;
2484 case GTK_RESPONSE_OK:
2486 gchar *current_folder;
2488 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2489 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2490 if (current_folder && current_folder != '\0') {
2492 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2493 current_folder, &err);
2495 g_debug ("Error storing latest used folder: %s", err->message);
2499 g_free (current_folder);
2506 window = MODEST_MSG_EDIT_WINDOW (user_data);
2507 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2509 /* allowed size is the maximum size - what's already there */
2510 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2511 &att_num, &att_size);
2512 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2515 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2517 const gchar *uri = (const gchar *) uri_node->data;
2520 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2522 if (total_size > allowed_size) {
2523 g_debug ("%s: total size: %u",
2524 __FUNCTION__, (unsigned int)total_size);
2527 allowed_size -= total_size;
2529 g_slist_foreach (uris, (GFunc) g_free, NULL);
2530 g_slist_free (uris);
2532 gtk_widget_destroy (GTK_WIDGET (dialog));
2536 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2538 GtkWidget *dialog = NULL;
2539 ModestMsgEditWindowPrivate *priv;
2542 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2544 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2546 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2549 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2550 _("mcen_ia_select_attachment_title"),
2551 (GtkWindow *) window,
2552 GTK_FILE_CHOOSER_ACTION_OPEN);
2553 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2554 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2555 if (conf_folder && conf_folder[0] != '\0') {
2556 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2559 /* Set the default folder to documents folder */
2560 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2561 #ifdef MODEST_TOOLKIT_HILDON2
2564 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2565 ".documents", NULL);
2568 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2569 g_free (docs_folder);
2571 g_free (conf_folder);
2572 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2573 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2574 GTK_WINDOW (dialog), GTK_WINDOW (window));
2576 /* Connect to response & show */
2577 g_signal_connect (dialog, "response",
2578 G_CALLBACK (on_attach_file_response), window);
2579 gtk_widget_show (dialog);
2584 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2586 GnomeVFSFileSize allowed_size)
2589 GnomeVFSHandle *handle = NULL;
2590 ModestMsgEditWindowPrivate *priv;
2591 GnomeVFSResult result;
2592 GnomeVFSFileSize size = 0;
2593 g_return_val_if_fail (window, 0);
2594 g_return_val_if_fail (uri, 0);
2596 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2598 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2599 if (result == GNOME_VFS_OK) {
2600 TnyMimePart *mime_part;
2602 const gchar *mime_type = NULL;
2604 gchar *escaped_filename;
2607 GnomeVFSFileInfo *info;
2608 GnomeVFSURI *vfs_uri;
2610 gnome_vfs_close (handle);
2611 vfs_uri = gnome_vfs_uri_new (uri);
2614 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2615 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2616 g_free (escaped_filename);
2617 gnome_vfs_uri_unref (vfs_uri);
2619 info = gnome_vfs_file_info_new ();
2621 if (gnome_vfs_get_file_info (uri,
2623 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2625 mime_type = gnome_vfs_file_info_get_mime_type (info);
2626 mime_part = tny_platform_factory_new_mime_part
2627 (modest_runtime_get_platform_factory ());
2629 /* try to get the attachment's size; this may fail for weird
2630 * file systems, like obex, upnp... */
2631 if (allowed_size != 0 &&
2632 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2634 if (size > allowed_size) {
2635 modest_platform_information_banner (NULL, NULL,
2636 _("mail_ib_error_attachment_size"));
2641 g_debug ("%s: could not get attachment size", __FUNCTION__);
2643 stream = create_stream_for_uri (uri);
2645 if (stream == NULL) {
2647 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2649 g_object_unref (mime_part);
2651 gnome_vfs_file_info_unref (info);
2655 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2656 g_object_unref (stream);
2658 content_id = g_strdup_printf ("%d", priv->next_cid);
2659 tny_mime_part_set_content_id (mime_part, content_id);
2660 g_free (content_id);
2663 basename = g_path_get_basename (filename);
2664 tny_mime_part_set_filename (mime_part, basename);
2667 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2668 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2670 info->size == 0, info->size);
2671 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2672 gtk_widget_show_all (priv->attachments_caption);
2673 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2675 g_object_unref (mime_part);
2676 gnome_vfs_file_info_unref (info);
2683 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2686 ModestMsgEditWindowPrivate *priv;
2689 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2690 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2692 if (att_list == NULL) {
2693 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2694 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2695 g_object_unref (att_list);
2699 g_object_ref (att_list);
2702 if (tny_list_get_length (att_list) == 0) {
2703 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2705 gboolean dialog_response;
2706 gchar *message = NULL;
2707 gchar *filename = NULL;
2709 if (tny_list_get_length (att_list) == 1) {
2711 iter = tny_list_create_iterator (att_list);
2712 part = (TnyMimePart *) tny_iterator_get_current (iter);
2713 g_object_unref (iter);
2714 if (TNY_IS_MSG (part)) {
2715 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2717 filename = tny_header_dup_subject (header);
2718 g_object_unref (header);
2720 if (filename == NULL) {
2721 filename = g_strdup (_("mail_va_no_subject"));
2724 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2726 g_object_unref (part);
2728 filename = g_strdup ("");
2730 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2731 "emev_nc_delete_attachments",
2732 tny_list_get_length (att_list)), filename);
2735 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2739 if (dialog_response != GTK_RESPONSE_OK) {
2740 g_object_unref (att_list);
2744 for (iter = tny_list_create_iterator (att_list);
2745 !tny_iterator_is_done (iter);
2746 tny_iterator_next (iter)) {
2747 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2748 const gchar *att_id;
2749 tny_list_remove (priv->attachments, (GObject *) mime_part);
2751 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2753 if (tny_list_get_length (priv->attachments) == 0)
2754 gtk_widget_hide (priv->attachments_caption);
2755 att_id = tny_mime_part_get_content_id (mime_part);
2757 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2759 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2760 g_object_unref (mime_part);
2762 g_object_unref (iter);
2765 g_object_unref (att_list);
2767 /* if the last attachment has been removed, focus the Subject: field */
2768 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2769 gtk_widget_grab_focus (priv->subject_field);
2773 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2776 ModestMsgEditWindowPrivate *priv;
2779 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2781 gtk_color_button_get_color (GTK_COLOR_BUTTON(priv->font_color_button), &new_color);
2783 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2785 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2789 font_size_clicked (GtkToolButton *button,
2790 ModestMsgEditWindow *window)
2792 #ifdef MODEST_TOOLKIT_HILDON2
2793 ModestMsgEditWindowPrivate *priv;
2794 GtkWidget *selector, *dialog;
2796 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2798 selector = hildon_touch_selector_new ();
2799 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2800 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2802 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2803 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2804 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2806 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2810 WPTextBufferFormat format;
2812 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2814 memset (&format, 0, sizeof (format));
2815 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2817 format.cs.font_size = TRUE;
2818 format.cs.text_position = TRUE;
2819 format.cs.font = TRUE;
2820 format.font_size = new_index;
2821 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2823 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2824 GINT_TO_POINTER (new_index)))
2825 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2827 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2828 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2829 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2830 size_text, "</span>", NULL);
2832 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2836 gtk_widget_destroy (dialog);
2838 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2843 font_face_clicked (GtkToolButton *button,
2844 ModestMsgEditWindow *window)
2846 #ifdef MODEST_TOOLKIT_HILDON2
2847 ModestMsgEditWindowPrivate *priv;
2848 GtkWidget *selector, *dialog;
2849 GtkCellRenderer *renderer;
2851 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2853 selector = hildon_touch_selector_new ();
2854 renderer = gtk_cell_renderer_text_new ();
2855 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2856 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2857 renderer, "family", 0, "text", 0, NULL);
2858 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2860 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2861 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2862 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2864 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2865 gint new_font_index;
2869 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2870 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2871 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2875 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2877 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2878 GINT_TO_POINTER(new_font_index)))
2879 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2881 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2882 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2884 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2888 gtk_tree_path_free (path);
2891 gtk_widget_destroy (dialog);
2893 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2898 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2901 ModestMsgEditWindowPrivate *priv = NULL;
2902 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2904 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2905 if (!priv->update_caption_visibility)
2908 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2910 gtk_widget_show (priv->cc_caption);
2912 gtk_widget_hide (priv->cc_caption);
2914 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2918 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2921 ModestMsgEditWindowPrivate *priv = NULL;
2922 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2924 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2925 if (!priv->update_caption_visibility)
2928 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2930 gtk_widget_show (priv->bcc_caption);
2932 gtk_widget_hide (priv->bcc_caption);
2934 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2938 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2939 ModestRecptEditor *editor)
2941 ModestMsgEditWindowPrivate *priv;
2943 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2944 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2946 /* we check for low-mem; in that case, show a warning, and don't allow
2947 * for the addressbook
2949 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2952 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2954 if (editor == NULL) {
2955 GtkWidget *view_focus, *parent;
2956 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2958 /* This code should be kept in sync with ModestRecptEditor. The
2959 textview inside the recpt editor is the one that really gets the
2960 focus. As it's inside a scrolled window, and this one inside the
2961 hbox recpt editor inherits from, we'll need to go up in the
2962 hierarchy to know if the text view is part of the recpt editor
2963 or if it's a different text entry */
2964 parent = gtk_widget_get_parent (view_focus);
2965 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2966 editor = MODEST_RECPT_EDITOR (parent);
2969 editor = MODEST_RECPT_EDITOR (priv->to_field);
2972 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2976 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2978 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2980 modest_msg_edit_window_open_addressbook (window, NULL);
2984 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2985 gboolean show_toolbar)
2987 ModestWindowPrivate *parent_priv;
2988 ModestMsgEditWindowPrivate *priv;
2990 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2991 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2992 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2994 /* We can not just use the code of
2995 modest_msg_edit_window_setup_toolbar because it has a
2996 mixture of both initialization and creation code. */
2998 gint current_format;
2999 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3000 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3001 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3002 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3004 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
3007 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3012 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
3013 TnyHeaderFlags priority_flags)
3015 ModestMsgEditWindowPrivate *priv;
3016 ModestWindowPrivate *parent_priv;
3018 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3020 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3021 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3023 if (priv->priority_flags != priority_flags) {
3024 GtkAction *priority_action = NULL;
3026 priv->priority_flags = priority_flags;
3028 switch (priority_flags) {
3029 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3030 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3031 MODEST_HEADER_ICON_HIGH,
3032 #ifdef MODEST_TOOLKIT_HILDON2
3033 HILDON_ICON_SIZE_SMALL
3035 GTK_ICON_SIZE_BUTTON
3038 gtk_widget_show (priv->priority_icon);
3039 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3040 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3042 case TNY_HEADER_FLAG_LOW_PRIORITY:
3043 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3044 MODEST_HEADER_ICON_LOW,
3045 #ifdef MODEST_TOOLKIT_HILDON2
3046 HILDON_ICON_SIZE_SMALL
3048 GTK_ICON_SIZE_BUTTON
3051 gtk_widget_show (priv->priority_icon);
3052 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3053 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3056 gtk_widget_hide (priv->priority_icon);
3057 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3058 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3061 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3062 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3064 gtk_widget_queue_resize (priv->subject_box);
3068 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3071 ModestMsgEditWindowPrivate *priv;
3072 ModestWindowPrivate *parent_priv;
3073 gint current_format;
3075 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3077 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3078 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3080 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3081 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3083 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3085 if (current_format != file_format) {
3086 switch (file_format) {
3087 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3088 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3089 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3090 if (parent_priv->toolbar)
3091 gtk_widget_show (parent_priv->toolbar);
3093 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3096 response = modest_platform_run_confirmation_dialog (NULL, _("emev_nc_formatting_lost"));
3097 if (response == GTK_RESPONSE_OK) {
3098 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3099 if (parent_priv->toolbar)
3100 gtk_widget_hide (parent_priv->toolbar);
3102 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3103 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3108 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3109 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3110 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3115 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3117 #ifdef MODEST_TOOLKIT_HILDON2
3119 ModestMsgEditWindowPrivate *priv;
3120 WPTextBufferFormat oldfmt, fmt;
3121 gint old_position = 0;
3125 GdkColor *color = NULL;
3126 gboolean bold, bold_set, italic, italic_set;
3127 gboolean underline, underline_set;
3128 gboolean strikethrough, strikethrough_set;
3129 gboolean position_set;
3130 gboolean font_size_set, font_set, color_set;
3133 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3134 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3136 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3137 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3138 GTK_WINDOW(dialog), GTK_WINDOW (window));
3140 /* First we get the currently selected font information */
3141 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3143 switch (oldfmt.text_position) {
3144 case TEXT_POSITION_NORMAL:
3147 case TEXT_POSITION_SUPERSCRIPT:
3155 g_object_set (G_OBJECT (dialog),
3156 "bold", oldfmt.bold != FALSE,
3157 "bold-set", !oldfmt.cs.bold,
3158 "underline", oldfmt.underline != FALSE,
3159 "underline-set", !oldfmt.cs.underline,
3160 "italic", oldfmt.italic != FALSE,
3161 "italic-set", !oldfmt.cs.italic,
3162 "strikethrough", oldfmt.strikethrough != FALSE,
3163 "strikethrough-set", !oldfmt.cs.strikethrough,
3164 "color", &oldfmt.color,
3165 "color-set", !oldfmt.cs.color,
3166 "size", wp_font_size[oldfmt.font_size],
3167 "size-set", !oldfmt.cs.font_size,
3168 "position", old_position,
3169 "position-set", !oldfmt.cs.text_position,
3170 "family", wp_get_font_name (oldfmt.font),
3171 "family-set", !oldfmt.cs.font,
3174 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3175 GTK_WINDOW (dialog), GTK_WINDOW (window));
3176 gtk_widget_show_all (dialog);
3177 priv->font_dialog = dialog;
3178 response = gtk_dialog_run (GTK_DIALOG (dialog));
3179 priv->font_dialog = NULL;
3180 if (response == GTK_RESPONSE_OK) {
3182 g_object_get( dialog,
3184 "bold-set", &bold_set,
3185 "underline", &underline,
3186 "underline-set", &underline_set,
3188 "italic-set", &italic_set,
3189 "strikethrough", &strikethrough,
3190 "strikethrough-set", &strikethrough_set,
3192 "color-set", &color_set,
3194 "size-set", &font_size_set,
3195 "family", &font_name,
3196 "family-set", &font_set,
3197 "position", &position,
3198 "position-set", &position_set,
3203 if (response == GTK_RESPONSE_OK) {
3204 memset(&fmt, 0, sizeof(fmt));
3210 fmt.italic = italic;
3211 fmt.cs.italic = TRUE;
3213 if (underline_set) {
3214 fmt.underline = underline;
3215 fmt.cs.underline = TRUE;
3217 if (strikethrough_set) {
3218 fmt.strikethrough = strikethrough;
3219 fmt.cs.strikethrough = TRUE;
3224 ? TEXT_POSITION_NORMAL
3225 : ( ( position == 1 )
3226 ? TEXT_POSITION_SUPERSCRIPT
3227 : TEXT_POSITION_SUBSCRIPT );
3228 fmt.cs.text_position = TRUE;
3229 fmt.font_size = oldfmt.font_size;
3233 fmt.cs.color = TRUE;
3236 fmt.font = wp_get_font_index(font_name,
3241 if (font_size_set) {
3242 fmt.cs.font_size = TRUE;
3243 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3245 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3246 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3248 gtk_widget_destroy (dialog);
3250 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3255 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3257 ModestMsgEditWindowPrivate *priv;
3258 ModestWindowPrivate *parent_priv;
3259 gboolean was_rich_text, is_rich_text;
3261 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3262 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3263 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3265 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3267 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3269 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3271 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3273 gtk_widget_show (parent_priv->toolbar);
3275 gtk_widget_hide (parent_priv->toolbar);
3278 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3279 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3283 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3285 ModestMsgEditWindowPrivate *priv;
3287 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3288 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3290 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3292 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3293 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3298 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3300 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3302 priv->can_undo = can_undo;
3306 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3308 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3310 priv->can_redo = can_redo;
3314 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3316 ModestMsgEditWindowPrivate *priv;
3317 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3318 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3320 return priv->can_undo;
3324 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3326 ModestMsgEditWindowPrivate *priv;
3327 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3328 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3330 return priv->can_redo;
3335 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3338 GtkTextIter match_start, match_end;
3340 if (image_id == NULL)
3343 gtk_text_buffer_get_start_iter (buffer, &iter);
3345 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3346 GSList *tags = gtk_text_iter_get_tags (&match_start);
3348 for (node = tags; node != NULL; node = g_slist_next (node)) {
3349 GtkTextTag *tag = (GtkTextTag *) node->data;
3350 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3351 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3352 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3354 offset = gtk_text_iter_get_offset (&match_start);
3355 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3356 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3360 gtk_text_iter_forward_char (&iter);
3365 message_is_empty (ModestMsgEditWindow *window)
3367 ModestMsgEditWindowPrivate *priv = NULL;
3369 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3370 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3372 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3373 * so we can ignore markup.
3375 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3378 count = gtk_text_buffer_get_char_count (buf);
3384 msg_body_focus (GtkWidget *focus,
3385 GdkEventFocus *event,
3389 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3390 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3391 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3396 recpt_field_changed (GtkTextBuffer *buffer,
3397 ModestMsgEditWindow *editor)
3399 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3400 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3404 body_changed (GtkTextBuffer *buffer, 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 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3414 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3415 GtkTextBuffer *buffer;
3417 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3418 gtk_text_buffer_set_modified (buffer, modified);
3419 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3420 gtk_text_buffer_set_modified (buffer, modified);
3421 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3422 gtk_text_buffer_set_modified (buffer, modified);
3423 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3427 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3429 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3430 const char *account_name;
3431 GtkTextBuffer *buffer;
3433 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3434 if (gtk_text_buffer_get_modified (buffer))
3436 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3437 if (gtk_text_buffer_get_modified (buffer))
3439 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3440 if (gtk_text_buffer_get_modified (buffer))
3442 if (gtk_text_buffer_get_modified (priv->text_buffer))
3445 account_name = modest_selector_get_active_id (priv->from_field);
3446 if (priv->original_mailbox) {
3447 if (!account_name || strcmp (account_name, priv->original_mailbox))
3449 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3460 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3462 ModestMsgEditWindowPrivate *priv = NULL;
3463 GSList *address_list = NULL;
3465 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3466 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3468 /* check if there's no recipient added */
3469 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3470 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3471 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3472 /* no recipient contents, then select contacts */
3473 modest_msg_edit_window_open_addressbook (window, NULL);
3478 g_object_ref (window);
3479 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3480 (add_to_addressbook) ? &address_list : NULL)) {
3481 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3482 g_object_unref (window);
3485 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3486 (add_to_addressbook) ? &address_list : NULL)) {
3487 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3488 g_object_unref (window);
3491 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3492 (add_to_addressbook) ? &address_list : NULL)) {
3493 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3494 g_object_unref (window);
3498 /* Add contacts to address book */
3499 if (add_to_addressbook && address_list)
3500 modest_address_book_add_address_list (address_list);
3502 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3503 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3504 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3505 g_object_unref (window);
3512 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3514 GSList *recipients = NULL;
3515 ModestMsgEditWindowPrivate *priv;
3516 gchar *joined, *after_remove, *to, *cc, *bcc;
3518 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3520 /* First of all check names */
3521 if (!modest_msg_edit_window_check_names (self, FALSE))
3524 if (!modest_msg_edit_window_has_pending_addresses (self))
3527 /* Don't add the from obviously */
3528 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3529 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3530 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3532 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3537 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3540 recipients = modest_text_utils_split_addresses_list (after_remove);
3541 g_free (after_remove);
3544 /* Offer the user to add recipients to the address book */
3545 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3546 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3551 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3552 ModestMsgEditWindow *window)
3554 modest_msg_edit_window_offer_attach_file (window);
3558 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3560 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3562 return priv->clipboard_text;
3566 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3568 ModestMsgEditWindow *window)
3570 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3571 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3574 /* It could happen that the window was already closed */
3575 if (!GTK_WIDGET_VISIBLE (window))
3578 g_object_ref (window);
3579 text = gtk_clipboard_wait_for_text (selection_clipboard);
3581 if (priv->clipboard_text != NULL) {
3582 g_free (priv->clipboard_text);
3584 priv->clipboard_text = text;
3586 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3588 g_object_unref (window);
3591 static gboolean clipboard_owner_change_idle (gpointer userdata)
3593 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3594 ModestMsgEditWindowPrivate *priv;
3596 gdk_threads_enter ();
3597 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3598 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3600 priv->clipboard_owner_idle = 0;
3601 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3602 gdk_threads_leave ();
3608 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3610 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3611 if (priv->clipboard_owner_idle == 0) {
3612 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3613 clipboard_owner_change_idle,
3614 g_object_ref (window),
3620 subject_field_move_cursor (GtkEntry *entry,
3621 GtkMovementStep step,
3626 /* It could happen that the window was already closed */
3627 if (!GTK_WIDGET_VISIBLE (window))
3630 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3634 update_window_title (ModestMsgEditWindow *window)
3636 ModestMsgEditWindowPrivate *priv = NULL;
3637 const gchar *subject;
3639 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3640 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3641 if (subject == NULL || subject[0] == '\0')
3642 subject = _("mail_va_new_email");
3644 modest_window_set_title (MODEST_WINDOW (window), subject);
3650 body_insert_text (GtkTextBuffer *buffer,
3651 GtkTextIter *location,
3654 ModestMsgEditWindow *window)
3656 GtkTextIter end_iter;
3663 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3665 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3667 offset = gtk_text_iter_get_offset (&end_iter);
3668 line = gtk_text_iter_get_line (&end_iter);
3672 while (text_offset < text + len) {
3673 if (*text_offset == '\n')
3675 if (text_lines + line >= MAX_BODY_LINES) {
3676 len = text_offset - text;
3682 utf8_len = g_utf8_strlen (text, len);
3684 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3685 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3686 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3691 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3693 /* Prevent endless recursion */
3694 result = g_strndup (text, utf8_end - text);
3695 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3696 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3697 (gpointer) result, (gpointer) (utf8_end - text),
3699 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3703 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3704 if (priv->max_chars_banner == NULL) {
3705 #ifdef MODEST_TOOLKIT_HILDON2
3706 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3707 _CS("ckdg_ib_maximum_characters_reached"));
3708 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3715 subject_field_changed (GtkEditable *editable,
3716 ModestMsgEditWindow *window)
3718 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3719 update_window_title (window);
3720 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3721 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3722 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3725 subject_field_insert_text (GtkEditable *editable,
3727 gint new_text_length,
3729 ModestMsgEditWindow *window)
3731 GString *result = g_string_new ("");
3733 gint result_len = 0;
3734 const gchar *entry_text = NULL;
3737 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3738 old_length = g_utf8_strlen (entry_text, -1);
3740 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3741 gunichar c = g_utf8_get_char_validated (current, 8);
3742 /* Invalid unichar, stop */
3748 result = g_string_append_unichar (result, c);
3752 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3753 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3756 /* Prevent endless recursion */
3757 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3758 g_signal_emit_by_name (editable, "insert-text",
3759 (gpointer) result->str, (gpointer) result->len,
3760 (gpointer) position, (gpointer) window);
3761 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3765 if (result_len + old_length > 1000) {
3766 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3767 _CS("ckdg_ib_maximum_characters_reached"));
3769 g_string_free (result, TRUE);
3773 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3776 ModestMsgEditWindowPrivate *priv = NULL;
3778 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3779 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3781 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3784 gtk_widget_show_all (priv->isearch_toolbar);
3785 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3787 gtk_widget_hide_all (priv->isearch_toolbar);
3788 gtk_widget_grab_focus (priv->msg_body);
3793 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3795 GtkTextIter *match_start,
3796 GtkTextIter *match_end)
3798 GtkTextIter end_iter;
3799 gchar *str_casefold;
3802 gchar *range_casefold;
3805 gboolean result = FALSE;
3812 gtk_text_iter_forward_to_end (&end_iter);
3814 str_casefold = g_utf8_casefold (str, -1);
3815 str_chars_n = strlen (str);
3817 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3818 range_casefold = g_utf8_casefold (range_text, -1);
3819 range_chars_n = strlen (range_casefold);
3821 if (range_chars_n < str_chars_n) {
3822 g_free (str_casefold);
3823 g_free (range_text);
3824 g_free (range_casefold);
3828 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3829 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3830 if (!g_utf8_collate (range_subtext, str_casefold)) {
3831 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3833 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3834 match_start, match_end, NULL)) {
3835 g_debug ("Matched string with collate, but not matched in model");
3837 g_free (found_text);
3839 g_free (range_subtext);
3843 g_free (str_casefold);
3844 g_free (range_text);
3845 g_free (range_casefold);
3852 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
3853 ModestMsgEditWindow *window)
3855 const gchar *current_search = NULL;
3856 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3858 GtkTextIter selection_start, selection_end;
3859 GtkTextIter match_start, match_end;
3860 gboolean continue_search = FALSE;
3862 if (message_is_empty (window)) {
3863 g_free (priv->last_search);
3864 priv->last_search = NULL;
3865 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3869 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
3870 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3871 g_free (priv->last_search);
3872 priv->last_search = NULL;
3873 /* Information banner about empty search */
3874 modest_platform_system_banner (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3878 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3879 continue_search = TRUE;
3881 g_free (priv->last_search);
3882 priv->last_search = g_strdup (current_search);
3885 if (continue_search) {
3886 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3887 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3888 &match_start, &match_end);
3890 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3892 GtkTextIter buffer_start;
3893 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3894 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3895 &match_start, &match_end);
3897 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3900 /* Mark as selected the string found in search */
3902 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3903 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3904 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3906 g_free (priv->last_search);
3907 priv->last_search = NULL;
3912 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3914 ModestMsgEditWindowPrivate *priv;
3916 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3921 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3924 ModestMsgEditWindowPrivate *priv;
3926 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3931 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
3932 ModestMsgEditWindow *window)
3934 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
3938 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3941 ModestMsgEditWindowPrivate *priv;
3942 TnyHeader *header = NULL;
3944 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3945 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3947 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3949 if (priv->draft_msg != NULL) {
3950 g_object_unref (priv->draft_msg);
3953 if (draft != NULL) {
3954 g_object_ref (draft);
3955 header = tny_msg_get_header (draft);
3956 if (priv->msg_uid) {
3957 g_free (priv->msg_uid);
3958 priv->msg_uid = NULL;
3960 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3963 priv->draft_msg = draft;
3967 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3968 GtkTextIter *start, GtkTextIter *end,
3971 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3972 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3975 if (tag == NULL) return;
3976 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3977 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3978 replace_with_images (window, priv->images);
3983 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3986 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3988 g_return_if_fail (TNY_IS_MIME_PART (part));
3989 tny_list_prepend (priv->attachments, (GObject *) part);
3990 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3991 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3992 gtk_widget_show_all (priv->attachments_caption);
3993 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3997 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3999 ModestMsgEditWindowPrivate *priv;
4001 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
4002 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4004 return priv->msg_uid;
4008 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
4009 ModestMsgEditWindowWidgetType widget_type)
4011 ModestMsgEditWindowPrivate *priv;
4013 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
4014 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
4016 switch (widget_type) {
4017 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
4018 return priv->msg_body;
4020 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
4021 return priv->to_field;
4023 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
4024 return priv->cc_field;
4026 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4027 return priv->bcc_field;
4029 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4030 return priv->subject_field;
4032 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4033 return priv->attachments_view;
4041 remove_tags (WPTextBuffer *buffer)
4043 GtkTextIter start, end;
4045 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4046 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4048 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4052 on_account_removed (TnyAccountStore *account_store,
4053 TnyAccount *account,
4056 /* Do nothing if it's a store account, because we use the
4057 transport to send the messages */
4058 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4059 const gchar *parent_acc = NULL;
4060 const gchar *our_acc = NULL;
4062 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4063 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4064 /* Close this window if I'm showing a message of the removed account */
4065 if (strcmp (parent_acc, our_acc) == 0)
4066 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4071 update_signature (ModestMsgEditWindow *self,
4072 const gchar *old_account,
4073 const gchar *new_account)
4075 ModestMsgEditWindowPrivate *priv;
4076 gboolean has_old_signature, has_new_signature;
4078 ModestAccountMgr *mgr;
4081 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4083 gtk_text_buffer_begin_user_action (priv->text_buffer);
4085 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4086 mgr = modest_runtime_get_account_mgr ();
4090 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4091 if (has_old_signature) {
4092 GtkTextIter match_start, match_end;
4094 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4095 seems that the search has some problems
4096 with the blank space at the end */
4097 if (gtk_text_iter_forward_search (&iter, "--",
4098 GTK_TEXT_SEARCH_TEXT_ONLY,
4099 &match_start, NULL, NULL)) {
4100 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4101 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4103 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4104 &match_start, &match_end, NULL)) {
4108 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4113 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4114 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4115 if (has_new_signature) {
4117 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4118 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4120 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4121 g_free (full_signature);
4124 gtk_text_buffer_end_user_action (priv->text_buffer);
4127 static void update_branding (ModestMsgEditWindow *self,
4128 const gchar *new_account)
4130 ModestMsgEditWindowPrivate *priv;
4131 ModestAccountMgr *mgr;
4132 const GdkPixbuf *new_icon = NULL;
4133 gchar *new_label = NULL;
4134 gboolean show = FALSE;
4136 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4138 mgr = modest_runtime_get_account_mgr ();
4140 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4142 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4143 gtk_widget_show (priv->brand_icon);
4146 gtk_widget_hide (priv->brand_icon);
4149 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4150 gtk_widget_show (priv->brand_label);
4154 gtk_widget_hide (priv->brand_label);
4158 gtk_widget_show (priv->brand_container);
4160 gtk_widget_hide (priv->brand_container);
4164 from_field_changed (GtkWidget *button,
4165 ModestMsgEditWindow *self)
4167 ModestMsgEditWindowPrivate *priv;
4168 gchar *old_account, *new_account;
4170 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4172 old_account = priv->last_from_account;
4173 new_account = modest_selector_get_active_id (priv->from_field);
4176 g_warning ("%s, could not get the new account", __FUNCTION__);
4180 /* If the From is the same do nothing */
4181 if (old_account && new_account && !strcmp (old_account, new_account))
4184 priv->last_from_account = new_account;
4186 update_signature (self, old_account, new_account);
4187 update_branding (self, new_account);
4191 typedef struct _MessageSettingsHelper {
4192 ModestMsgEditWindow *window;
4193 GSList *priority_group;
4194 GSList *format_group;
4195 GtkToggleButton *current_priority;
4196 GtkToggleButton *current_format;
4197 } MessageSettingsHelper;
4200 on_priority_toggle (GtkToggleButton *button,
4201 MessageSettingsHelper *helper)
4204 ModestMsgEditWindowPrivate *priv;
4206 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4207 if (gtk_toggle_button_get_active (button)) {
4209 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4210 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4211 if ((node_button != button) &&
4212 gtk_toggle_button_get_active (node_button)) {
4213 gtk_toggle_button_set_active (node_button, FALSE);
4216 helper->current_priority = button;
4218 gboolean found = FALSE;
4219 /* If no one is active, activate it again */
4220 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4221 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4222 if (gtk_toggle_button_get_active (node_button)) {
4228 gtk_toggle_button_set_active (button, TRUE);
4234 on_format_toggle (GtkToggleButton *button,
4235 MessageSettingsHelper *helper)
4238 ModestMsgEditWindowPrivate *priv;
4240 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4241 if (gtk_toggle_button_get_active (button)) {
4243 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4244 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4245 if ((node_button != button) &&
4246 gtk_toggle_button_get_active (node_button)) {
4247 gtk_toggle_button_set_active (node_button, FALSE);
4250 helper->current_format = button;
4252 gboolean found = FALSE;
4253 /* If no one is active, activate it again */
4254 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4255 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4256 if (gtk_toggle_button_get_active (node_button)) {
4262 gtk_toggle_button_set_active (button, TRUE);
4269 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4271 #ifdef MODEST_TOOLKIT_HILDON2
4275 GtkWidget *priority_hbox;
4276 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4277 GtkWidget *captioned;
4278 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4279 GtkWidget *format_hbox;
4280 GtkWidget *html_toggle, *text_toggle;
4281 ModestMsgEditWindowPrivate *priv;
4282 MessageSettingsHelper helper = {0,};
4284 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4285 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4286 helper.window = window;
4287 helper.priority_group = NULL;
4288 helper.format_group = NULL;
4290 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4291 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4293 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4294 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4295 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4296 vbox = gtk_vbox_new (FALSE, 0);
4297 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4298 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4299 gtk_container_add (GTK_CONTAINER (align), vbox);
4300 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4301 gtk_widget_show (align);
4302 gtk_widget_show (vbox);
4304 /* Priority toggles */
4305 priority_hbox = gtk_hbox_new (TRUE, 0);
4306 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4307 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4308 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4309 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4310 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4311 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4312 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4313 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4314 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4315 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4316 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4317 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4318 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4319 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4320 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4321 gtk_widget_show_all (priority_hbox);
4322 captioned = modest_toolkit_utils_create_captioned (title_sizegroup, value_sizegroup,
4323 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4324 gtk_widget_show (captioned);
4325 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4327 /* format toggles */
4328 format_hbox = gtk_hbox_new (TRUE, 0);
4329 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4330 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4331 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4332 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4333 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4334 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4335 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4336 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4337 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4338 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4339 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4340 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4341 gtk_widget_show_all (format_hbox);
4342 gtk_widget_show (format_hbox);
4343 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4346 g_object_unref (title_sizegroup);
4347 g_object_unref (value_sizegroup);
4349 /* Set current values */
4350 switch (priv->priority_flags) {
4351 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4352 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4353 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4355 case TNY_HEADER_FLAG_LOW_PRIORITY:
4356 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4357 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4360 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4361 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4365 switch (modest_msg_edit_window_get_format (window)) {
4366 case MODEST_MSG_EDIT_FORMAT_TEXT:
4367 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4368 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4370 case MODEST_MSG_EDIT_FORMAT_HTML:
4372 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4373 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4377 /* Signal connects */
4378 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4379 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4380 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4381 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4382 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4384 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4385 GTK_WINDOW (dialog), GTK_WINDOW (window));
4387 /* Save settings if the user clicked on done */
4388 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4389 TnyHeaderFlags flags;
4390 ModestMsgEditFormat old_format, new_format;
4392 /* Set priority flags */
4393 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4394 if (priv->priority_flags != flags)
4395 modest_msg_edit_window_set_priority_flags (window, flags);
4397 /* Set edit format */
4398 old_format = modest_msg_edit_window_get_format (window);
4399 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4400 if (old_format != new_format) {
4401 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4402 modest_msg_edit_window_set_file_format (window, file_format);
4406 gtk_widget_destroy (dialog);
4407 g_slist_free (helper.priority_group);
4412 on_message_settings (GtkAction *action,
4413 ModestMsgEditWindow *window)
4415 modest_msg_edit_window_show_msg_settings_dialog (window);
4419 on_cc_button_toggled (GtkWidget *button,
4420 ModestMsgEditWindow *window)
4422 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4424 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4425 modest_togglable_get_active (button));
4429 on_bcc_button_toggled (GtkWidget *button,
4430 ModestMsgEditWindow *window)
4432 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4434 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4435 modest_togglable_get_active (button));
4439 setup_menu (ModestMsgEditWindow *self)
4441 ModestMsgEditWindowPrivate *priv = NULL;
4443 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4445 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4447 /* Settings menu buttons */
4448 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4449 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4451 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4452 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4453 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4454 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4455 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4456 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4458 #ifdef MODEST_TOOLKIT_HILDON2
4459 priv->cc_button = hildon_check_button_new (0);
4460 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4461 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4463 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4464 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4465 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4467 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4468 _("mcen_me_editor_showbcc"));
4469 modest_togglable_set_active (priv->bcc_button,
4471 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4473 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4474 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4477 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4478 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4479 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4480 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4481 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4483 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4484 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4485 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4486 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4487 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4489 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4490 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4495 emit_open_addressbook (GtkButton *button,
4496 ModestRecptEditor *editor)
4498 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4502 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4503 const gchar *label, GtkWidget *control)
4505 GtkWidget *abook_button;
4508 GtkWidget *label_widget;
4510 box = gtk_hbox_new (FALSE, 0);
4512 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4513 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4515 #ifdef MODEST_TOOLKIT_HILDON2
4516 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4518 abook_button = gtk_button_new ();
4520 label_widget = gtk_label_new (label);
4521 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4522 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4524 gtk_container_add (GTK_CONTAINER (align), abook_button);
4525 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4526 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4527 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4528 if (title_size_group)
4529 gtk_size_group_add_widget (title_size_group, label_widget);
4530 if (value_size_group)
4531 gtk_size_group_add_widget (value_size_group, control);
4533 g_signal_connect (G_OBJECT (abook_button), "clicked",
4534 G_CALLBACK (emit_open_addressbook), control);
4540 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4542 ModestMsgEditWindowPrivate *priv = NULL;
4544 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4547 priv->max_chars_banner = NULL;
4551 has_pending_addresses (ModestRecptEditor *recpt_editor)
4553 const gchar *recipients = NULL;
4554 GSList *start_indexes = NULL, *end_indexes = NULL;
4555 GSList *current_start, *current_end;
4556 GtkTextBuffer *buffer;
4557 gint offset_delta = 0;
4559 gboolean has_recipients_to_add = FALSE;
4561 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4562 last_length = g_utf8_strlen (recipients, -1);
4563 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4568 current_start = start_indexes;
4569 current_end = end_indexes;
4570 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4572 while (current_start && !has_recipients_to_add) {
4574 gchar *start_ptr, *end_ptr;
4575 gint start_pos, end_pos;
4577 start_pos = (*((gint*) current_start->data)) + offset_delta;
4578 end_pos = (*((gint*) current_end->data)) + offset_delta;
4580 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4581 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4583 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4585 if (modest_text_utils_validate_recipient (address, NULL)) {
4586 if (!modest_address_book_has_address (address)) {
4587 has_recipients_to_add = TRUE;
4590 current_start = g_slist_next (current_start);
4591 current_end = g_slist_next (current_end);
4593 return has_recipients_to_add;
4597 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4599 ModestMsgEditWindowPrivate *priv = NULL;
4601 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4603 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4605 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4606 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4607 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))