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,
366 MODEST_TYPE_SHELL_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 parent_priv->menubar = NULL;
897 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
898 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
900 /* Note: This ModestPairList* must exist for as long as the picker
901 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
902 * so it can't know how to manage its memory. */
903 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
905 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
906 if (GTK_IS_COMBO_BOX (priv->from_field)) {
907 from_caption = modest_toolkit_utils_create_captioned (title_size_group, NULL,
908 _("mail_va_from"), FALSE,
910 gtk_widget_show (from_caption);
912 #ifdef MODEST_TOOLKIT_HILDON2
913 modest_toolkit_utils_set_hbutton_layout (title_size_group, NULL,
914 _("mail_va_from"), priv->from_field);
915 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
916 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
917 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
918 from_caption = priv->from_field;
922 priv->to_field = modest_recpt_editor_new ();
923 priv->cc_field = modest_recpt_editor_new ();
924 priv->bcc_field = modest_recpt_editor_new ();
925 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
926 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
927 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
928 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
929 priv->priority_icon = gtk_image_new ();
930 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
931 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
932 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
933 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
934 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
936 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
937 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
939 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
940 priv->attachments_view = modest_attachments_view_new (NULL);
941 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
942 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
944 priv->header_box = gtk_vbox_new (FALSE, 0);
946 to_caption = _create_addressbook_box
947 (title_size_group, value_size_group,
948 _("mail_va_to"), priv->to_field);
949 priv->cc_caption = _create_addressbook_box
950 (title_size_group, value_size_group,
951 _("mail_va_cc"), priv->cc_field);
952 priv->bcc_caption = _create_addressbook_box
953 (title_size_group, value_size_group,
954 _("mail_va_hotfix1"), priv->bcc_field);
955 subject_caption = modest_toolkit_utils_create_captioned (title_size_group, value_size_group,
956 _("mail_va_subject"), FALSE, priv->subject_box);
957 priv->attachments_caption = modest_toolkit_utils_create_captioned_with_size_type (NULL, NULL,
958 _("mail_va_attachment"),
960 priv->attachments_view,
961 #ifdef MODEST_TOOLKIT_HILDON2
962 HILDON_SIZE_AUTO_WIDTH |
963 HILDON_SIZE_AUTO_HEIGHT
968 attachments_label = modest_toolkit_utils_captioned_get_label_widget (priv->attachments_caption);
970 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
974 #ifdef MODEST_TOOLKIT_HILDON2
975 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
976 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
978 priv->send_button = gtk_button_new ();
979 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, GTK_ICON_SIZE_BUTTON);
981 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
982 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
984 g_object_unref (title_size_group);
985 g_object_unref (value_size_group);
987 priv->brand_icon = gtk_image_new ();
988 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
989 priv->brand_label = gtk_label_new (NULL);
990 #ifdef MODEST_TOOLKIT_HILDON2
991 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
993 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
994 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
995 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
997 from_send_hbox = gtk_hbox_new (FALSE, 0);
998 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
999 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
1001 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
1002 gtk_widget_show (branding_box);
1003 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
1004 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
1006 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
1007 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1008 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
1009 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
1012 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
1013 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
1014 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
1015 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
1016 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
1017 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
1018 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
1019 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1021 init_wp_text_view_style ();
1023 priv->msg_body = modest_wp_text_view_new ();
1026 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1027 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1028 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1029 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1030 #if (GTK_MINOR_VERSION >= 10)
1031 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1032 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1034 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1035 deserialize_type, TRUE);
1037 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1039 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1041 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1043 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1045 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1047 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1049 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1050 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1051 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1053 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1054 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1055 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1057 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1058 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1060 window_box = gtk_vbox_new (FALSE, 0);
1061 gtk_container_add (GTK_CONTAINER(obj), window_box);
1063 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1068 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1070 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1072 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1073 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1074 priv->clipboard_change_handler_id))
1075 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1076 priv->clipboard_change_handler_id);
1077 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1078 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1079 priv->default_clipboard_change_handler_id))
1080 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1081 priv->default_clipboard_change_handler_id);
1083 if (priv->account_removed_handler_id &&
1084 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1085 priv->account_removed_handler_id))
1086 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1087 priv->account_removed_handler_id);
1091 modest_msg_edit_window_finalize (GObject *obj)
1093 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1095 if (priv->max_chars_banner) {
1096 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1097 priv->max_chars_banner = FALSE;
1100 /* Sanity check: shouldn't be needed, the window mgr should
1101 call this function before */
1102 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1104 if (priv->font_dialog != NULL) {
1105 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1108 if (priv->clipboard_text != NULL) {
1109 g_free (priv->clipboard_text);
1110 priv->clipboard_text = NULL;
1113 if (priv->draft_msg != NULL) {
1114 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1115 if (TNY_IS_HEADER (header)) {
1116 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1117 modest_window_mgr_unregister_header (mgr, header);
1119 g_object_unref (priv->draft_msg);
1120 priv->draft_msg = NULL;
1122 if (priv->outbox_msg != NULL) {
1123 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1124 if (TNY_IS_HEADER (header)) {
1125 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1126 modest_window_mgr_unregister_header (mgr, header);
1128 g_object_unref (priv->outbox_msg);
1129 priv->outbox_msg = NULL;
1131 if (priv->correct_scroll_idle > 0) {
1132 g_source_remove (priv->correct_scroll_idle);
1133 priv->correct_scroll_idle = 0;
1135 if (priv->scroll_drag_timeout_id > 0) {
1136 g_source_remove (priv->scroll_drag_timeout_id);
1137 priv->scroll_drag_timeout_id = 0;
1139 if (priv->clipboard_owner_idle > 0) {
1140 g_source_remove (priv->clipboard_owner_idle);
1141 priv->clipboard_owner_idle = 0;
1143 if (priv->original_account_name)
1144 g_free (priv->original_account_name);
1145 if (priv->original_mailbox)
1146 g_free (priv->original_mailbox);
1147 g_free (priv->msg_uid);
1148 g_free (priv->last_search);
1149 g_free (priv->references);
1150 g_free (priv->in_reply_to);
1151 g_object_unref (priv->attachments);
1152 g_object_unref (priv->images);
1154 /* This had to stay alive for as long as the picker that used it: */
1155 modest_pair_list_free (priv->from_field_protos);
1157 G_OBJECT_CLASS(parent_class)->finalize (obj);
1161 pixbuf_size_prepared (GdkPixbufLoader *loader,
1164 ModestMsgEditWindow *self)
1166 gint new_height, new_width;
1169 new_height = height;
1173 if (width > IMAGE_MAX_WIDTH) {
1174 new_height = height * IMAGE_MAX_WIDTH / width;
1175 new_width = IMAGE_MAX_WIDTH;
1178 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1182 pixbuf_from_stream (TnyStream *stream,
1183 const gchar *mime_type,
1184 guint64 *stream_size,
1185 ModestMsgEditWindow *self)
1187 GdkPixbufLoader *loader;
1190 GError *error = NULL;
1194 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1196 if (loader == NULL) {
1201 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1203 modest_window_show_progress (MODEST_WINDOW (self), TRUE);
1205 tny_stream_reset (TNY_STREAM (stream));
1206 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1207 unsigned char read_buffer[128];
1209 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1211 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1214 /* Allow some UI responsiveness */
1215 while (gtk_events_pending ())
1216 gtk_main_iteration ();
1218 modest_window_show_progress (MODEST_WINDOW (self), FALSE);
1220 gdk_pixbuf_loader_close (loader, &error);
1223 g_error_free (error);
1224 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1226 g_object_ref (pixbuf);
1227 g_object_unref (loader);
1232 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1233 GdkPixbuf *new_pixbuf;
1235 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1236 gdk_pixbuf_get_width (pixbuf);
1237 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1238 g_object_unref (pixbuf);
1239 pixbuf = new_pixbuf;
1243 *stream_size = size;
1249 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1251 ModestMsgEditWindowPrivate *priv;
1254 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1256 g_object_ref (self);
1257 for (iter = tny_list_create_iterator (attachments);
1258 !tny_iterator_is_done (iter);
1259 tny_iterator_next (iter)) {
1260 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1261 const gchar *cid = tny_mime_part_get_content_id (part);
1262 const gchar *mime_type = tny_mime_part_get_content_type (part);
1263 if ((cid != NULL)&&(mime_type != NULL)) {
1264 guint64 stream_size;
1265 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1266 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1269 g_object_unref (stream);
1271 if (pixbuf != NULL) {
1272 priv->images_count ++;
1273 priv->images_size += stream_size;
1274 #ifndef MODEST_HAVE_LIBWPEDITOR_PLUS
1275 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1277 g_object_unref (pixbuf);
1280 g_object_unref (part);
1282 g_object_unref (iter);
1283 g_object_unref (self);
1287 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1289 TnyMimePart *parent = NULL;
1290 const gchar *content_type = NULL;
1291 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1293 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1295 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1296 parent = g_object_ref (msg);
1297 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1298 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1301 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1302 iter = tny_list_create_iterator (parts);
1303 while (!tny_iterator_is_done (iter)) {
1305 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1306 content_type = tny_mime_part_get_content_type (part);
1307 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1311 g_object_unref (part);
1313 tny_iterator_next (iter);
1315 g_object_unref (iter);
1316 g_object_unref (parts);
1319 if (parent != NULL) {
1320 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1323 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1324 iter = tny_list_create_iterator (parts);
1325 while (!tny_iterator_is_done (iter)) {
1327 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1328 content_type = tny_mime_part_get_content_type (part);
1329 if (content_type && g_str_has_prefix (content_type, "image/")) {
1330 tny_list_prepend (priv->images, (GObject *) part);
1332 g_object_unref (part);
1333 tny_iterator_next (iter);
1335 g_object_unref (iter);
1336 g_object_unref (parts);
1337 g_object_unref (parent);
1342 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1345 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1347 for (iter = tny_list_create_iterator (attachments) ;
1348 !tny_iterator_is_done (iter);
1349 tny_iterator_next (iter)) {
1350 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1351 const gchar *cid = tny_mime_part_get_content_id (part);
1353 char *invalid = NULL;
1354 gint int_cid = strtol (cid, &invalid, 10);
1355 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1356 priv->next_cid = int_cid + 1;
1359 g_object_unref (part);
1361 g_object_unref (iter);
1365 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1368 gchar *to, *cc, *bcc, *subject;
1370 ModestMsgEditWindowPrivate *priv;
1371 ModestWindowPrivate *parent_priv;
1373 TnyHeaderFlags priority_flags;
1374 TnyFolder *msg_folder;
1375 gboolean is_html = FALSE;
1376 gboolean field_view_set;
1378 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1379 g_return_if_fail (TNY_IS_MSG (msg));
1381 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1382 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1384 header = tny_msg_get_header (msg);
1385 to = tny_header_dup_to (header);
1386 cc = tny_header_dup_cc (header);
1387 bcc = tny_header_dup_bcc (header);
1388 subject = tny_header_dup_subject (header);
1390 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1391 priority_flags = tny_header_get_priority (header);
1394 gchar *quoted_names = modest_text_utils_quote_names (to);
1395 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1396 g_free (quoted_names);
1399 field_view_set = TRUE;
1401 gchar *quoted_names = modest_text_utils_quote_names (cc);
1402 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1403 g_free (quoted_names);
1404 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1405 gtk_widget_show (priv->cc_caption);
1406 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1407 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1408 gtk_widget_hide (priv->cc_caption);
1409 field_view_set = FALSE;
1411 modest_togglable_set_active (priv->cc_button, field_view_set);
1413 field_view_set = TRUE;
1415 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1416 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1417 g_free (quoted_names);
1418 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1419 gtk_widget_show (priv->bcc_caption);
1420 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1421 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1422 gtk_widget_hide (priv->bcc_caption);
1423 field_view_set = FALSE;
1425 modest_togglable_set_active (priv->bcc_button, field_view_set);
1429 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1430 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1433 update_window_title (self);
1435 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1436 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1438 if ((body == NULL)||(body[0] == '\0')) {
1440 body = modest_text_utils_convert_to_html ("");
1443 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1444 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1447 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1450 /* Add attachments to the view */
1451 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1452 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1453 if (tny_list_get_length (priv->attachments) == 0) {
1454 gtk_widget_hide (priv->attachments_caption);
1456 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1457 gtk_widget_show_all (priv->attachments_caption);
1459 get_related_images (self, msg);
1460 update_next_cid (self, priv->attachments);
1461 update_next_cid (self, priv->images);
1462 replace_with_images (self, priv->images);
1464 if (preserve_is_rich && !is_html) {
1465 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1466 /* Get the default format required from configuration */
1467 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1468 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1471 /* Set the default focus depending on having already a To: field or not */
1472 if ((!to)||(*to == '\0')) {
1473 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1475 gtk_widget_grab_focus (priv->msg_body);
1478 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1480 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1481 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1483 modest_msg_edit_window_set_modified (self, FALSE);
1485 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1486 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1487 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1488 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1490 if (priv->msg_uid) {
1491 g_free (priv->msg_uid);
1492 priv->msg_uid = NULL;
1495 /* we should set a reference to the incoming message if it is a draft */
1496 msg_folder = tny_msg_get_folder (msg);
1498 if (modest_tny_folder_is_local_folder (msg_folder)) {
1499 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1500 if (type == TNY_FOLDER_TYPE_INVALID)
1501 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1503 if (type == TNY_FOLDER_TYPE_DRAFTS)
1504 priv->draft_msg = g_object_ref(msg);
1505 if (type == TNY_FOLDER_TYPE_OUTBOX)
1506 priv->outbox_msg = g_object_ref(msg);
1507 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1509 g_object_unref (msg_folder);
1519 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1521 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1522 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1523 GtkWidget *placeholder;
1524 GtkWidget *tool_item;
1529 GtkWidget *sizes_menu;
1530 GtkWidget *fonts_menu;
1536 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1537 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1538 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar),
1539 #ifdef MODEST_TOOLKIT_HILDON2
1540 HILDON_ICON_SIZE_FINGER
1542 GTK_ICON_SIZE_LARGE_TOOLBAR
1545 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1547 /* Font color placeholder */
1548 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1549 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1552 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1553 #ifdef MODEST_TOOLKIT_HILDON2
1554 priv->font_color_button = modest_color_button_new ();
1556 priv->font_color_button = gtk_color_button_new ();
1558 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1559 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1560 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1561 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1562 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1563 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1564 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1565 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1567 G_CALLBACK (modest_msg_edit_window_color_button_change),
1570 /* Font size and face placeholder */
1571 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1572 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1574 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1575 priv->size_tool_button_label = gtk_label_new (NULL);
1576 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1577 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1578 size_text, "</span>", NULL);
1579 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1580 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1582 #ifdef MODEST_TOOLKIT_HILDON2
1583 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1585 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1586 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1587 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1588 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1589 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1590 gtk_widget_set_sensitive (arrow, FALSE);
1591 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1592 sizes_menu = gtk_menu_new ();
1593 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1594 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1597 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1598 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1600 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1604 if (wp_font_size[size_index] == 12)
1605 priv->current_size_index = size_index;
1609 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1610 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1611 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1612 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1613 priv->font_size_toolitem = tool_item;
1616 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1617 priv->font_tool_button_label = gtk_label_new (NULL);
1618 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1619 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1620 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1622 #ifdef MODEST_TOOLKIT_HILDON2
1623 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1625 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1626 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1627 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1628 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1629 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1630 gtk_widget_set_sensitive (arrow, FALSE);
1631 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1632 fonts_menu = gtk_menu_new ();
1633 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1634 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1637 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1639 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1640 0, wp_get_font_name (font_index),
1643 if (font_index == DEFAULT_FONT)
1644 priv->current_face_index = font_index;
1646 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1647 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1648 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1649 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1650 priv->font_face_toolitem = tool_item;
1652 /* Set expand and homogeneous for remaining items */
1653 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1654 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1655 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1656 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1657 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1658 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1660 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1661 will not show the tool items added to the placeholders) */
1662 gtk_widget_show_all (parent_priv->toolbar);
1664 /* Set the no show all *after* showing all items. We do not
1665 want the toolbar to be shown with a show all because it
1666 could go agains the gconf setting regarding showing or not
1667 the toolbar of the editor window */
1668 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1674 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1677 ModestWindowPrivate *parent_priv;
1678 ModestMsgEditWindowPrivate *priv;
1679 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1680 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1681 ModestWindowMgr *mgr = NULL;
1683 g_return_val_if_fail (msg, NULL);
1684 g_return_val_if_fail (account_name, NULL);
1686 mgr = modest_runtime_get_window_mgr ();
1688 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1690 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1691 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1693 /* Menubar. Update the state of some toggles */
1694 priv->from_field_protos = get_transports ();
1695 priv->original_mailbox = NULL;
1696 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1697 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1698 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1699 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1700 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1701 priv->original_mailbox = g_strdup (mailbox);
1702 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1703 /* We set the first mailbox as the active mailbox */
1704 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1705 if (priv->original_mailbox != NULL)
1706 modest_selector_set_active_id (priv->from_field,
1707 (gpointer) priv->original_mailbox);
1709 modest_selector_set_active_id (priv->from_field,
1710 (gpointer) account_name);
1712 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1714 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1715 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1716 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1717 #ifdef HILDON_TOOLKIT_HILDON2
1718 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1720 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1721 hildon_touch_selector_get_current_text
1722 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1725 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1726 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1729 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1731 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1733 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1734 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1736 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1738 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1739 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1740 /* Add common dimming rules */
1741 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1742 modest_msg_edit_window_toolbar_dimming_entries,
1743 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1744 MODEST_WINDOW (obj));
1745 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1746 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1747 MODEST_WINDOW (obj));
1748 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1749 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1750 MODEST_WINDOW (obj));
1751 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1752 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1753 MODEST_WINDOW (obj));
1754 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1755 G_CALLBACK (modest_ui_dimming_rules_on_send),
1756 MODEST_WINDOW (obj));
1757 /* Insert dimming rules group for this window */
1758 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1759 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1761 /* Setup app menu */
1762 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1764 /* Checks the dimming rules */
1765 g_object_unref (toolbar_rules_group);
1766 g_object_unref (clipboard_rules_group);
1767 gtk_widget_hide (priv->priority_icon);
1768 gtk_widget_queue_resize (priv->subject_box);
1769 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1771 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1773 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1774 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1775 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1776 priv->update_caption_visibility = TRUE;
1778 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1780 /* Track account-removed signal, this window should be closed
1781 in the case we're creating a mail associated to the account
1783 priv->account_removed_handler_id =
1784 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1786 G_CALLBACK(on_account_removed),
1789 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1791 return (ModestWindow*) obj;
1795 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1797 GString **string_buffer = (GString **) user_data;
1799 *string_buffer = g_string_append (*string_buffer, buffer);
1805 * @result: A new string which should be freed with g_free().
1808 get_formatted_data (ModestMsgEditWindow *edit_window)
1810 ModestMsgEditWindowPrivate *priv;
1811 GString *string_buffer = g_string_new ("");
1813 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1815 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1817 modest_text_utils_hyperlinkify (string_buffer);
1819 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1821 return g_string_free (string_buffer, FALSE);
1826 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1829 const gchar *account_name;
1830 ModestMsgEditWindowPrivate *priv;
1831 TnyIterator *att_iter;
1832 const gchar *picker_active_id;
1834 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1836 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1838 picker_active_id = modest_selector_get_active_id (priv->from_field);
1839 g_return_val_if_fail (picker_active_id, NULL);
1840 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1842 /* don't free these (except from) */
1843 data = g_slice_new0 (MsgData);
1844 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1845 data->account_name = g_strdup (account_name);
1846 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1847 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1848 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1849 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1850 data->references = g_strdup (priv->references);
1851 data->in_reply_to = g_strdup (priv->in_reply_to);
1852 if (priv->draft_msg) {
1853 data->draft_msg = g_object_ref (priv->draft_msg);
1854 } else if (priv->outbox_msg) {
1855 data->draft_msg = g_object_ref (priv->outbox_msg);
1857 data->draft_msg = NULL;
1860 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1862 gtk_text_buffer_get_bounds (buf, &b, &e);
1863 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1865 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1866 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1868 data->html_body = NULL;
1870 /* deep-copy the data */
1871 att_iter = tny_list_create_iterator (priv->attachments);
1872 data->attachments = NULL;
1873 while (!tny_iterator_is_done (att_iter)) {
1874 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1875 if (!(TNY_IS_MIME_PART(part))) {
1876 g_warning ("strange data in attachment list");
1877 g_object_unref (part);
1878 tny_iterator_next (att_iter);
1881 data->attachments = g_list_append (data->attachments,
1883 tny_iterator_next (att_iter);
1885 g_object_unref (att_iter);
1887 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1888 att_iter = tny_list_create_iterator (priv->images);
1889 data->images = NULL;
1890 while (!tny_iterator_is_done (att_iter)) {
1891 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1893 if (!(TNY_IS_MIME_PART(part))) {
1894 g_warning ("strange data in attachment list");
1895 g_object_unref (part);
1896 tny_iterator_next (att_iter);
1899 cid = tny_mime_part_get_content_id (part);
1901 gchar *image_tag_id;
1902 GtkTextTag *image_tag;
1904 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1905 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1906 g_free (image_tag_id);
1908 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1910 ((gtk_text_iter_has_tag (&iter, image_tag))||
1911 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1912 data->images = g_list_append (data->images,
1913 g_object_ref (part));
1915 g_object_unref (part);
1916 tny_iterator_next (att_iter);
1918 g_object_unref (att_iter);
1920 data->priority_flags = priv->priority_flags;
1927 unref_gobject (GObject *obj, gpointer data)
1929 if (!G_IS_OBJECT(obj))
1931 g_object_unref (obj);
1935 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1938 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1946 g_free (data->from);
1947 g_free (data->subject);
1948 g_free (data->plain_body);
1949 g_free (data->html_body);
1950 g_free (data->account_name);
1951 g_free (data->references);
1952 g_free (data->in_reply_to);
1954 if (data->draft_msg != NULL) {
1955 g_object_unref (data->draft_msg);
1956 data->draft_msg = NULL;
1959 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1960 g_list_free (data->attachments);
1961 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1962 g_list_free (data->images);
1964 g_slice_free (MsgData, data);
1968 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1970 guint64 *parts_size)
1972 ModestMsgEditWindowPrivate *priv;
1974 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1976 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1978 /* TODO: add images */
1979 *parts_size += priv->images_size;
1980 *parts_count += priv->images_count;
1985 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1988 ModestMsgEditWindowPrivate *priv = NULL;
1989 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1991 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1993 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1995 return MODEST_MSG_EDIT_FORMAT_HTML;
1997 return MODEST_MSG_EDIT_FORMAT_TEXT;
2001 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
2002 ModestMsgEditFormat format)
2004 ModestMsgEditWindowPrivate *priv;
2005 ModestWindowPrivate *parent_priv;
2007 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2008 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2009 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2012 case MODEST_MSG_EDIT_FORMAT_HTML:
2013 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2014 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
2016 case MODEST_MSG_EDIT_FORMAT_TEXT:
2017 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2018 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
2021 g_return_if_reached ();
2025 ModestMsgEditFormatState *
2026 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2028 ModestMsgEditFormatState *format_state = NULL;
2029 ModestMsgEditWindowPrivate *priv;
2030 WPTextBufferFormat *buffer_format;
2032 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2034 buffer_format = g_new0 (WPTextBufferFormat, 1);
2035 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2037 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2039 format_state = g_new0 (ModestMsgEditFormatState, 1);
2040 format_state->bold = buffer_format->bold&0x1;
2041 format_state->italics = buffer_format->italic&0x1;
2042 format_state->bullet = buffer_format->bullet&0x1;
2043 format_state->color = buffer_format->color;
2044 format_state->font_size = buffer_format->font_size;
2045 format_state->font_family = wp_get_font_name (buffer_format->font);
2046 format_state->justification = buffer_format->justification;
2047 g_free (buffer_format);
2049 return format_state;
2054 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2055 const ModestMsgEditFormatState *format_state)
2057 ModestMsgEditWindowPrivate *priv;
2058 WPTextBufferFormat *buffer_format;
2059 WPTextBufferFormat *current_format;
2061 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2062 g_return_if_fail (format_state != NULL);
2064 buffer_format = g_new0 (WPTextBufferFormat, 1);
2065 current_format = g_new0 (WPTextBufferFormat, 1);
2067 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2068 gtk_widget_grab_focus (priv->msg_body);
2069 buffer_format->bold = (format_state->bold != FALSE);
2070 buffer_format->italic = (format_state->italics != FALSE);
2071 buffer_format->color = format_state->color;
2072 buffer_format->font_size = format_state->font_size;
2073 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2074 buffer_format->justification = format_state->justification;
2075 buffer_format->bullet = format_state->bullet;
2077 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2079 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2080 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2081 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2082 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2083 buffer_format->cs.font = (buffer_format->font != current_format->font);
2084 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2085 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2087 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2088 if (buffer_format->cs.bold) {
2089 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2090 GINT_TO_POINTER (buffer_format->bold&0x1));
2092 if (buffer_format->cs.italic) {
2093 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2094 GINT_TO_POINTER (buffer_format->italic&0x1));
2096 if (buffer_format->cs.color) {
2097 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2098 GINT_TO_POINTER (&(buffer_format->color)));
2100 if (buffer_format->cs.font_size) {
2101 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2102 GINT_TO_POINTER (buffer_format->font_size));
2104 if (buffer_format->cs.justification) {
2105 switch (buffer_format->justification) {
2106 case GTK_JUSTIFY_LEFT:
2107 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2108 GINT_TO_POINTER(TRUE));
2110 case GTK_JUSTIFY_CENTER:
2111 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2112 GINT_TO_POINTER(TRUE));
2114 case GTK_JUSTIFY_RIGHT:
2115 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2116 GINT_TO_POINTER(TRUE));
2123 if (buffer_format->cs.font) {
2124 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2125 GINT_TO_POINTER (buffer_format->font));
2127 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2128 if (buffer_format->cs.bullet) {
2129 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2130 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2132 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2134 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2136 g_free (buffer_format);
2137 g_free (current_format);
2139 /* Check dimming rules */
2140 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2141 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2145 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2147 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2149 ModestWindowPrivate *parent_priv;
2150 ModestMsgEditWindowPrivate *priv;
2152 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2153 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2155 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2156 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2157 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2158 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2160 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2161 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2162 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2165 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2167 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2168 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2170 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2171 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2173 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2174 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2177 switch (buffer_format->justification)
2179 case GTK_JUSTIFY_LEFT:
2180 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2182 case GTK_JUSTIFY_CENTER:
2183 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2185 case GTK_JUSTIFY_RIGHT:
2186 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2193 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2195 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2196 G_CALLBACK (modest_msg_edit_window_color_button_change),
2198 #ifdef MODEST_TOOLKIT_HILDON2
2199 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2201 gtk_color_button_set_color (GTK_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2203 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2204 G_CALLBACK (modest_msg_edit_window_color_button_change),
2207 if (priv->current_size_index != buffer_format->font_size) {
2211 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2212 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2216 priv->current_size_index = buffer_format->font_size;
2218 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2219 markup = g_strconcat ("<span font_family='Sans'>",
2220 size_text, "</span>", NULL);
2222 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2226 gtk_tree_path_free (path);
2229 if (priv->current_face_index != buffer_format->font) {
2233 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2234 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2238 priv->current_face_index = buffer_format->font;
2239 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2240 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2241 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2248 g_free (buffer_format);
2254 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2256 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2257 ModestMsgEditWindowPrivate *priv;
2258 GtkWidget *dialog = NULL;
2260 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2261 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2263 #ifdef MODEST_TOOLKIT_HILDON2
2264 dialog = hildon_color_chooser_new ();
2265 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2266 g_free (buffer_format);
2268 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2270 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2271 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2274 gtk_widget_destroy (dialog);
2276 dialog = gtk_color_selection_dialog_new (NULL);
2277 GtkWidget *selection;
2279 g_object_get (G_OBJECT (dialog), "color_selection", &selection, NULL);
2280 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2281 gtk_color_selection_set_previous_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2282 g_free (buffer_format);
2284 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2286 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION(selection), &col);
2287 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2290 gtk_widget_destroy (dialog);
2297 create_stream_for_uri (const gchar* uri)
2302 TnyStream *result = NULL;
2304 GnomeVFSHandle *handle = NULL;
2305 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2306 if (test == GNOME_VFS_OK) {
2307 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2308 /* Streams over OBEX (Bluetooth) are not seekable but
2309 * we expect them to be (we might need to read them
2310 * several times). So if this is a Bluetooth URI just
2311 * read the whole file into memory (this is not a fast
2312 * protocol so we can assume that these files are not
2313 * going to be very big) */
2314 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2315 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2316 TnyStream *memstream = tny_camel_mem_stream_new ();
2317 tny_stream_write_to_stream (vfssstream, memstream);
2318 g_object_unref (vfssstream);
2321 result = vfssstream;
2329 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2332 ModestMsgEditWindowPrivate *priv;
2333 GtkWidget *dialog = NULL;
2335 GSList *uris = NULL;
2336 GSList *uri_node = NULL;
2338 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2340 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2341 _("mcen_ia_select_inline_image_title"),
2342 (GtkWindow *) window,
2343 GTK_FILE_CHOOSER_ACTION_OPEN);
2344 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2346 #ifdef MODEST_TOOLKIT_HILDON2
2347 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2350 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2351 GTK_WINDOW (dialog), GTK_WINDOW (window));
2353 response = gtk_dialog_run (GTK_DIALOG (dialog));
2355 case GTK_RESPONSE_OK:
2357 gchar *current_folder;
2358 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2359 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2360 if (current_folder && current_folder != '\0') {
2362 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2363 current_folder, &err);
2365 g_debug ("Error storing latest used folder: %s", err->message);
2369 g_free (current_folder);
2375 gtk_widget_destroy (dialog);
2377 g_object_ref (window);
2378 /* The operation could take some time so allow the dialog to be closed */
2379 while (gtk_events_pending ())
2380 gtk_main_iteration ();
2382 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2384 GnomeVFSHandle *handle = NULL;
2385 GnomeVFSResult result;
2386 GtkTextIter position;
2387 GtkTextMark *insert_mark;
2389 uri = (const gchar *) uri_node->data;
2390 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2391 if (result == GNOME_VFS_OK) {
2393 GnomeVFSFileInfo *info;
2394 gchar *filename, *basename, *escaped_filename;
2395 TnyMimePart *mime_part;
2397 const gchar *mime_type = NULL;
2398 GnomeVFSURI *vfs_uri;
2399 guint64 stream_size;
2401 gnome_vfs_close (handle);
2402 vfs_uri = gnome_vfs_uri_new (uri);
2404 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2405 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2406 g_free (escaped_filename);
2407 gnome_vfs_uri_unref (vfs_uri);
2408 info = gnome_vfs_file_info_new ();
2410 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2411 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2413 mime_type = gnome_vfs_file_info_get_mime_type (info);
2415 mime_part = tny_platform_factory_new_mime_part
2416 (modest_runtime_get_platform_factory ());
2418 TnyStream *stream = create_stream_for_uri (uri);
2420 if (stream == NULL) {
2422 modest_platform_information_banner (NULL, NULL,
2423 _FM("sfil_ib_opening_not_allowed"));
2425 g_object_unref (mime_part);
2426 gnome_vfs_file_info_unref (info);
2430 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2432 content_id = g_strdup_printf ("%d", priv->next_cid);
2433 tny_mime_part_set_content_id (mime_part, content_id);
2434 g_free (content_id);
2437 basename = g_path_get_basename (filename);
2438 tny_mime_part_set_filename (mime_part, basename);
2441 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2443 if (pixbuf != NULL) {
2444 priv->images_size += stream_size;
2445 priv->images_count ++;
2446 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2447 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2448 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2449 tny_mime_part_get_content_id (mime_part), pixbuf);
2450 g_object_unref (pixbuf);
2452 tny_list_prepend (priv->images, (GObject *) mime_part);
2453 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2455 modest_platform_information_banner (NULL, NULL,
2456 _("mail_ib_file_operation_failed"));
2460 g_object_unref (mime_part);
2461 gnome_vfs_file_info_unref (info);
2465 g_object_unref (window);
2469 on_attach_file_response (GtkDialog *dialog,
2473 GSList *uris = NULL;
2475 GnomeVFSFileSize total_size, allowed_size;
2476 ModestMsgEditWindow *window;
2477 ModestMsgEditWindowPrivate *priv;
2482 case GTK_RESPONSE_OK:
2484 gchar *current_folder;
2486 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2487 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2488 if (current_folder && current_folder != '\0') {
2490 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2491 current_folder, &err);
2493 g_debug ("Error storing latest used folder: %s", err->message);
2497 g_free (current_folder);
2504 window = MODEST_MSG_EDIT_WINDOW (user_data);
2505 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2507 /* allowed size is the maximum size - what's already there */
2508 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2509 &att_num, &att_size);
2510 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2513 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2515 const gchar *uri = (const gchar *) uri_node->data;
2518 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2520 if (total_size > allowed_size) {
2521 g_debug ("%s: total size: %u",
2522 __FUNCTION__, (unsigned int)total_size);
2525 allowed_size -= total_size;
2527 g_slist_foreach (uris, (GFunc) g_free, NULL);
2528 g_slist_free (uris);
2530 gtk_widget_destroy (GTK_WIDGET (dialog));
2534 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2536 GtkWidget *dialog = NULL;
2537 ModestMsgEditWindowPrivate *priv;
2540 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2542 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2544 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2547 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2548 _("mcen_ia_select_attachment_title"),
2549 (GtkWindow *) window,
2550 GTK_FILE_CHOOSER_ACTION_OPEN);
2551 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2552 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2553 if (conf_folder && conf_folder[0] != '\0') {
2554 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2557 /* Set the default folder to documents folder */
2558 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2559 #ifdef MODEST_TOOLKIT_HILDON2
2562 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2563 ".documents", NULL);
2566 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2567 g_free (docs_folder);
2569 g_free (conf_folder);
2570 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2571 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2572 GTK_WINDOW (dialog), GTK_WINDOW (window));
2574 /* Connect to response & show */
2575 g_signal_connect (dialog, "response",
2576 G_CALLBACK (on_attach_file_response), window);
2577 gtk_widget_show (dialog);
2582 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2584 GnomeVFSFileSize allowed_size)
2587 GnomeVFSHandle *handle = NULL;
2588 ModestMsgEditWindowPrivate *priv;
2589 GnomeVFSResult result;
2590 GnomeVFSFileSize size = 0;
2591 g_return_val_if_fail (window, 0);
2592 g_return_val_if_fail (uri, 0);
2594 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2596 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2597 if (result == GNOME_VFS_OK) {
2598 TnyMimePart *mime_part;
2600 const gchar *mime_type = NULL;
2602 gchar *escaped_filename;
2605 GnomeVFSFileInfo *info;
2606 GnomeVFSURI *vfs_uri;
2608 gnome_vfs_close (handle);
2609 vfs_uri = gnome_vfs_uri_new (uri);
2612 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2613 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2614 g_free (escaped_filename);
2615 gnome_vfs_uri_unref (vfs_uri);
2617 info = gnome_vfs_file_info_new ();
2619 if (gnome_vfs_get_file_info (uri,
2621 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2623 mime_type = gnome_vfs_file_info_get_mime_type (info);
2624 mime_part = tny_platform_factory_new_mime_part
2625 (modest_runtime_get_platform_factory ());
2627 /* try to get the attachment's size; this may fail for weird
2628 * file systems, like obex, upnp... */
2629 if (allowed_size != 0 &&
2630 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2632 if (size > allowed_size) {
2633 modest_platform_information_banner (NULL, NULL,
2634 _("mail_ib_error_attachment_size"));
2639 g_debug ("%s: could not get attachment size", __FUNCTION__);
2641 stream = create_stream_for_uri (uri);
2643 if (stream == NULL) {
2645 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2647 g_object_unref (mime_part);
2649 gnome_vfs_file_info_unref (info);
2653 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2654 g_object_unref (stream);
2656 content_id = g_strdup_printf ("%d", priv->next_cid);
2657 tny_mime_part_set_content_id (mime_part, content_id);
2658 g_free (content_id);
2661 basename = g_path_get_basename (filename);
2662 tny_mime_part_set_filename (mime_part, basename);
2665 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2666 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2668 info->size == 0, info->size);
2669 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2670 gtk_widget_show_all (priv->attachments_caption);
2671 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2673 g_object_unref (mime_part);
2674 gnome_vfs_file_info_unref (info);
2681 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2684 ModestMsgEditWindowPrivate *priv;
2687 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2688 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2690 if (att_list == NULL) {
2691 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2692 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2693 g_object_unref (att_list);
2697 g_object_ref (att_list);
2700 if (tny_list_get_length (att_list) == 0) {
2701 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2703 gboolean dialog_response;
2704 gchar *message = NULL;
2705 gchar *filename = NULL;
2707 if (tny_list_get_length (att_list) == 1) {
2709 iter = tny_list_create_iterator (att_list);
2710 part = (TnyMimePart *) tny_iterator_get_current (iter);
2711 g_object_unref (iter);
2712 if (TNY_IS_MSG (part)) {
2713 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2715 filename = tny_header_dup_subject (header);
2716 g_object_unref (header);
2718 if (filename == NULL) {
2719 filename = g_strdup (_("mail_va_no_subject"));
2722 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2724 g_object_unref (part);
2726 filename = g_strdup ("");
2728 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2729 "emev_nc_delete_attachments",
2730 tny_list_get_length (att_list)), filename);
2733 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2737 if (dialog_response != GTK_RESPONSE_OK) {
2738 g_object_unref (att_list);
2742 for (iter = tny_list_create_iterator (att_list);
2743 !tny_iterator_is_done (iter);
2744 tny_iterator_next (iter)) {
2745 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2746 const gchar *att_id;
2747 tny_list_remove (priv->attachments, (GObject *) mime_part);
2749 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2751 if (tny_list_get_length (priv->attachments) == 0)
2752 gtk_widget_hide (priv->attachments_caption);
2753 att_id = tny_mime_part_get_content_id (mime_part);
2755 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2757 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2758 g_object_unref (mime_part);
2760 g_object_unref (iter);
2763 g_object_unref (att_list);
2765 /* if the last attachment has been removed, focus the Subject: field */
2766 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2767 gtk_widget_grab_focus (priv->subject_field);
2771 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2774 ModestMsgEditWindowPrivate *priv;
2777 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2779 gtk_color_button_get_color (GTK_COLOR_BUTTON(priv->font_color_button), &new_color);
2781 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2783 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2787 font_size_clicked (GtkToolButton *button,
2788 ModestMsgEditWindow *window)
2790 #ifdef MODEST_TOOLKIT_HILDON2
2791 ModestMsgEditWindowPrivate *priv;
2792 GtkWidget *selector, *dialog;
2794 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2796 selector = hildon_touch_selector_new ();
2797 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2798 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2800 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2801 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2802 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2804 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2808 WPTextBufferFormat format;
2810 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2812 memset (&format, 0, sizeof (format));
2813 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2815 format.cs.font_size = TRUE;
2816 format.cs.text_position = TRUE;
2817 format.cs.font = TRUE;
2818 format.font_size = new_index;
2819 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2821 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2822 GINT_TO_POINTER (new_index)))
2823 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2825 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2826 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2827 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2828 size_text, "</span>", NULL);
2830 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2834 gtk_widget_destroy (dialog);
2836 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2841 font_face_clicked (GtkToolButton *button,
2842 ModestMsgEditWindow *window)
2844 #ifdef MODEST_TOOLKIT_HILDON2
2845 ModestMsgEditWindowPrivate *priv;
2846 GtkWidget *selector, *dialog;
2847 GtkCellRenderer *renderer;
2849 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2851 selector = hildon_touch_selector_new ();
2852 renderer = gtk_cell_renderer_text_new ();
2853 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2854 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2855 renderer, "family", 0, "text", 0, NULL);
2856 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2858 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2859 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2860 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2862 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2863 gint new_font_index;
2867 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2868 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2869 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2873 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2875 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2876 GINT_TO_POINTER(new_font_index)))
2877 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2879 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2880 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2882 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2886 gtk_tree_path_free (path);
2889 gtk_widget_destroy (dialog);
2891 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2896 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2899 ModestMsgEditWindowPrivate *priv = NULL;
2900 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2902 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2903 if (!priv->update_caption_visibility)
2906 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2908 gtk_widget_show (priv->cc_caption);
2910 gtk_widget_hide (priv->cc_caption);
2912 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2916 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2919 ModestMsgEditWindowPrivate *priv = NULL;
2920 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2922 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2923 if (!priv->update_caption_visibility)
2926 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2928 gtk_widget_show (priv->bcc_caption);
2930 gtk_widget_hide (priv->bcc_caption);
2932 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2936 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2937 ModestRecptEditor *editor)
2939 ModestMsgEditWindowPrivate *priv;
2941 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2942 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2944 /* we check for low-mem; in that case, show a warning, and don't allow
2945 * for the addressbook
2947 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2950 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2952 if (editor == NULL) {
2953 GtkWidget *view_focus, *parent;
2954 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2956 /* This code should be kept in sync with ModestRecptEditor. The
2957 textview inside the recpt editor is the one that really gets the
2958 focus. As it's inside a scrolled window, and this one inside the
2959 hbox recpt editor inherits from, we'll need to go up in the
2960 hierarchy to know if the text view is part of the recpt editor
2961 or if it's a different text entry */
2962 parent = gtk_widget_get_parent (view_focus);
2963 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2964 editor = MODEST_RECPT_EDITOR (parent);
2967 editor = MODEST_RECPT_EDITOR (priv->to_field);
2970 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2974 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2976 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2978 modest_msg_edit_window_open_addressbook (window, NULL);
2982 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2983 gboolean show_toolbar)
2985 ModestWindowPrivate *parent_priv;
2986 ModestMsgEditWindowPrivate *priv;
2988 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2989 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2990 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2992 /* We can not just use the code of
2993 modest_msg_edit_window_setup_toolbar because it has a
2994 mixture of both initialization and creation code. */
2996 gint current_format;
2997 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2998 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2999 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3000 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3002 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
3005 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3010 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
3011 TnyHeaderFlags priority_flags)
3013 ModestMsgEditWindowPrivate *priv;
3014 ModestWindowPrivate *parent_priv;
3016 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3018 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3019 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3021 if (priv->priority_flags != priority_flags) {
3022 GtkAction *priority_action = NULL;
3024 priv->priority_flags = priority_flags;
3026 switch (priority_flags) {
3027 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3028 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3029 MODEST_HEADER_ICON_HIGH,
3030 #ifdef MODEST_TOOLKIT_HILDON2
3031 HILDON_ICON_SIZE_SMALL
3033 GTK_ICON_SIZE_BUTTON
3036 gtk_widget_show (priv->priority_icon);
3037 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3038 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3040 case TNY_HEADER_FLAG_LOW_PRIORITY:
3041 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3042 MODEST_HEADER_ICON_LOW,
3043 #ifdef MODEST_TOOLKIT_HILDON2
3044 HILDON_ICON_SIZE_SMALL
3046 GTK_ICON_SIZE_BUTTON
3049 gtk_widget_show (priv->priority_icon);
3050 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3051 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3054 gtk_widget_hide (priv->priority_icon);
3055 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3056 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3059 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3060 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3062 gtk_widget_queue_resize (priv->subject_box);
3066 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3069 ModestMsgEditWindowPrivate *priv;
3070 ModestWindowPrivate *parent_priv;
3071 gint current_format;
3073 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3075 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3076 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3078 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3079 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3081 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3083 if (current_format != file_format) {
3084 switch (file_format) {
3085 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3086 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3087 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3088 if (parent_priv->toolbar)
3089 gtk_widget_show (parent_priv->toolbar);
3091 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3094 response = modest_platform_run_confirmation_dialog (NULL, _("emev_nc_formatting_lost"));
3095 if (response == GTK_RESPONSE_OK) {
3096 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3097 if (parent_priv->toolbar)
3098 gtk_widget_hide (parent_priv->toolbar);
3100 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3101 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3106 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3107 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3108 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3113 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3115 #ifdef MODEST_TOOLKIT_HILDON2
3117 ModestMsgEditWindowPrivate *priv;
3118 WPTextBufferFormat oldfmt, fmt;
3119 gint old_position = 0;
3123 GdkColor *color = NULL;
3124 gboolean bold, bold_set, italic, italic_set;
3125 gboolean underline, underline_set;
3126 gboolean strikethrough, strikethrough_set;
3127 gboolean position_set;
3128 gboolean font_size_set, font_set, color_set;
3131 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3132 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3134 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3135 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3136 GTK_WINDOW(dialog), GTK_WINDOW (window));
3138 /* First we get the currently selected font information */
3139 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3141 switch (oldfmt.text_position) {
3142 case TEXT_POSITION_NORMAL:
3145 case TEXT_POSITION_SUPERSCRIPT:
3153 g_object_set (G_OBJECT (dialog),
3154 "bold", oldfmt.bold != FALSE,
3155 "bold-set", !oldfmt.cs.bold,
3156 "underline", oldfmt.underline != FALSE,
3157 "underline-set", !oldfmt.cs.underline,
3158 "italic", oldfmt.italic != FALSE,
3159 "italic-set", !oldfmt.cs.italic,
3160 "strikethrough", oldfmt.strikethrough != FALSE,
3161 "strikethrough-set", !oldfmt.cs.strikethrough,
3162 "color", &oldfmt.color,
3163 "color-set", !oldfmt.cs.color,
3164 "size", wp_font_size[oldfmt.font_size],
3165 "size-set", !oldfmt.cs.font_size,
3166 "position", old_position,
3167 "position-set", !oldfmt.cs.text_position,
3168 "family", wp_get_font_name (oldfmt.font),
3169 "family-set", !oldfmt.cs.font,
3172 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3173 GTK_WINDOW (dialog), GTK_WINDOW (window));
3174 gtk_widget_show_all (dialog);
3175 priv->font_dialog = dialog;
3176 response = gtk_dialog_run (GTK_DIALOG (dialog));
3177 priv->font_dialog = NULL;
3178 if (response == GTK_RESPONSE_OK) {
3180 g_object_get( dialog,
3182 "bold-set", &bold_set,
3183 "underline", &underline,
3184 "underline-set", &underline_set,
3186 "italic-set", &italic_set,
3187 "strikethrough", &strikethrough,
3188 "strikethrough-set", &strikethrough_set,
3190 "color-set", &color_set,
3192 "size-set", &font_size_set,
3193 "family", &font_name,
3194 "family-set", &font_set,
3195 "position", &position,
3196 "position-set", &position_set,
3201 if (response == GTK_RESPONSE_OK) {
3202 memset(&fmt, 0, sizeof(fmt));
3208 fmt.italic = italic;
3209 fmt.cs.italic = TRUE;
3211 if (underline_set) {
3212 fmt.underline = underline;
3213 fmt.cs.underline = TRUE;
3215 if (strikethrough_set) {
3216 fmt.strikethrough = strikethrough;
3217 fmt.cs.strikethrough = TRUE;
3222 ? TEXT_POSITION_NORMAL
3223 : ( ( position == 1 )
3224 ? TEXT_POSITION_SUPERSCRIPT
3225 : TEXT_POSITION_SUBSCRIPT );
3226 fmt.cs.text_position = TRUE;
3227 fmt.font_size = oldfmt.font_size;
3231 fmt.cs.color = TRUE;
3234 fmt.font = wp_get_font_index(font_name,
3239 if (font_size_set) {
3240 fmt.cs.font_size = TRUE;
3241 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3243 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3244 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3246 gtk_widget_destroy (dialog);
3248 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3253 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3255 ModestMsgEditWindowPrivate *priv;
3256 ModestWindowPrivate *parent_priv;
3257 gboolean was_rich_text, is_rich_text;
3259 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3260 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3261 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3263 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3265 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3267 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3269 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3271 gtk_widget_show (parent_priv->toolbar);
3273 gtk_widget_hide (parent_priv->toolbar);
3276 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3277 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3281 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3283 ModestMsgEditWindowPrivate *priv;
3285 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3286 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3288 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3290 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3291 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3296 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3298 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3300 priv->can_undo = can_undo;
3304 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3306 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3308 priv->can_redo = can_redo;
3312 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3314 ModestMsgEditWindowPrivate *priv;
3315 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3316 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3318 return priv->can_undo;
3322 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3324 ModestMsgEditWindowPrivate *priv;
3325 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3326 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3328 return priv->can_redo;
3333 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3336 GtkTextIter match_start, match_end;
3338 if (image_id == NULL)
3341 gtk_text_buffer_get_start_iter (buffer, &iter);
3343 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3344 GSList *tags = gtk_text_iter_get_tags (&match_start);
3346 for (node = tags; node != NULL; node = g_slist_next (node)) {
3347 GtkTextTag *tag = (GtkTextTag *) node->data;
3348 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3349 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3350 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3352 offset = gtk_text_iter_get_offset (&match_start);
3353 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3354 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3358 gtk_text_iter_forward_char (&iter);
3363 message_is_empty (ModestMsgEditWindow *window)
3365 ModestMsgEditWindowPrivate *priv = NULL;
3367 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3368 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3370 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3371 * so we can ignore markup.
3373 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3376 count = gtk_text_buffer_get_char_count (buf);
3382 msg_body_focus (GtkWidget *focus,
3383 GdkEventFocus *event,
3387 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3388 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3389 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3394 recpt_field_changed (GtkTextBuffer *buffer,
3395 ModestMsgEditWindow *editor)
3397 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3398 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3402 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3404 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3405 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3409 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3412 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3413 GtkTextBuffer *buffer;
3415 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3416 gtk_text_buffer_set_modified (buffer, modified);
3417 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3418 gtk_text_buffer_set_modified (buffer, modified);
3419 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3420 gtk_text_buffer_set_modified (buffer, modified);
3421 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3425 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3427 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3428 const char *account_name;
3429 GtkTextBuffer *buffer;
3431 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3432 if (gtk_text_buffer_get_modified (buffer))
3434 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3435 if (gtk_text_buffer_get_modified (buffer))
3437 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3438 if (gtk_text_buffer_get_modified (buffer))
3440 if (gtk_text_buffer_get_modified (priv->text_buffer))
3443 account_name = modest_selector_get_active_id (priv->from_field);
3444 if (priv->original_mailbox) {
3445 if (!account_name || strcmp (account_name, priv->original_mailbox))
3447 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3458 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3460 ModestMsgEditWindowPrivate *priv = NULL;
3461 GSList *address_list = NULL;
3463 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3464 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3466 /* check if there's no recipient added */
3467 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3468 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3469 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3470 /* no recipient contents, then select contacts */
3471 modest_msg_edit_window_open_addressbook (window, NULL);
3476 g_object_ref (window);
3477 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3478 (add_to_addressbook) ? &address_list : NULL)) {
3479 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3480 g_object_unref (window);
3483 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3484 (add_to_addressbook) ? &address_list : NULL)) {
3485 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3486 g_object_unref (window);
3489 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3490 (add_to_addressbook) ? &address_list : NULL)) {
3491 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3492 g_object_unref (window);
3496 /* Add contacts to address book */
3497 if (add_to_addressbook && address_list)
3498 modest_address_book_add_address_list (address_list);
3500 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3501 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3502 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3503 g_object_unref (window);
3510 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3512 GSList *recipients = NULL;
3513 ModestMsgEditWindowPrivate *priv;
3514 gchar *joined, *after_remove, *to, *cc, *bcc;
3516 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3518 /* First of all check names */
3519 if (!modest_msg_edit_window_check_names (self, FALSE))
3522 if (!modest_msg_edit_window_has_pending_addresses (self))
3525 /* Don't add the from obviously */
3526 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3527 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3528 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3530 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3535 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3538 recipients = modest_text_utils_split_addresses_list (after_remove);
3539 g_free (after_remove);
3542 /* Offer the user to add recipients to the address book */
3543 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3544 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3549 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3550 ModestMsgEditWindow *window)
3552 modest_msg_edit_window_offer_attach_file (window);
3556 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3558 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3560 return priv->clipboard_text;
3564 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3566 ModestMsgEditWindow *window)
3568 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3569 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3572 /* It could happen that the window was already closed */
3573 if (!GTK_WIDGET_VISIBLE (window))
3576 g_object_ref (window);
3577 text = gtk_clipboard_wait_for_text (selection_clipboard);
3579 if (priv->clipboard_text != NULL) {
3580 g_free (priv->clipboard_text);
3582 priv->clipboard_text = text;
3584 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3586 g_object_unref (window);
3589 static gboolean clipboard_owner_change_idle (gpointer userdata)
3591 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3592 ModestMsgEditWindowPrivate *priv;
3594 gdk_threads_enter ();
3595 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3596 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3598 priv->clipboard_owner_idle = 0;
3599 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3600 gdk_threads_leave ();
3606 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3608 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3609 if (priv->clipboard_owner_idle == 0) {
3610 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3611 clipboard_owner_change_idle,
3612 g_object_ref (window),
3618 subject_field_move_cursor (GtkEntry *entry,
3619 GtkMovementStep step,
3624 /* It could happen that the window was already closed */
3625 if (!GTK_WIDGET_VISIBLE (window))
3628 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3632 update_window_title (ModestMsgEditWindow *window)
3634 ModestMsgEditWindowPrivate *priv = NULL;
3635 const gchar *subject;
3637 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3638 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3639 if (subject == NULL || subject[0] == '\0')
3640 subject = _("mail_va_new_email");
3642 modest_window_set_title (MODEST_WINDOW (window), subject);
3648 body_insert_text (GtkTextBuffer *buffer,
3649 GtkTextIter *location,
3652 ModestMsgEditWindow *window)
3654 GtkTextIter end_iter;
3661 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3663 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3665 offset = gtk_text_iter_get_offset (&end_iter);
3666 line = gtk_text_iter_get_line (&end_iter);
3670 while (text_offset < text + len) {
3671 if (*text_offset == '\n')
3673 if (text_lines + line >= MAX_BODY_LINES) {
3674 len = text_offset - text;
3680 utf8_len = g_utf8_strlen (text, len);
3682 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3683 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3684 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3689 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3691 /* Prevent endless recursion */
3692 result = g_strndup (text, utf8_end - text);
3693 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3694 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3695 (gpointer) result, (gpointer) (utf8_end - text),
3697 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3701 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3702 if (priv->max_chars_banner == NULL) {
3703 #ifdef MODEST_TOOLKIT_HILDON2
3704 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3705 _CS_MAXIMUM_CHARACTERS_REACHED);
3706 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3713 subject_field_changed (GtkEditable *editable,
3714 ModestMsgEditWindow *window)
3716 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3717 update_window_title (window);
3718 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3719 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3720 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3723 subject_field_insert_text (GtkEditable *editable,
3725 gint new_text_length,
3727 ModestMsgEditWindow *window)
3729 GString *result = g_string_new ("");
3731 gint result_len = 0;
3732 const gchar *entry_text = NULL;
3735 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3736 old_length = g_utf8_strlen (entry_text, -1);
3738 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3739 gunichar c = g_utf8_get_char_validated (current, 8);
3740 /* Invalid unichar, stop */
3746 result = g_string_append_unichar (result, c);
3750 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3751 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3754 /* Prevent endless recursion */
3755 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3756 g_signal_emit_by_name (editable, "insert-text",
3757 (gpointer) result->str, (gpointer) result->len,
3758 (gpointer) position, (gpointer) window);
3759 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3763 if (result_len + old_length > 1000) {
3764 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3765 _CS_MAXIMUM_CHARACTERS_REACHED);
3767 g_string_free (result, TRUE);
3771 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3774 ModestMsgEditWindowPrivate *priv = NULL;
3776 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3777 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3779 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3782 gtk_widget_show_all (priv->isearch_toolbar);
3783 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3785 gtk_widget_hide_all (priv->isearch_toolbar);
3786 gtk_widget_grab_focus (priv->msg_body);
3791 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3793 GtkTextIter *match_start,
3794 GtkTextIter *match_end)
3796 GtkTextIter end_iter;
3797 gchar *str_casefold;
3800 gchar *range_casefold;
3803 gboolean result = FALSE;
3810 gtk_text_iter_forward_to_end (&end_iter);
3812 str_casefold = g_utf8_casefold (str, -1);
3813 str_chars_n = strlen (str);
3815 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3816 range_casefold = g_utf8_casefold (range_text, -1);
3817 range_chars_n = strlen (range_casefold);
3819 if (range_chars_n < str_chars_n) {
3820 g_free (str_casefold);
3821 g_free (range_text);
3822 g_free (range_casefold);
3826 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3827 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3828 if (!g_utf8_collate (range_subtext, str_casefold)) {
3829 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3831 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3832 match_start, match_end, NULL)) {
3833 g_debug ("Matched string with collate, but not matched in model");
3835 g_free (found_text);
3837 g_free (range_subtext);
3841 g_free (str_casefold);
3842 g_free (range_text);
3843 g_free (range_casefold);
3850 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
3851 ModestMsgEditWindow *window)
3853 const gchar *current_search = NULL;
3854 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3856 GtkTextIter selection_start, selection_end;
3857 GtkTextIter match_start, match_end;
3858 gboolean continue_search = FALSE;
3860 if (message_is_empty (window)) {
3861 g_free (priv->last_search);
3862 priv->last_search = NULL;
3863 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3867 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
3868 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3869 g_free (priv->last_search);
3870 priv->last_search = NULL;
3871 /* Information banner about empty search */
3872 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
3876 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3877 continue_search = TRUE;
3879 g_free (priv->last_search);
3880 priv->last_search = g_strdup (current_search);
3883 if (continue_search) {
3884 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3885 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3886 &match_start, &match_end);
3888 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_COMPLETE);
3890 GtkTextIter buffer_start;
3891 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3892 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3893 &match_start, &match_end);
3895 modest_platform_system_banner (NULL, NULL, _HL_IB_FIND_NO_MATCHES);
3898 /* Mark as selected the string found in search */
3900 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3901 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3902 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3904 g_free (priv->last_search);
3905 priv->last_search = NULL;
3910 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3912 ModestMsgEditWindowPrivate *priv;
3914 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3919 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3922 ModestMsgEditWindowPrivate *priv;
3924 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3929 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
3930 ModestMsgEditWindow *window)
3932 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
3936 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3939 ModestMsgEditWindowPrivate *priv;
3940 TnyHeader *header = NULL;
3942 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3943 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3945 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3947 if (priv->draft_msg != NULL) {
3948 g_object_unref (priv->draft_msg);
3951 if (draft != NULL) {
3952 g_object_ref (draft);
3953 header = tny_msg_get_header (draft);
3954 if (priv->msg_uid) {
3955 g_free (priv->msg_uid);
3956 priv->msg_uid = NULL;
3958 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3961 priv->draft_msg = draft;
3965 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3966 GtkTextIter *start, GtkTextIter *end,
3969 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3970 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3973 if (tag == NULL) return;
3974 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3975 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3976 replace_with_images (window, priv->images);
3981 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3984 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3986 g_return_if_fail (TNY_IS_MIME_PART (part));
3987 tny_list_prepend (priv->attachments, (GObject *) part);
3988 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3989 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3990 gtk_widget_show_all (priv->attachments_caption);
3991 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3995 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3997 ModestMsgEditWindowPrivate *priv;
3999 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
4000 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4002 return priv->msg_uid;
4006 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
4007 ModestMsgEditWindowWidgetType widget_type)
4009 ModestMsgEditWindowPrivate *priv;
4011 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
4012 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
4014 switch (widget_type) {
4015 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
4016 return priv->msg_body;
4018 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
4019 return priv->to_field;
4021 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
4022 return priv->cc_field;
4024 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4025 return priv->bcc_field;
4027 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4028 return priv->subject_field;
4030 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4031 return priv->attachments_view;
4039 remove_tags (WPTextBuffer *buffer)
4041 GtkTextIter start, end;
4043 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4044 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4046 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4050 on_account_removed (TnyAccountStore *account_store,
4051 TnyAccount *account,
4054 /* Do nothing if it's a store account, because we use the
4055 transport to send the messages */
4056 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4057 const gchar *parent_acc = NULL;
4058 const gchar *our_acc = NULL;
4060 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4061 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4062 /* Close this window if I'm showing a message of the removed account */
4063 if (strcmp (parent_acc, our_acc) == 0)
4064 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4069 update_signature (ModestMsgEditWindow *self,
4070 const gchar *old_account,
4071 const gchar *new_account)
4073 ModestMsgEditWindowPrivate *priv;
4074 gboolean has_old_signature, has_new_signature;
4076 ModestAccountMgr *mgr;
4079 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4081 gtk_text_buffer_begin_user_action (priv->text_buffer);
4083 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4084 mgr = modest_runtime_get_account_mgr ();
4088 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4089 if (has_old_signature) {
4090 GtkTextIter match_start, match_end;
4092 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4093 seems that the search has some problems
4094 with the blank space at the end */
4095 if (gtk_text_iter_forward_search (&iter, "--",
4096 GTK_TEXT_SEARCH_TEXT_ONLY,
4097 &match_start, NULL, NULL)) {
4098 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4099 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4101 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4102 &match_start, &match_end, NULL)) {
4106 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4111 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4112 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4113 if (has_new_signature) {
4115 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4116 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4118 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4119 g_free (full_signature);
4122 gtk_text_buffer_end_user_action (priv->text_buffer);
4125 static void update_branding (ModestMsgEditWindow *self,
4126 const gchar *new_account)
4128 ModestMsgEditWindowPrivate *priv;
4129 ModestAccountMgr *mgr;
4130 const GdkPixbuf *new_icon = NULL;
4131 gchar *new_label = NULL;
4132 gboolean show = FALSE;
4134 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4136 mgr = modest_runtime_get_account_mgr ();
4138 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4140 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4141 gtk_widget_show (priv->brand_icon);
4144 gtk_widget_hide (priv->brand_icon);
4147 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4148 gtk_widget_show (priv->brand_label);
4152 gtk_widget_hide (priv->brand_label);
4156 gtk_widget_show (priv->brand_container);
4158 gtk_widget_hide (priv->brand_container);
4162 from_field_changed (GtkWidget *button,
4163 ModestMsgEditWindow *self)
4165 ModestMsgEditWindowPrivate *priv;
4166 gchar *old_account, *new_account;
4168 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4170 old_account = priv->last_from_account;
4171 new_account = modest_selector_get_active_id (priv->from_field);
4174 g_warning ("%s, could not get the new account", __FUNCTION__);
4178 /* If the From is the same do nothing */
4179 if (old_account && new_account && !strcmp (old_account, new_account))
4182 priv->last_from_account = new_account;
4184 update_signature (self, old_account, new_account);
4185 update_branding (self, new_account);
4189 typedef struct _MessageSettingsHelper {
4190 ModestMsgEditWindow *window;
4191 GSList *priority_group;
4192 GSList *format_group;
4193 GtkToggleButton *current_priority;
4194 GtkToggleButton *current_format;
4195 } MessageSettingsHelper;
4197 #ifdef MODEST_TOOLKIT_HILDON2
4199 on_priority_toggle (GtkToggleButton *button,
4200 MessageSettingsHelper *helper)
4203 ModestMsgEditWindowPrivate *priv;
4205 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4206 if (gtk_toggle_button_get_active (button)) {
4208 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4209 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4210 if ((node_button != button) &&
4211 gtk_toggle_button_get_active (node_button)) {
4212 gtk_toggle_button_set_active (node_button, FALSE);
4215 helper->current_priority = button;
4217 gboolean found = FALSE;
4218 /* If no one is active, activate it again */
4219 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4220 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4221 if (gtk_toggle_button_get_active (node_button)) {
4227 gtk_toggle_button_set_active (button, TRUE);
4233 on_format_toggle (GtkToggleButton *button,
4234 MessageSettingsHelper *helper)
4237 ModestMsgEditWindowPrivate *priv;
4239 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4240 if (gtk_toggle_button_get_active (button)) {
4242 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4243 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4244 if ((node_button != button) &&
4245 gtk_toggle_button_get_active (node_button)) {
4246 gtk_toggle_button_set_active (node_button, FALSE);
4249 helper->current_format = button;
4251 gboolean found = FALSE;
4252 /* If no one is active, activate it again */
4253 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4254 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4255 if (gtk_toggle_button_get_active (node_button)) {
4261 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_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);
4418 #ifdef MODEST_TOOLKIT_HILDON2
4420 on_cc_button_toggled (GtkWidget *button,
4421 ModestMsgEditWindow *window)
4423 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4425 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4426 modest_togglable_get_active (button));
4430 on_bcc_button_toggled (GtkWidget *button,
4431 ModestMsgEditWindow *window)
4433 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4435 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4436 modest_togglable_get_active (button));
4441 setup_menu (ModestMsgEditWindow *self)
4443 ModestMsgEditWindowPrivate *priv = NULL;
4445 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4447 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4449 /* Settings menu buttons */
4450 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4451 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4453 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4454 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4455 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4456 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4457 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4458 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4460 #ifdef MODEST_TOOLKIT_HILDON2
4461 priv->cc_button = hildon_check_button_new (0);
4462 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4463 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4465 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4466 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4467 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4469 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4470 _("mcen_me_editor_showbcc"));
4471 modest_togglable_set_active (priv->bcc_button,
4473 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4475 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4476 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4479 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4480 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4481 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4482 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4483 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4485 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4486 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4487 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4488 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4489 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4491 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4492 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4497 emit_open_addressbook (GtkButton *button,
4498 ModestRecptEditor *editor)
4500 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4504 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4505 const gchar *label, GtkWidget *control)
4507 GtkWidget *abook_button;
4510 GtkWidget *label_widget;
4512 box = gtk_hbox_new (FALSE, 0);
4514 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4515 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4517 #ifdef MODEST_TOOLKIT_HILDON2
4518 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4520 abook_button = gtk_button_new ();
4522 label_widget = gtk_label_new (label);
4523 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4524 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4526 gtk_container_add (GTK_CONTAINER (align), abook_button);
4527 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4528 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4529 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4530 if (title_size_group)
4531 gtk_size_group_add_widget (title_size_group, label_widget);
4532 if (value_size_group)
4533 gtk_size_group_add_widget (value_size_group, control);
4535 g_signal_connect (G_OBJECT (abook_button), "clicked",
4536 G_CALLBACK (emit_open_addressbook), control);
4542 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4544 ModestMsgEditWindowPrivate *priv = NULL;
4546 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4548 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4549 priv->max_chars_banner = NULL;
4553 has_pending_addresses (ModestRecptEditor *recpt_editor)
4555 const gchar *recipients = NULL;
4556 GSList *start_indexes = NULL, *end_indexes = NULL;
4557 GSList *current_start, *current_end;
4558 GtkTextBuffer *buffer;
4559 gint offset_delta = 0;
4561 gboolean has_recipients_to_add = FALSE;
4563 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4564 last_length = g_utf8_strlen (recipients, -1);
4565 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4570 current_start = start_indexes;
4571 current_end = end_indexes;
4572 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4574 while (current_start && !has_recipients_to_add) {
4576 gchar *start_ptr, *end_ptr;
4577 gint start_pos, end_pos;
4579 start_pos = (*((gint*) current_start->data)) + offset_delta;
4580 end_pos = (*((gint*) current_end->data)) + offset_delta;
4582 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4583 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4585 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4587 if (modest_text_utils_validate_recipient (address, NULL)) {
4588 if (!modest_address_book_has_address (address)) {
4589 has_recipients_to_add = TRUE;
4592 current_start = g_slist_next (current_start);
4593 current_end = g_slist_next (current_end);
4595 return has_recipients_to_add;
4599 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4601 ModestMsgEditWindowPrivate *priv = NULL;
4603 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4605 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4607 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4608 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4609 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))