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-color-button.h"
75 #include <modest-toolkit-utils.h>
77 #ifdef MODEST_USE_CALENDAR_WIDGETS
78 #include <calendar-ui-widgets.h>
80 #ifdef MODEST_TOOLKIT_HILDON2
81 #include <hildon/hildon.h>
82 #include "modest-maemo-utils.h"
83 #include "modest-hildon-includes.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 (MODEST_TYPE_HILDON2_WINDOW,
363 "ModestMsgEditWindow",
371 save_state (ModestWindow *self)
373 modest_widget_memory_save (modest_runtime_get_conf(),
374 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
379 restore_settings (ModestMsgEditWindow *self)
381 ModestConf *conf = NULL;
383 conf = modest_runtime_get_conf ();
385 /* Dim at start clipboard actions */
386 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
391 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
393 GObjectClass *gobject_class;
394 ModestWindowClass *modest_window_class;
395 gobject_class = (GObjectClass*) klass;
396 modest_window_class = (ModestWindowClass*) klass;
398 parent_class = g_type_class_peek_parent (klass);
399 gobject_class->finalize = modest_msg_edit_window_finalize;
401 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
402 modest_window_class->save_state_func = save_state;
403 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
405 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
409 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
411 ModestMsgEditWindowPrivate *priv;
412 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
414 priv->msg_body = NULL;
415 priv->from_field = NULL;
416 priv->to_field = NULL;
417 priv->cc_field = NULL;
418 priv->bcc_field = NULL;
419 priv->subject_field = NULL;
420 priv->attachments = TNY_LIST (tny_simple_list_new ());
421 priv->images = TNY_LIST (tny_simple_list_new ());
422 priv->images_size = 0;
423 priv->images_count = 0;
426 priv->cc_caption = NULL;
427 priv->bcc_caption = NULL;
428 priv->update_caption_visibility = FALSE;
430 priv->priority_flags = 0;
432 priv->isearch_toolbar = NULL;
433 priv->last_search = NULL;
435 priv->draft_msg = NULL;
436 priv->outbox_msg = NULL;
437 priv->msg_uid = NULL;
439 priv->can_undo = FALSE;
440 priv->can_redo = FALSE;
441 priv->clipboard_change_handler_id = 0;
442 priv->default_clipboard_change_handler_id = 0;
443 priv->account_removed_handler_id = 0;
444 priv->clipboard_owner_idle = 0;
445 priv->clipboard_text = NULL;
448 priv->scroll_drag_timeout_id = 0;
449 priv->correct_scroll_idle = 0;
450 priv->last_upper = 0.0;
452 priv->font_dialog = NULL;
453 priv->app_menu = NULL;
455 priv->references = NULL;
456 priv->in_reply_to = NULL;
457 priv->max_chars_banner = NULL;
459 if (!is_wp_text_buffer_started) {
460 is_wp_text_buffer_started = TRUE;
461 wp_text_buffer_library_init ();
466 hildon_program_add_window (hildon_program_get_instance(),
471 multimailbox_get_default_mailbox (const gchar *account_name)
473 gchar *transport_account;
474 gchar *result = NULL;
476 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
478 TNY_ACCOUNT_TYPE_TRANSPORT);
479 if (transport_account) {
481 ModestProtocolRegistry *registry;
483 registry = modest_runtime_get_protocol_registry ();
485 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
486 MODEST_ACCOUNT_PROTO, TRUE);
488 ModestProtocol *protocol =
489 modest_protocol_registry_get_protocol_by_name (registry,
490 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
492 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
493 ModestPairList *pair_list;
495 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
498 ModestPair *pair = (ModestPair *) pair_list->data;
499 result = g_strdup ((const gchar *) pair->first);
500 modest_pair_list_free (pair_list);
511 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
513 static ModestPairList*
514 get_transports (void)
516 GSList *transports = NULL;
518 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
519 GSList *accounts = modest_account_mgr_account_names (account_mgr,
520 TRUE /* only enabled accounts. */);
522 GSList *cursor = accounts;
524 gchar *account_name = cursor->data;
527 gchar *transport_account;
528 gboolean multi_mailbox = FALSE;
529 ModestProtocol *protocol = NULL;
531 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
533 transport_account = modest_account_mgr_get_server_account_name
534 (modest_runtime_get_account_mgr (),
536 TNY_ACCOUNT_TYPE_TRANSPORT);
537 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
538 ModestPairList *pair_list;
539 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
542 transports = g_slist_concat (transports, pair_list);
543 multi_mailbox = TRUE;
548 if (!multi_mailbox) {
549 gchar *from_string = NULL;
551 from_string = modest_account_mgr_get_from_string (account_mgr,
553 if (from_string && account_name) {
554 gchar *name = account_name;
555 ModestPair *pair = modest_pair_new ((gpointer) name,
556 (gpointer) from_string , TRUE);
557 transports = g_slist_prepend (transports, pair);
562 cursor = cursor->next;
564 g_slist_free (accounts); /* only free the accounts, not the elements,
565 * because they are used in the pairlist */
569 static void window_focus (GtkWindow *window,
573 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
577 scroll_drag_timeout (gpointer userdata)
579 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
580 ModestMsgEditWindowPrivate *priv;
582 /* It could happen that the window was already closed */
583 if (!GTK_WIDGET_VISIBLE (win))
586 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
588 correct_scroll_without_drag_check (win, TRUE);
590 priv->scroll_drag_timeout_id = 0;
596 correct_scroll_without_drag_check_idle (gpointer userdata)
598 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
599 ModestMsgEditWindowPrivate *priv;
601 GdkRectangle rectangle;
602 gint offset_min, offset_max;
606 /* It could happen that the window was already closed */
607 if (!GTK_WIDGET_VISIBLE (w))
610 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
612 insert = gtk_text_buffer_get_insert (priv->text_buffer);
613 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
615 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
616 offset_min = priv->msg_body->allocation.y + rectangle.y;
617 offset_max = offset_min + rectangle.height;
619 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
620 offset_min = MAX (offset_min - 48, 0);
621 offset_max = MIN (offset_max + 48, vadj->upper);
623 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
625 priv->correct_scroll_idle = 0;
630 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
632 ModestMsgEditWindowPrivate *priv;
634 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
636 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
639 if (priv->correct_scroll_idle > 0) {
643 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
644 (GSourceFunc) correct_scroll_without_drag_check_idle,
650 correct_scroll (ModestMsgEditWindow *w)
652 ModestMsgEditWindowPrivate *priv;
654 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
655 if (gtk_grab_get_current () == priv->msg_body) {
656 if (priv->scroll_drag_timeout_id == 0) {
657 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
659 (GSourceFunc) scroll_drag_timeout,
666 correct_scroll_without_drag_check (w, TRUE);
670 text_buffer_end_user_action (GtkTextBuffer *buffer,
671 ModestMsgEditWindow *userdata)
674 correct_scroll (userdata);
678 text_buffer_mark_set (GtkTextBuffer *buffer,
681 ModestMsgEditWindow *userdata)
683 gtk_text_buffer_begin_user_action (buffer);
684 gtk_text_buffer_end_user_action (buffer);
688 cut_clipboard_check (GtkTextView *text_view,
691 GtkTextBuffer *buffer;
693 buffer = gtk_text_view_get_buffer (text_view);
694 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
695 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
700 copy_clipboard_check (GtkTextView *text_view,
703 GtkTextBuffer *buffer;
705 buffer = gtk_text_view_get_buffer (text_view);
706 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
707 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
712 attachment_deleted (ModestAttachmentsView *attachments_view,
715 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
720 body_size_request (GtkWidget *body,
724 /* Make sure the body always get at least 70 pixels */
725 if (req->height < 70)
730 connect_signals (ModestMsgEditWindow *obj)
732 ModestMsgEditWindowPrivate *priv;
734 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
736 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
737 G_CALLBACK (text_buffer_refresh_attributes), obj);
738 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
739 G_CALLBACK (text_buffer_can_undo), obj);
740 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
741 G_CALLBACK (text_buffer_can_redo), obj);
742 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
743 G_CALLBACK (body_changed), obj);
744 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
745 G_CALLBACK (body_insert_text), obj);
746 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
747 G_CALLBACK (body_changed), obj);
748 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
749 G_CALLBACK (text_buffer_end_user_action), obj);
750 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
751 G_CALLBACK (text_buffer_mark_set), obj);
752 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
753 G_CALLBACK (text_buffer_apply_tag), obj);
754 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
755 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
756 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
757 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
758 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
759 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
761 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
762 G_CALLBACK (modest_ui_actions_on_send), obj);
764 if (GTK_IS_COMBO_BOX (priv->from_field)) {
765 g_signal_connect (G_OBJECT (priv->from_field), "changed",
766 G_CALLBACK (from_field_changed), obj);
768 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
769 G_CALLBACK (from_field_changed), obj);
772 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
773 G_CALLBACK (msg_body_focus), obj);
774 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
775 G_CALLBACK (msg_body_focus), obj);
776 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
777 G_CALLBACK (body_size_request), obj);
778 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
779 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
780 "changed", G_CALLBACK (recpt_field_changed), obj);
781 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
782 "changed", G_CALLBACK (recpt_field_changed), obj);
783 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
784 "changed", G_CALLBACK (recpt_field_changed), obj);
785 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
786 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
787 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
789 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
790 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
791 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
792 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_close), obj);
794 priv->clipboard_change_handler_id =
795 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
796 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
797 priv->default_clipboard_change_handler_id =
798 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
799 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
801 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
802 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
803 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
807 init_wp_text_view_style ()
809 static gboolean initialized = FALSE;
812 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
818 init_window (ModestMsgEditWindow *obj)
820 GtkWidget *to_caption, *subject_caption;
821 GtkWidget *main_vbox;
822 ModestMsgEditWindowPrivate *priv;
823 GtkActionGroup *action_group;
824 ModestWindowPrivate *parent_priv;
825 GdkPixbuf *window_icon = NULL;
826 GError *error = NULL;
828 GtkSizeGroup *title_size_group;
829 GtkSizeGroup *value_size_group;
830 GtkWidget *window_box;
831 GtkWidget *window_align;
832 #if (GTK_MINOR_VERSION >= 10)
833 GdkAtom deserialize_type;
835 GtkWidget *from_send_hbox;
836 GtkWidget *send_icon;
837 GtkWidget *attachments_label;
838 GtkWidget *branding_box;
839 GtkWidget *from_caption;
841 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
842 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
844 parent_priv->ui_manager = gtk_ui_manager_new();
845 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
846 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
848 /* Add common actions */
849 gtk_action_group_add_actions (action_group,
850 modest_msg_edit_action_entries,
851 G_N_ELEMENTS (modest_msg_edit_action_entries),
853 gtk_action_group_add_actions (action_group,
854 hildon2_msg_edit_action_entries,
855 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
857 gtk_action_group_add_toggle_actions (action_group,
858 modest_msg_edit_toggle_action_entries,
859 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
861 gtk_action_group_add_radio_actions (action_group,
862 modest_msg_edit_alignment_radio_action_entries,
863 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
865 G_CALLBACK (modest_ui_actions_on_change_justify),
867 gtk_action_group_add_radio_actions (action_group,
868 modest_msg_edit_priority_action_entries,
869 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
871 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
873 gtk_action_group_add_radio_actions (action_group,
874 modest_msg_edit_file_format_action_entries,
875 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
876 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
877 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
879 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
880 g_object_unref (action_group);
882 /* Load the UI definition */
883 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
886 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
887 g_clear_error (&error);
890 /* Add accelerators */
891 gtk_window_add_accel_group (GTK_WINDOW (obj),
892 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
894 parent_priv->menubar = NULL;
896 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
897 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
899 /* Note: This ModestPairList* must exist for as long as the picker
900 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
901 * so it can't know how to manage its memory. */
902 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
904 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
905 if (GTK_IS_COMBO_BOX (priv->from_field)) {
906 from_caption = modest_toolkit_utils_create_captioned (title_size_group, NULL,
907 _("mail_va_from"), FALSE,
909 gtk_widget_show (from_caption);
911 modest_toolkit_utils_set_hbutton_layout (title_size_group, NULL,
912 _("mail_va_from"), priv->from_field);
913 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
914 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
915 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
916 from_caption = priv->from_field;
919 priv->to_field = modest_recpt_editor_new ();
920 priv->cc_field = modest_recpt_editor_new ();
921 priv->bcc_field = modest_recpt_editor_new ();
922 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
923 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
924 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
925 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
926 priv->priority_icon = gtk_image_new ();
927 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
928 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
929 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
930 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
931 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
932 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
933 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
934 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
935 priv->attachments_view = modest_attachments_view_new (NULL);
936 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
937 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
939 priv->header_box = gtk_vbox_new (FALSE, 0);
941 to_caption = _create_addressbook_box
942 (title_size_group, value_size_group,
943 _("mail_va_to"), priv->to_field);
944 priv->cc_caption = _create_addressbook_box
945 (title_size_group, value_size_group,
946 _("mail_va_cc"), priv->cc_field);
947 priv->bcc_caption = _create_addressbook_box
948 (title_size_group, value_size_group,
949 _("mail_va_hotfix1"), priv->bcc_field);
950 subject_caption = modest_toolkit_utils_create_captioned (title_size_group, value_size_group,
951 _("mail_va_subject"), FALSE, priv->subject_box);
952 priv->attachments_caption = modest_toolkit_utils_create_captioned_with_size_type (NULL, NULL,
953 _("mail_va_attachment"),
955 priv->attachments_view,
956 HILDON_SIZE_AUTO_WIDTH |
957 HILDON_SIZE_AUTO_HEIGHT);
958 attachments_label = modest_toolkit_utils_captioned_get_label_widget (priv->attachments_caption);
959 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
962 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
963 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
964 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
965 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
967 g_object_unref (title_size_group);
968 g_object_unref (value_size_group);
970 priv->brand_icon = gtk_image_new ();
971 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
972 priv->brand_label = gtk_label_new (NULL);
973 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
974 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
975 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
976 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
978 from_send_hbox = gtk_hbox_new (FALSE, 0);
979 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
980 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
982 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
983 gtk_widget_show (branding_box);
984 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
985 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
987 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
988 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
989 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
990 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
993 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
994 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
995 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
996 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
997 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
998 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
999 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
1000 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1002 init_wp_text_view_style ();
1004 priv->msg_body = modest_wp_text_view_new ();
1007 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1008 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1009 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1010 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1011 #if (GTK_MINOR_VERSION >= 10)
1012 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1013 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1015 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1016 deserialize_type, TRUE);
1018 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1020 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1022 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1024 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1026 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1028 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1030 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1031 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1032 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1034 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1035 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1036 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1038 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1039 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1041 window_box = gtk_vbox_new (FALSE, 0);
1042 gtk_container_add (GTK_CONTAINER(obj), window_box);
1044 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1046 /* Set window icon */
1047 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1049 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1050 g_object_unref (window_icon);
1055 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1057 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1059 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1060 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1061 priv->clipboard_change_handler_id))
1062 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1063 priv->clipboard_change_handler_id);
1064 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1065 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1066 priv->default_clipboard_change_handler_id))
1067 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1068 priv->default_clipboard_change_handler_id);
1070 if (priv->account_removed_handler_id &&
1071 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1072 priv->account_removed_handler_id))
1073 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1074 priv->account_removed_handler_id);
1078 modest_msg_edit_window_finalize (GObject *obj)
1080 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1082 if (priv->max_chars_banner) {
1083 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1084 priv->max_chars_banner = FALSE;
1087 /* Sanity check: shouldn't be needed, the window mgr should
1088 call this function before */
1089 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1091 if (priv->font_dialog != NULL) {
1092 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1095 if (priv->clipboard_text != NULL) {
1096 g_free (priv->clipboard_text);
1097 priv->clipboard_text = NULL;
1100 if (priv->draft_msg != NULL) {
1101 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1102 if (TNY_IS_HEADER (header)) {
1103 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1104 modest_window_mgr_unregister_header (mgr, header);
1106 g_object_unref (priv->draft_msg);
1107 priv->draft_msg = NULL;
1109 if (priv->outbox_msg != NULL) {
1110 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1111 if (TNY_IS_HEADER (header)) {
1112 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1113 modest_window_mgr_unregister_header (mgr, header);
1115 g_object_unref (priv->outbox_msg);
1116 priv->outbox_msg = NULL;
1118 if (priv->correct_scroll_idle > 0) {
1119 g_source_remove (priv->correct_scroll_idle);
1120 priv->correct_scroll_idle = 0;
1122 if (priv->scroll_drag_timeout_id > 0) {
1123 g_source_remove (priv->scroll_drag_timeout_id);
1124 priv->scroll_drag_timeout_id = 0;
1126 if (priv->clipboard_owner_idle > 0) {
1127 g_source_remove (priv->clipboard_owner_idle);
1128 priv->clipboard_owner_idle = 0;
1130 if (priv->original_account_name)
1131 g_free (priv->original_account_name);
1132 if (priv->original_mailbox)
1133 g_free (priv->original_mailbox);
1134 g_free (priv->msg_uid);
1135 g_free (priv->last_search);
1136 g_free (priv->references);
1137 g_free (priv->in_reply_to);
1138 g_object_unref (priv->attachments);
1139 g_object_unref (priv->images);
1141 /* This had to stay alive for as long as the picker that used it: */
1142 modest_pair_list_free (priv->from_field_protos);
1144 G_OBJECT_CLASS(parent_class)->finalize (obj);
1148 pixbuf_size_prepared (GdkPixbufLoader *loader,
1151 ModestMsgEditWindow *self)
1153 gint new_height, new_width;
1156 new_height = height;
1160 if (width > IMAGE_MAX_WIDTH) {
1161 new_height = height * IMAGE_MAX_WIDTH / width;
1162 new_width = IMAGE_MAX_WIDTH;
1165 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1169 pixbuf_from_stream (TnyStream *stream,
1170 const gchar *mime_type,
1171 guint64 *stream_size,
1172 ModestMsgEditWindow *self)
1174 GdkPixbufLoader *loader;
1177 GError *error = NULL;
1181 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1183 if (loader == NULL) {
1188 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1190 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1192 tny_stream_reset (TNY_STREAM (stream));
1193 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1194 unsigned char read_buffer[128];
1196 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1198 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1201 /* Allow some UI responsiveness */
1202 while (gtk_events_pending ())
1203 gtk_main_iteration ();
1205 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1207 gdk_pixbuf_loader_close (loader, &error);
1210 g_error_free (error);
1211 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1213 g_object_ref (pixbuf);
1214 g_object_unref (loader);
1219 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1220 GdkPixbuf *new_pixbuf;
1222 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1223 gdk_pixbuf_get_width (pixbuf);
1224 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1225 g_object_unref (pixbuf);
1226 pixbuf = new_pixbuf;
1230 *stream_size = size;
1236 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1238 ModestMsgEditWindowPrivate *priv;
1241 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1243 g_object_ref (self);
1244 for (iter = tny_list_create_iterator (attachments);
1245 !tny_iterator_is_done (iter);
1246 tny_iterator_next (iter)) {
1247 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1248 const gchar *cid = tny_mime_part_get_content_id (part);
1249 const gchar *mime_type = tny_mime_part_get_content_type (part);
1250 if ((cid != NULL)&&(mime_type != NULL)) {
1251 guint64 stream_size;
1252 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1253 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1256 g_object_unref (stream);
1258 if (pixbuf != NULL) {
1259 priv->images_count ++;
1260 priv->images_size += stream_size;
1261 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1262 g_object_unref (pixbuf);
1265 g_object_unref (part);
1267 g_object_unref (iter);
1268 g_object_unref (self);
1272 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1274 TnyMimePart *parent = NULL;
1275 const gchar *content_type = NULL;
1276 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1278 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1280 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1281 parent = g_object_ref (msg);
1282 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1283 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1286 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1287 iter = tny_list_create_iterator (parts);
1288 while (!tny_iterator_is_done (iter)) {
1290 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1291 content_type = tny_mime_part_get_content_type (part);
1292 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1296 g_object_unref (part);
1298 tny_iterator_next (iter);
1300 g_object_unref (iter);
1301 g_object_unref (parts);
1304 if (parent != NULL) {
1305 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1308 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1309 iter = tny_list_create_iterator (parts);
1310 while (!tny_iterator_is_done (iter)) {
1312 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1313 content_type = tny_mime_part_get_content_type (part);
1314 if (content_type && g_str_has_prefix (content_type, "image/")) {
1315 tny_list_prepend (priv->images, (GObject *) part);
1317 g_object_unref (part);
1318 tny_iterator_next (iter);
1320 g_object_unref (iter);
1321 g_object_unref (parts);
1322 g_object_unref (parent);
1327 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1330 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1332 for (iter = tny_list_create_iterator (attachments) ;
1333 !tny_iterator_is_done (iter);
1334 tny_iterator_next (iter)) {
1335 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1336 const gchar *cid = tny_mime_part_get_content_id (part);
1338 char *invalid = NULL;
1339 gint int_cid = strtol (cid, &invalid, 10);
1340 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1341 priv->next_cid = int_cid + 1;
1344 g_object_unref (part);
1346 g_object_unref (iter);
1350 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1353 gchar *to, *cc, *bcc, *subject;
1355 ModestMsgEditWindowPrivate *priv;
1356 ModestWindowPrivate *parent_priv;
1358 TnyHeaderFlags priority_flags;
1359 TnyFolder *msg_folder;
1360 gboolean is_html = FALSE;
1361 gboolean field_view_set;
1363 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1364 g_return_if_fail (TNY_IS_MSG (msg));
1366 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1367 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1369 header = tny_msg_get_header (msg);
1370 to = tny_header_dup_to (header);
1371 cc = tny_header_dup_cc (header);
1372 bcc = tny_header_dup_bcc (header);
1373 subject = tny_header_dup_subject (header);
1375 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1376 priority_flags = tny_header_get_priority (header);
1379 gchar *quoted_names = modest_text_utils_quote_names (to);
1380 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1381 g_free (quoted_names);
1384 field_view_set = TRUE;
1386 gchar *quoted_names = modest_text_utils_quote_names (cc);
1387 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1388 g_free (quoted_names);
1389 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1390 gtk_widget_show (priv->cc_caption);
1391 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1392 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1393 gtk_widget_hide (priv->cc_caption);
1394 field_view_set = FALSE;
1396 modest_togglable_set_active (priv->cc_button, field_view_set);
1398 field_view_set = TRUE;
1400 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1401 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1402 g_free (quoted_names);
1403 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1404 gtk_widget_show (priv->bcc_caption);
1405 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1406 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1407 gtk_widget_hide (priv->bcc_caption);
1408 field_view_set = FALSE;
1410 modest_togglable_set_active (priv->bcc_button, field_view_set);
1414 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1415 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1418 update_window_title (self);
1420 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1421 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1423 if ((body == NULL)||(body[0] == '\0')) {
1425 body = modest_text_utils_convert_to_html ("");
1428 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1429 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1432 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1435 /* Add attachments to the view */
1436 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1437 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1438 if (tny_list_get_length (priv->attachments) == 0) {
1439 gtk_widget_hide (priv->attachments_caption);
1441 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1442 gtk_widget_show_all (priv->attachments_caption);
1444 get_related_images (self, msg);
1445 update_next_cid (self, priv->attachments);
1446 update_next_cid (self, priv->images);
1447 replace_with_images (self, priv->images);
1449 if (preserve_is_rich && !is_html) {
1450 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1451 /* Get the default format required from configuration */
1452 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1453 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1456 /* Set the default focus depending on having already a To: field or not */
1457 if ((!to)||(*to == '\0')) {
1458 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1460 gtk_widget_grab_focus (priv->msg_body);
1463 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1465 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1466 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1468 modest_msg_edit_window_set_modified (self, FALSE);
1470 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1471 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1472 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1473 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1475 if (priv->msg_uid) {
1476 g_free (priv->msg_uid);
1477 priv->msg_uid = NULL;
1480 /* we should set a reference to the incoming message if it is a draft */
1481 msg_folder = tny_msg_get_folder (msg);
1483 if (modest_tny_folder_is_local_folder (msg_folder)) {
1484 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1485 if (type == TNY_FOLDER_TYPE_INVALID)
1486 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1488 if (type == TNY_FOLDER_TYPE_DRAFTS)
1489 priv->draft_msg = g_object_ref(msg);
1490 if (type == TNY_FOLDER_TYPE_OUTBOX)
1491 priv->outbox_msg = g_object_ref(msg);
1492 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1494 g_object_unref (msg_folder);
1504 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1506 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1507 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1508 GtkWidget *placeholder;
1509 GtkWidget *tool_item;
1514 GtkWidget *sizes_menu;
1515 GtkWidget *fonts_menu;
1521 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1522 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1523 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1524 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1526 /* Font color placeholder */
1527 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1528 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1531 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1532 priv->font_color_button = modest_color_button_new ();
1533 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1534 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1535 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1536 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1537 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1538 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1539 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1540 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1542 G_CALLBACK (modest_msg_edit_window_color_button_change),
1545 /* Font size and face placeholder */
1546 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1547 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1549 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1550 priv->size_tool_button_label = gtk_label_new (NULL);
1551 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1552 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1553 size_text, "</span>", NULL);
1554 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1555 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1557 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1558 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1559 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1560 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1561 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1562 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1563 gtk_widget_set_sensitive (arrow, FALSE);
1564 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1565 sizes_menu = gtk_menu_new ();
1566 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1567 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1570 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1571 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1573 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1577 if (wp_font_size[size_index] == 12)
1578 priv->current_size_index = size_index;
1582 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1583 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1584 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1585 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1586 priv->font_size_toolitem = tool_item;
1589 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1590 priv->font_tool_button_label = gtk_label_new (NULL);
1591 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1592 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1593 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1595 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1596 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1597 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1598 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1599 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1600 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1601 gtk_widget_set_sensitive (arrow, FALSE);
1602 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1603 fonts_menu = gtk_menu_new ();
1604 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1605 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1608 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1610 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1611 0, wp_get_font_name (font_index),
1614 if (font_index == DEFAULT_FONT)
1615 priv->current_face_index = font_index;
1617 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1618 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1619 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1620 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1621 priv->font_face_toolitem = tool_item;
1623 /* Set expand and homogeneous for remaining items */
1624 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1625 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1626 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1627 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1628 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1629 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1631 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1632 will not show the tool items added to the placeholders) */
1633 gtk_widget_show_all (parent_priv->toolbar);
1635 /* Set the no show all *after* showing all items. We do not
1636 want the toolbar to be shown with a show all because it
1637 could go agains the gconf setting regarding showing or not
1638 the toolbar of the editor window */
1639 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1645 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1648 ModestWindowPrivate *parent_priv;
1649 ModestMsgEditWindowPrivate *priv;
1650 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1651 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1652 ModestWindowMgr *mgr = NULL;
1654 g_return_val_if_fail (msg, NULL);
1655 g_return_val_if_fail (account_name, NULL);
1657 mgr = modest_runtime_get_window_mgr ();
1659 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1661 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1662 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1664 /* Menubar. Update the state of some toggles */
1665 priv->from_field_protos = get_transports ();
1666 priv->original_mailbox = NULL;
1667 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1668 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1669 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1670 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1671 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1672 priv->original_mailbox = g_strdup (mailbox);
1673 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1674 /* We set the first mailbox as the active mailbox */
1675 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1676 if (priv->original_mailbox != NULL)
1677 modest_selector_set_active_id (priv->from_field,
1678 (gpointer) priv->original_mailbox);
1680 modest_selector_set_active_id (priv->from_field,
1681 (gpointer) account_name);
1683 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1685 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1686 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1687 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1688 #ifdef HILDON_TOOLKIT_HILDON2
1689 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1691 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1692 hildon_touch_selector_get_current_text
1693 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1696 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1697 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1700 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1702 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1704 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1705 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1707 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1709 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1710 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1711 /* Add common dimming rules */
1712 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1713 modest_msg_edit_window_toolbar_dimming_entries,
1714 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1715 MODEST_WINDOW (obj));
1716 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1717 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1718 MODEST_WINDOW (obj));
1719 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1720 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1721 MODEST_WINDOW (obj));
1722 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1723 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1724 MODEST_WINDOW (obj));
1725 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1726 G_CALLBACK (modest_ui_dimming_rules_on_send),
1727 MODEST_WINDOW (obj));
1728 /* Insert dimming rules group for this window */
1729 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1730 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1732 /* Setup app menu */
1733 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1735 /* Checks the dimming rules */
1736 g_object_unref (toolbar_rules_group);
1737 g_object_unref (clipboard_rules_group);
1738 gtk_widget_hide (priv->priority_icon);
1739 gtk_widget_queue_resize (priv->subject_box);
1740 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1742 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1744 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1745 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1746 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1747 priv->update_caption_visibility = TRUE;
1749 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1751 /* Track account-removed signal, this window should be closed
1752 in the case we're creating a mail associated to the account
1754 priv->account_removed_handler_id =
1755 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1757 G_CALLBACK(on_account_removed),
1760 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1762 return (ModestWindow*) obj;
1766 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1768 GString **string_buffer = (GString **) user_data;
1770 *string_buffer = g_string_append (*string_buffer, buffer);
1776 * @result: A new string which should be freed with g_free().
1779 get_formatted_data (ModestMsgEditWindow *edit_window)
1781 ModestMsgEditWindowPrivate *priv;
1782 GString *string_buffer = g_string_new ("");
1784 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1786 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1788 modest_text_utils_hyperlinkify (string_buffer);
1790 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1792 return g_string_free (string_buffer, FALSE);
1797 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1800 const gchar *account_name;
1801 ModestMsgEditWindowPrivate *priv;
1802 TnyIterator *att_iter;
1803 const gchar *picker_active_id;
1805 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1807 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1809 picker_active_id = modest_selector_get_active_id (priv->from_field);
1810 g_return_val_if_fail (picker_active_id, NULL);
1811 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1813 /* don't free these (except from) */
1814 data = g_slice_new0 (MsgData);
1815 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1816 data->account_name = g_strdup (account_name);
1817 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1818 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1819 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1820 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1821 data->references = g_strdup (priv->references);
1822 data->in_reply_to = g_strdup (priv->in_reply_to);
1823 if (priv->draft_msg) {
1824 data->draft_msg = g_object_ref (priv->draft_msg);
1825 } else if (priv->outbox_msg) {
1826 data->draft_msg = g_object_ref (priv->outbox_msg);
1828 data->draft_msg = NULL;
1831 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1833 gtk_text_buffer_get_bounds (buf, &b, &e);
1834 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1836 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1837 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1839 data->html_body = NULL;
1841 /* deep-copy the data */
1842 att_iter = tny_list_create_iterator (priv->attachments);
1843 data->attachments = NULL;
1844 while (!tny_iterator_is_done (att_iter)) {
1845 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1846 if (!(TNY_IS_MIME_PART(part))) {
1847 g_warning ("strange data in attachment list");
1848 g_object_unref (part);
1849 tny_iterator_next (att_iter);
1852 data->attachments = g_list_append (data->attachments,
1854 tny_iterator_next (att_iter);
1856 g_object_unref (att_iter);
1858 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1859 att_iter = tny_list_create_iterator (priv->images);
1860 data->images = NULL;
1861 while (!tny_iterator_is_done (att_iter)) {
1862 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1864 if (!(TNY_IS_MIME_PART(part))) {
1865 g_warning ("strange data in attachment list");
1866 g_object_unref (part);
1867 tny_iterator_next (att_iter);
1870 cid = tny_mime_part_get_content_id (part);
1872 gchar *image_tag_id;
1873 GtkTextTag *image_tag;
1875 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1876 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1877 g_free (image_tag_id);
1879 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1881 ((gtk_text_iter_has_tag (&iter, image_tag))||
1882 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1883 data->images = g_list_append (data->images,
1884 g_object_ref (part));
1886 g_object_unref (part);
1887 tny_iterator_next (att_iter);
1889 g_object_unref (att_iter);
1891 data->priority_flags = priv->priority_flags;
1898 unref_gobject (GObject *obj, gpointer data)
1900 if (!G_IS_OBJECT(obj))
1902 g_object_unref (obj);
1906 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1909 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1917 g_free (data->from);
1918 g_free (data->subject);
1919 g_free (data->plain_body);
1920 g_free (data->html_body);
1921 g_free (data->account_name);
1922 g_free (data->references);
1923 g_free (data->in_reply_to);
1925 if (data->draft_msg != NULL) {
1926 g_object_unref (data->draft_msg);
1927 data->draft_msg = NULL;
1930 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1931 g_list_free (data->attachments);
1932 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1933 g_list_free (data->images);
1935 g_slice_free (MsgData, data);
1939 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1941 guint64 *parts_size)
1943 ModestMsgEditWindowPrivate *priv;
1945 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1947 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1949 /* TODO: add images */
1950 *parts_size += priv->images_size;
1951 *parts_count += priv->images_count;
1956 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1959 ModestMsgEditWindowPrivate *priv = NULL;
1960 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1962 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1964 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1966 return MODEST_MSG_EDIT_FORMAT_HTML;
1968 return MODEST_MSG_EDIT_FORMAT_TEXT;
1972 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1973 ModestMsgEditFormat format)
1975 ModestMsgEditWindowPrivate *priv;
1976 ModestWindowPrivate *parent_priv;
1978 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1979 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1980 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1983 case MODEST_MSG_EDIT_FORMAT_HTML:
1984 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1985 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
1987 case MODEST_MSG_EDIT_FORMAT_TEXT:
1988 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1989 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
1992 g_return_if_reached ();
1996 ModestMsgEditFormatState *
1997 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1999 ModestMsgEditFormatState *format_state = NULL;
2000 ModestMsgEditWindowPrivate *priv;
2001 WPTextBufferFormat *buffer_format;
2003 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2005 buffer_format = g_new0 (WPTextBufferFormat, 1);
2006 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2008 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2010 format_state = g_new0 (ModestMsgEditFormatState, 1);
2011 format_state->bold = buffer_format->bold&0x1;
2012 format_state->italics = buffer_format->italic&0x1;
2013 format_state->bullet = buffer_format->bullet&0x1;
2014 format_state->color = buffer_format->color;
2015 format_state->font_size = buffer_format->font_size;
2016 format_state->font_family = wp_get_font_name (buffer_format->font);
2017 format_state->justification = buffer_format->justification;
2018 g_free (buffer_format);
2020 return format_state;
2025 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2026 const ModestMsgEditFormatState *format_state)
2028 ModestMsgEditWindowPrivate *priv;
2029 WPTextBufferFormat *buffer_format;
2030 WPTextBufferFormat *current_format;
2032 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2033 g_return_if_fail (format_state != NULL);
2035 buffer_format = g_new0 (WPTextBufferFormat, 1);
2036 current_format = g_new0 (WPTextBufferFormat, 1);
2038 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2039 gtk_widget_grab_focus (priv->msg_body);
2040 buffer_format->bold = (format_state->bold != FALSE);
2041 buffer_format->italic = (format_state->italics != FALSE);
2042 buffer_format->color = format_state->color;
2043 buffer_format->font_size = format_state->font_size;
2044 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2045 buffer_format->justification = format_state->justification;
2046 buffer_format->bullet = format_state->bullet;
2048 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2050 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2051 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2052 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2053 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2054 buffer_format->cs.font = (buffer_format->font != current_format->font);
2055 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2056 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2058 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2059 if (buffer_format->cs.bold) {
2060 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2061 GINT_TO_POINTER (buffer_format->bold&0x1));
2063 if (buffer_format->cs.italic) {
2064 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2065 GINT_TO_POINTER (buffer_format->italic&0x1));
2067 if (buffer_format->cs.color) {
2068 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2069 GINT_TO_POINTER (&(buffer_format->color)));
2071 if (buffer_format->cs.font_size) {
2072 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2073 GINT_TO_POINTER (buffer_format->font_size));
2075 if (buffer_format->cs.justification) {
2076 switch (buffer_format->justification) {
2077 case GTK_JUSTIFY_LEFT:
2078 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2079 GINT_TO_POINTER(TRUE));
2081 case GTK_JUSTIFY_CENTER:
2082 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2083 GINT_TO_POINTER(TRUE));
2085 case GTK_JUSTIFY_RIGHT:
2086 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2087 GINT_TO_POINTER(TRUE));
2094 if (buffer_format->cs.font) {
2095 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2096 GINT_TO_POINTER (buffer_format->font));
2098 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2099 if (buffer_format->cs.bullet) {
2100 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2101 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2103 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2105 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2107 g_free (buffer_format);
2108 g_free (current_format);
2110 /* Check dimming rules */
2111 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2112 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2116 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2118 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2120 ModestWindowPrivate *parent_priv;
2121 ModestMsgEditWindowPrivate *priv;
2123 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2124 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2126 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2127 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2128 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2129 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2131 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2132 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2133 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2136 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2138 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2139 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2141 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2142 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2144 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2145 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2148 switch (buffer_format->justification)
2150 case GTK_JUSTIFY_LEFT:
2151 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2153 case GTK_JUSTIFY_CENTER:
2154 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2156 case GTK_JUSTIFY_RIGHT:
2157 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2164 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2166 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2167 G_CALLBACK (modest_msg_edit_window_color_button_change),
2169 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2170 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2171 G_CALLBACK (modest_msg_edit_window_color_button_change),
2174 if (priv->current_size_index != buffer_format->font_size) {
2178 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2179 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2183 priv->current_size_index = buffer_format->font_size;
2185 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2186 markup = g_strconcat ("<span font_family='Sans'>",
2187 size_text, "</span>", NULL);
2189 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2193 gtk_tree_path_free (path);
2196 if (priv->current_face_index != buffer_format->font) {
2200 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2201 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2205 priv->current_face_index = buffer_format->font;
2206 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2207 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2208 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2215 g_free (buffer_format);
2221 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2223 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2224 ModestMsgEditWindowPrivate *priv;
2225 GtkWidget *dialog = NULL;
2227 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2228 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2230 dialog = hildon_color_chooser_new ();
2231 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2232 g_free (buffer_format);
2234 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2236 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2237 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2240 gtk_widget_destroy (dialog);
2245 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2247 ModestMsgEditWindowPrivate *priv;
2248 GtkWidget *dialog = NULL;
2249 GdkColor *old_color = NULL;
2251 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2252 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2254 dialog = hildon_color_chooser_new ();
2255 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2257 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2259 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2260 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2262 gtk_widget_destroy (dialog);
2267 create_stream_for_uri (const gchar* uri)
2272 TnyStream *result = NULL;
2274 GnomeVFSHandle *handle = NULL;
2275 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2276 if (test == GNOME_VFS_OK) {
2277 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2278 /* Streams over OBEX (Bluetooth) are not seekable but
2279 * we expect them to be (we might need to read them
2280 * several times). So if this is a Bluetooth URI just
2281 * read the whole file into memory (this is not a fast
2282 * protocol so we can assume that these files are not
2283 * going to be very big) */
2284 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2285 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2286 TnyStream *memstream = tny_camel_mem_stream_new ();
2287 tny_stream_write_to_stream (vfssstream, memstream);
2288 g_object_unref (vfssstream);
2291 result = vfssstream;
2299 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2302 ModestMsgEditWindowPrivate *priv;
2303 GtkWidget *dialog = NULL;
2305 GSList *uris = NULL;
2306 GSList *uri_node = NULL;
2308 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2310 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2311 _("mcen_ia_select_inline_image_title"),
2312 (GtkWindow *) window,
2313 GTK_FILE_CHOOSER_ACTION_OPEN);
2314 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2316 #ifdef MODEST_TOOLKIT_HILDON2
2317 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2320 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2321 GTK_WINDOW (dialog), GTK_WINDOW (window));
2323 response = gtk_dialog_run (GTK_DIALOG (dialog));
2325 case GTK_RESPONSE_OK:
2327 gchar *current_folder;
2328 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2329 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2330 if (current_folder && current_folder != '\0') {
2332 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2333 current_folder, &err);
2335 g_debug ("Error storing latest used folder: %s", err->message);
2339 g_free (current_folder);
2345 gtk_widget_destroy (dialog);
2347 g_object_ref (window);
2348 /* The operation could take some time so allow the dialog to be closed */
2349 while (gtk_events_pending ())
2350 gtk_main_iteration ();
2352 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2354 GnomeVFSHandle *handle = NULL;
2355 GnomeVFSResult result;
2356 GtkTextIter position;
2357 GtkTextMark *insert_mark;
2359 uri = (const gchar *) uri_node->data;
2360 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2361 if (result == GNOME_VFS_OK) {
2363 GnomeVFSFileInfo *info;
2364 gchar *filename, *basename, *escaped_filename;
2365 TnyMimePart *mime_part;
2367 const gchar *mime_type = NULL;
2368 GnomeVFSURI *vfs_uri;
2369 guint64 stream_size;
2371 gnome_vfs_close (handle);
2372 vfs_uri = gnome_vfs_uri_new (uri);
2374 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2375 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2376 g_free (escaped_filename);
2377 gnome_vfs_uri_unref (vfs_uri);
2378 info = gnome_vfs_file_info_new ();
2380 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2381 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2383 mime_type = gnome_vfs_file_info_get_mime_type (info);
2385 mime_part = tny_platform_factory_new_mime_part
2386 (modest_runtime_get_platform_factory ());
2388 TnyStream *stream = create_stream_for_uri (uri);
2390 if (stream == NULL) {
2392 modest_platform_information_banner (NULL, NULL,
2393 _FM("sfil_ib_opening_not_allowed"));
2395 g_object_unref (mime_part);
2396 gnome_vfs_file_info_unref (info);
2400 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2402 content_id = g_strdup_printf ("%d", priv->next_cid);
2403 tny_mime_part_set_content_id (mime_part, content_id);
2404 g_free (content_id);
2407 basename = g_path_get_basename (filename);
2408 tny_mime_part_set_filename (mime_part, basename);
2411 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2413 if (pixbuf != NULL) {
2414 priv->images_size += stream_size;
2415 priv->images_count ++;
2416 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2417 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2418 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2419 tny_mime_part_get_content_id (mime_part), pixbuf);
2420 g_object_unref (pixbuf);
2422 tny_list_prepend (priv->images, (GObject *) mime_part);
2423 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2425 modest_platform_information_banner (NULL, NULL,
2426 _("mail_ib_file_operation_failed"));
2430 g_object_unref (mime_part);
2431 gnome_vfs_file_info_unref (info);
2435 g_object_unref (window);
2439 on_attach_file_response (GtkDialog *dialog,
2443 GSList *uris = NULL;
2445 GnomeVFSFileSize total_size, allowed_size;
2446 ModestMsgEditWindow *window;
2447 ModestMsgEditWindowPrivate *priv;
2452 case GTK_RESPONSE_OK:
2454 gchar *current_folder;
2456 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2457 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2458 if (current_folder && current_folder != '\0') {
2460 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2461 current_folder, &err);
2463 g_debug ("Error storing latest used folder: %s", err->message);
2467 g_free (current_folder);
2474 window = MODEST_MSG_EDIT_WINDOW (user_data);
2475 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2477 /* allowed size is the maximum size - what's already there */
2478 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2479 &att_num, &att_size);
2480 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2483 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2485 const gchar *uri = (const gchar *) uri_node->data;
2488 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2490 if (total_size > allowed_size) {
2491 g_debug ("%s: total size: %u",
2492 __FUNCTION__, (unsigned int)total_size);
2495 allowed_size -= total_size;
2497 g_slist_foreach (uris, (GFunc) g_free, NULL);
2498 g_slist_free (uris);
2500 gtk_widget_destroy (GTK_WIDGET (dialog));
2504 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2506 GtkWidget *dialog = NULL;
2507 ModestMsgEditWindowPrivate *priv;
2510 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2512 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2514 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2517 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2518 _("mcen_ia_select_attachment_title"),
2519 (GtkWindow *) window,
2520 GTK_FILE_CHOOSER_ACTION_OPEN);
2521 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2522 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2523 if (conf_folder && conf_folder[0] != '\0') {
2524 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2527 /* Set the default folder to documents folder */
2528 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2529 #ifdef MODEST_TOOLKIT_HILDON2
2532 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2533 ".documents", NULL);
2536 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2537 g_free (docs_folder);
2539 g_free (conf_folder);
2540 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2541 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2542 GTK_WINDOW (dialog), GTK_WINDOW (window));
2544 /* Connect to response & show */
2545 g_signal_connect (dialog, "response",
2546 G_CALLBACK (on_attach_file_response), window);
2547 gtk_widget_show (dialog);
2552 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2554 GnomeVFSFileSize allowed_size)
2557 GnomeVFSHandle *handle = NULL;
2558 ModestMsgEditWindowPrivate *priv;
2559 GnomeVFSResult result;
2560 GnomeVFSFileSize size = 0;
2561 g_return_val_if_fail (window, 0);
2562 g_return_val_if_fail (uri, 0);
2564 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2566 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2567 if (result == GNOME_VFS_OK) {
2568 TnyMimePart *mime_part;
2570 const gchar *mime_type = NULL;
2572 gchar *escaped_filename;
2575 GnomeVFSFileInfo *info;
2576 GnomeVFSURI *vfs_uri;
2578 gnome_vfs_close (handle);
2579 vfs_uri = gnome_vfs_uri_new (uri);
2582 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2583 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2584 g_free (escaped_filename);
2585 gnome_vfs_uri_unref (vfs_uri);
2587 info = gnome_vfs_file_info_new ();
2589 if (gnome_vfs_get_file_info (uri,
2591 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2593 mime_type = gnome_vfs_file_info_get_mime_type (info);
2594 mime_part = tny_platform_factory_new_mime_part
2595 (modest_runtime_get_platform_factory ());
2597 /* try to get the attachment's size; this may fail for weird
2598 * file systems, like obex, upnp... */
2599 if (allowed_size != 0 &&
2600 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2602 if (size > allowed_size) {
2603 modest_platform_information_banner (NULL, NULL,
2604 _("mail_ib_error_attachment_size"));
2609 g_debug ("%s: could not get attachment size", __FUNCTION__);
2611 stream = create_stream_for_uri (uri);
2613 if (stream == NULL) {
2615 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2617 g_object_unref (mime_part);
2619 gnome_vfs_file_info_unref (info);
2623 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2624 g_object_unref (stream);
2626 content_id = g_strdup_printf ("%d", priv->next_cid);
2627 tny_mime_part_set_content_id (mime_part, content_id);
2628 g_free (content_id);
2631 basename = g_path_get_basename (filename);
2632 tny_mime_part_set_filename (mime_part, basename);
2635 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2636 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2638 info->size == 0, info->size);
2639 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2640 gtk_widget_show_all (priv->attachments_caption);
2641 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2643 g_object_unref (mime_part);
2644 gnome_vfs_file_info_unref (info);
2651 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2654 ModestMsgEditWindowPrivate *priv;
2657 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2658 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2660 if (att_list == NULL) {
2661 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2662 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2663 g_object_unref (att_list);
2667 g_object_ref (att_list);
2670 if (tny_list_get_length (att_list) == 0) {
2671 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2673 gboolean dialog_response;
2674 gchar *message = NULL;
2675 gchar *filename = NULL;
2677 if (tny_list_get_length (att_list) == 1) {
2679 iter = tny_list_create_iterator (att_list);
2680 part = (TnyMimePart *) tny_iterator_get_current (iter);
2681 g_object_unref (iter);
2682 if (TNY_IS_MSG (part)) {
2683 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2685 filename = tny_header_dup_subject (header);
2686 g_object_unref (header);
2688 if (filename == NULL) {
2689 filename = g_strdup (_("mail_va_no_subject"));
2692 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2694 g_object_unref (part);
2696 filename = g_strdup ("");
2698 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2699 "emev_nc_delete_attachments",
2700 tny_list_get_length (att_list)), filename);
2703 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2707 if (dialog_response != GTK_RESPONSE_OK) {
2708 g_object_unref (att_list);
2712 for (iter = tny_list_create_iterator (att_list);
2713 !tny_iterator_is_done (iter);
2714 tny_iterator_next (iter)) {
2715 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2716 const gchar *att_id;
2717 tny_list_remove (priv->attachments, (GObject *) mime_part);
2719 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2721 if (tny_list_get_length (priv->attachments) == 0)
2722 gtk_widget_hide (priv->attachments_caption);
2723 att_id = tny_mime_part_get_content_id (mime_part);
2725 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2727 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2728 g_object_unref (mime_part);
2730 g_object_unref (iter);
2733 g_object_unref (att_list);
2735 /* if the last attachment has been removed, focus the Subject: field */
2736 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2737 gtk_widget_grab_focus (priv->subject_field);
2741 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2744 ModestMsgEditWindowPrivate *priv;
2747 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2749 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2751 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2753 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2757 font_size_clicked (GtkToolButton *button,
2758 ModestMsgEditWindow *window)
2760 ModestMsgEditWindowPrivate *priv;
2761 GtkWidget *selector, *dialog;
2763 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2765 selector = hildon_touch_selector_new ();
2766 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2767 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2769 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2770 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2771 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2773 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2777 WPTextBufferFormat format;
2779 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2781 memset (&format, 0, sizeof (format));
2782 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2784 format.cs.font_size = TRUE;
2785 format.cs.text_position = TRUE;
2786 format.cs.font = TRUE;
2787 format.font_size = new_index;
2788 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2790 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2791 GINT_TO_POINTER (new_index)))
2792 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2794 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2795 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2796 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2797 size_text, "</span>", NULL);
2799 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2803 gtk_widget_destroy (dialog);
2805 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2810 font_face_clicked (GtkToolButton *button,
2811 ModestMsgEditWindow *window)
2813 ModestMsgEditWindowPrivate *priv;
2814 GtkWidget *selector, *dialog;
2815 GtkCellRenderer *renderer;
2817 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2819 selector = hildon_touch_selector_new ();
2820 renderer = gtk_cell_renderer_text_new ();
2821 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2822 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2823 renderer, "family", 0, "text", 0, NULL);
2824 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2826 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2827 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2828 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2830 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2831 gint new_font_index;
2835 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2836 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2837 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2841 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2843 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2844 GINT_TO_POINTER(new_font_index)))
2845 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2847 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2848 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2850 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2854 gtk_tree_path_free (path);
2857 gtk_widget_destroy (dialog);
2859 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2864 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2867 ModestMsgEditWindowPrivate *priv = NULL;
2868 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2870 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2871 if (!priv->update_caption_visibility)
2874 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2876 gtk_widget_show (priv->cc_caption);
2878 gtk_widget_hide (priv->cc_caption);
2880 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2884 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2887 ModestMsgEditWindowPrivate *priv = NULL;
2888 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2890 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2891 if (!priv->update_caption_visibility)
2894 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2896 gtk_widget_show (priv->bcc_caption);
2898 gtk_widget_hide (priv->bcc_caption);
2900 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2904 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2905 ModestRecptEditor *editor)
2907 ModestMsgEditWindowPrivate *priv;
2909 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2910 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2912 /* we check for low-mem; in that case, show a warning, and don't allow
2913 * for the addressbook
2915 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2918 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2920 if (editor == NULL) {
2921 GtkWidget *view_focus, *parent;
2922 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2924 /* This code should be kept in sync with ModestRecptEditor. The
2925 textview inside the recpt editor is the one that really gets the
2926 focus. As it's inside a scrolled window, and this one inside the
2927 hbox recpt editor inherits from, we'll need to go up in the
2928 hierarchy to know if the text view is part of the recpt editor
2929 or if it's a different text entry */
2930 parent = gtk_widget_get_parent (view_focus);
2931 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2932 editor = MODEST_RECPT_EDITOR (parent);
2935 editor = MODEST_RECPT_EDITOR (priv->to_field);
2938 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2942 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2944 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2946 modest_msg_edit_window_open_addressbook (window, NULL);
2950 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2951 gboolean show_toolbar)
2953 ModestWindowPrivate *parent_priv;
2954 ModestMsgEditWindowPrivate *priv;
2956 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2957 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2958 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2960 /* We can not just use the code of
2961 modest_msg_edit_window_setup_toolbar because it has a
2962 mixture of both initialization and creation code. */
2964 gint current_format;
2965 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2966 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2967 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2968 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2970 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2973 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2978 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2979 TnyHeaderFlags priority_flags)
2981 ModestMsgEditWindowPrivate *priv;
2982 ModestWindowPrivate *parent_priv;
2984 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2986 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2987 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2989 if (priv->priority_flags != priority_flags) {
2990 GtkAction *priority_action = NULL;
2992 priv->priority_flags = priority_flags;
2994 switch (priority_flags) {
2995 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2996 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2997 MODEST_HEADER_ICON_HIGH,
2998 HILDON_ICON_SIZE_SMALL);
2999 gtk_widget_show (priv->priority_icon);
3000 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3001 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3003 case TNY_HEADER_FLAG_LOW_PRIORITY:
3004 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3005 MODEST_HEADER_ICON_LOW,
3006 HILDON_ICON_SIZE_SMALL);
3007 gtk_widget_show (priv->priority_icon);
3008 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3009 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3012 gtk_widget_hide (priv->priority_icon);
3013 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3014 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3017 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3018 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3020 gtk_widget_queue_resize (priv->subject_box);
3024 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3027 ModestMsgEditWindowPrivate *priv;
3028 ModestWindowPrivate *parent_priv;
3029 gint current_format;
3031 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3033 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3034 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3036 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3037 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3039 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3041 if (current_format != file_format) {
3042 switch (file_format) {
3043 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3044 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3045 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3046 if (parent_priv->toolbar)
3047 gtk_widget_show (parent_priv->toolbar);
3049 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3053 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3054 response = gtk_dialog_run (GTK_DIALOG (dialog));
3055 gtk_widget_destroy (dialog);
3056 if (response == GTK_RESPONSE_OK) {
3057 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3058 if (parent_priv->toolbar)
3059 gtk_widget_hide (parent_priv->toolbar);
3061 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3062 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3067 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3068 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3069 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3074 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3077 ModestMsgEditWindowPrivate *priv;
3078 WPTextBufferFormat oldfmt, fmt;
3079 gint old_position = 0;
3083 GdkColor *color = NULL;
3084 gboolean bold, bold_set, italic, italic_set;
3085 gboolean underline, underline_set;
3086 gboolean strikethrough, strikethrough_set;
3087 gboolean position_set;
3088 gboolean font_size_set, font_set, color_set;
3091 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3092 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3094 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3095 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3096 GTK_WINDOW(dialog), GTK_WINDOW (window));
3098 /* First we get the currently selected font information */
3099 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3101 switch (oldfmt.text_position) {
3102 case TEXT_POSITION_NORMAL:
3105 case TEXT_POSITION_SUPERSCRIPT:
3113 g_object_set (G_OBJECT (dialog),
3114 "bold", oldfmt.bold != FALSE,
3115 "bold-set", !oldfmt.cs.bold,
3116 "underline", oldfmt.underline != FALSE,
3117 "underline-set", !oldfmt.cs.underline,
3118 "italic", oldfmt.italic != FALSE,
3119 "italic-set", !oldfmt.cs.italic,
3120 "strikethrough", oldfmt.strikethrough != FALSE,
3121 "strikethrough-set", !oldfmt.cs.strikethrough,
3122 "color", &oldfmt.color,
3123 "color-set", !oldfmt.cs.color,
3124 "size", wp_font_size[oldfmt.font_size],
3125 "size-set", !oldfmt.cs.font_size,
3126 "position", old_position,
3127 "position-set", !oldfmt.cs.text_position,
3128 "family", wp_get_font_name (oldfmt.font),
3129 "family-set", !oldfmt.cs.font,
3132 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3133 GTK_WINDOW (dialog), GTK_WINDOW (window));
3134 gtk_widget_show_all (dialog);
3135 priv->font_dialog = dialog;
3136 response = gtk_dialog_run (GTK_DIALOG (dialog));
3137 priv->font_dialog = NULL;
3138 if (response == GTK_RESPONSE_OK) {
3140 g_object_get( dialog,
3142 "bold-set", &bold_set,
3143 "underline", &underline,
3144 "underline-set", &underline_set,
3146 "italic-set", &italic_set,
3147 "strikethrough", &strikethrough,
3148 "strikethrough-set", &strikethrough_set,
3150 "color-set", &color_set,
3152 "size-set", &font_size_set,
3153 "family", &font_name,
3154 "family-set", &font_set,
3155 "position", &position,
3156 "position-set", &position_set,
3161 if (response == GTK_RESPONSE_OK) {
3162 memset(&fmt, 0, sizeof(fmt));
3168 fmt.italic = italic;
3169 fmt.cs.italic = TRUE;
3171 if (underline_set) {
3172 fmt.underline = underline;
3173 fmt.cs.underline = TRUE;
3175 if (strikethrough_set) {
3176 fmt.strikethrough = strikethrough;
3177 fmt.cs.strikethrough = TRUE;
3182 ? TEXT_POSITION_NORMAL
3183 : ( ( position == 1 )
3184 ? TEXT_POSITION_SUPERSCRIPT
3185 : TEXT_POSITION_SUBSCRIPT );
3186 fmt.cs.text_position = TRUE;
3187 fmt.font_size = oldfmt.font_size;
3191 fmt.cs.color = TRUE;
3194 fmt.font = wp_get_font_index(font_name,
3199 if (font_size_set) {
3200 fmt.cs.font_size = TRUE;
3201 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3203 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3204 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3206 gtk_widget_destroy (dialog);
3208 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3212 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3214 ModestMsgEditWindowPrivate *priv;
3215 ModestWindowPrivate *parent_priv;
3216 gboolean was_rich_text, is_rich_text;
3218 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3219 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3220 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3222 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3224 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3226 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3228 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3230 gtk_widget_show (parent_priv->toolbar);
3232 gtk_widget_hide (parent_priv->toolbar);
3235 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3236 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3240 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3242 ModestMsgEditWindowPrivate *priv;
3244 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3245 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3247 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3249 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3250 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3255 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3257 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3259 priv->can_undo = can_undo;
3263 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3265 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3267 priv->can_redo = can_redo;
3271 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3273 ModestMsgEditWindowPrivate *priv;
3274 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3275 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3277 return priv->can_undo;
3281 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3283 ModestMsgEditWindowPrivate *priv;
3284 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3285 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3287 return priv->can_redo;
3292 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3295 GtkTextIter match_start, match_end;
3297 if (image_id == NULL)
3300 gtk_text_buffer_get_start_iter (buffer, &iter);
3302 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3303 GSList *tags = gtk_text_iter_get_tags (&match_start);
3305 for (node = tags; node != NULL; node = g_slist_next (node)) {
3306 GtkTextTag *tag = (GtkTextTag *) node->data;
3307 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3308 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3309 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3311 offset = gtk_text_iter_get_offset (&match_start);
3312 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3313 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3317 gtk_text_iter_forward_char (&iter);
3322 message_is_empty (ModestMsgEditWindow *window)
3324 ModestMsgEditWindowPrivate *priv = NULL;
3326 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3327 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3329 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3330 * so we can ignore markup.
3332 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3335 count = gtk_text_buffer_get_char_count (buf);
3341 msg_body_focus (GtkWidget *focus,
3342 GdkEventFocus *event,
3346 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3347 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3348 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3353 recpt_field_changed (GtkTextBuffer *buffer,
3354 ModestMsgEditWindow *editor)
3356 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3357 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3361 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3363 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3364 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3368 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3371 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3372 GtkTextBuffer *buffer;
3374 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3375 gtk_text_buffer_set_modified (buffer, modified);
3376 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3377 gtk_text_buffer_set_modified (buffer, modified);
3378 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3379 gtk_text_buffer_set_modified (buffer, modified);
3380 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3384 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3386 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3387 const char *account_name;
3388 GtkTextBuffer *buffer;
3390 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3391 if (gtk_text_buffer_get_modified (buffer))
3393 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3394 if (gtk_text_buffer_get_modified (buffer))
3396 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3397 if (gtk_text_buffer_get_modified (buffer))
3399 if (gtk_text_buffer_get_modified (priv->text_buffer))
3402 account_name = modest_selector_get_active_id (priv->from_field);
3403 if (priv->original_mailbox) {
3404 if (!account_name || strcmp (account_name, priv->original_mailbox))
3406 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3417 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3419 ModestMsgEditWindowPrivate *priv = NULL;
3420 GSList *address_list = NULL;
3422 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3423 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3425 /* check if there's no recipient added */
3426 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3427 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3428 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3429 /* no recipient contents, then select contacts */
3430 modest_msg_edit_window_open_addressbook (window, NULL);
3435 g_object_ref (window);
3436 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3437 (add_to_addressbook) ? &address_list : NULL)) {
3438 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3439 g_object_unref (window);
3442 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3443 (add_to_addressbook) ? &address_list : NULL)) {
3444 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3445 g_object_unref (window);
3448 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3449 (add_to_addressbook) ? &address_list : NULL)) {
3450 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3451 g_object_unref (window);
3455 /* Add contacts to address book */
3456 if (add_to_addressbook && address_list)
3457 modest_address_book_add_address_list (address_list);
3459 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3460 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3461 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3462 g_object_unref (window);
3469 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3471 GSList *recipients = NULL;
3472 ModestMsgEditWindowPrivate *priv;
3473 gchar *joined, *after_remove, *to, *cc, *bcc;
3475 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3477 /* First of all check names */
3478 if (!modest_msg_edit_window_check_names (self, FALSE))
3481 if (!modest_msg_edit_window_has_pending_addresses (self))
3484 /* Don't add the from obviously */
3485 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3486 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3487 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3489 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3494 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3497 recipients = modest_text_utils_split_addresses_list (after_remove);
3498 g_free (after_remove);
3501 /* Offer the user to add recipients to the address book */
3502 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3503 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3508 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3509 ModestMsgEditWindow *window)
3511 modest_msg_edit_window_offer_attach_file (window);
3515 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3517 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3519 return priv->clipboard_text;
3523 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3525 ModestMsgEditWindow *window)
3527 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3528 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3531 /* It could happen that the window was already closed */
3532 if (!GTK_WIDGET_VISIBLE (window))
3535 g_object_ref (window);
3536 text = gtk_clipboard_wait_for_text (selection_clipboard);
3538 if (priv->clipboard_text != NULL) {
3539 g_free (priv->clipboard_text);
3541 priv->clipboard_text = text;
3543 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3545 g_object_unref (window);
3548 static gboolean clipboard_owner_change_idle (gpointer userdata)
3550 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3551 ModestMsgEditWindowPrivate *priv;
3553 gdk_threads_enter ();
3554 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3555 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3557 priv->clipboard_owner_idle = 0;
3558 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3559 gdk_threads_leave ();
3565 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3567 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3568 if (priv->clipboard_owner_idle == 0) {
3569 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3570 clipboard_owner_change_idle,
3571 g_object_ref (window),
3577 subject_field_move_cursor (GtkEntry *entry,
3578 GtkMovementStep step,
3583 /* It could happen that the window was already closed */
3584 if (!GTK_WIDGET_VISIBLE (window))
3587 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3591 update_window_title (ModestMsgEditWindow *window)
3593 ModestMsgEditWindowPrivate *priv = NULL;
3594 const gchar *subject;
3596 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3597 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3598 if (subject == NULL || subject[0] == '\0')
3599 subject = _("mail_va_new_email");
3601 modest_window_set_title (MODEST_WINDOW (window), subject);
3607 body_insert_text (GtkTextBuffer *buffer,
3608 GtkTextIter *location,
3611 ModestMsgEditWindow *window)
3613 GtkTextIter end_iter;
3620 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3622 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3624 offset = gtk_text_iter_get_offset (&end_iter);
3625 line = gtk_text_iter_get_line (&end_iter);
3629 while (text_offset < text + len) {
3630 if (*text_offset == '\n')
3632 if (text_lines + line >= MAX_BODY_LINES) {
3633 len = text_offset - text;
3639 utf8_len = g_utf8_strlen (text, len);
3641 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3642 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3643 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3648 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3650 /* Prevent endless recursion */
3651 result = g_strndup (text, utf8_end - text);
3652 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3653 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3654 (gpointer) result, (gpointer) (utf8_end - text),
3656 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3660 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3661 if (priv->max_chars_banner == NULL) {
3662 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3663 _CS("ckdg_ib_maximum_characters_reached"));
3664 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3670 subject_field_changed (GtkEditable *editable,
3671 ModestMsgEditWindow *window)
3673 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3674 update_window_title (window);
3675 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3676 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3677 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3680 subject_field_insert_text (GtkEditable *editable,
3682 gint new_text_length,
3684 ModestMsgEditWindow *window)
3686 GString *result = g_string_new ("");
3688 gint result_len = 0;
3689 const gchar *entry_text = NULL;
3692 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3693 old_length = g_utf8_strlen (entry_text, -1);
3695 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3696 gunichar c = g_utf8_get_char_validated (current, 8);
3697 /* Invalid unichar, stop */
3703 result = g_string_append_unichar (result, c);
3707 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3708 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3711 /* Prevent endless recursion */
3712 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3713 g_signal_emit_by_name (editable, "insert-text",
3714 (gpointer) result->str, (gpointer) result->len,
3715 (gpointer) position, (gpointer) window);
3716 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3720 if (result_len + old_length > 1000) {
3721 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3722 _CS("ckdg_ib_maximum_characters_reached"));
3724 g_string_free (result, TRUE);
3728 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3731 ModestMsgEditWindowPrivate *priv = NULL;
3733 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3734 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3736 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3739 gtk_widget_show_all (priv->isearch_toolbar);
3740 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3742 gtk_widget_hide_all (priv->isearch_toolbar);
3743 gtk_widget_grab_focus (priv->msg_body);
3748 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3750 GtkTextIter *match_start,
3751 GtkTextIter *match_end)
3753 GtkTextIter end_iter;
3754 gchar *str_casefold;
3757 gchar *range_casefold;
3760 gboolean result = FALSE;
3767 gtk_text_iter_forward_to_end (&end_iter);
3769 str_casefold = g_utf8_casefold (str, -1);
3770 str_chars_n = strlen (str);
3772 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3773 range_casefold = g_utf8_casefold (range_text, -1);
3774 range_chars_n = strlen (range_casefold);
3776 if (range_chars_n < str_chars_n) {
3777 g_free (str_casefold);
3778 g_free (range_text);
3779 g_free (range_casefold);
3783 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3784 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3785 if (!g_utf8_collate (range_subtext, str_casefold)) {
3786 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3788 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3789 match_start, match_end, NULL)) {
3790 g_debug ("Matched string with collate, but not matched in model");
3792 g_free (found_text);
3794 g_free (range_subtext);
3798 g_free (str_casefold);
3799 g_free (range_text);
3800 g_free (range_casefold);
3807 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
3808 ModestMsgEditWindow *window)
3810 const gchar *current_search = NULL;
3811 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3813 GtkTextIter selection_start, selection_end;
3814 GtkTextIter match_start, match_end;
3815 gboolean continue_search = FALSE;
3817 if (message_is_empty (window)) {
3818 g_free (priv->last_search);
3819 priv->last_search = NULL;
3820 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3824 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
3825 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3826 g_free (priv->last_search);
3827 priv->last_search = NULL;
3828 /* Information banner about empty search */
3829 modest_platform_system_banner (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3833 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3834 continue_search = TRUE;
3836 g_free (priv->last_search);
3837 priv->last_search = g_strdup (current_search);
3840 if (continue_search) {
3841 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3842 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3843 &match_start, &match_end);
3845 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3847 GtkTextIter buffer_start;
3848 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3849 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3850 &match_start, &match_end);
3852 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3855 /* Mark as selected the string found in search */
3857 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3858 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3859 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3861 g_free (priv->last_search);
3862 priv->last_search = NULL;
3867 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3869 ModestMsgEditWindowPrivate *priv;
3871 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3876 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3879 ModestMsgEditWindowPrivate *priv;
3881 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3886 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
3887 ModestMsgEditWindow *window)
3889 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
3893 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3896 ModestMsgEditWindowPrivate *priv;
3897 TnyHeader *header = NULL;
3899 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3900 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3902 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3904 if (priv->draft_msg != NULL) {
3905 g_object_unref (priv->draft_msg);
3908 if (draft != NULL) {
3909 g_object_ref (draft);
3910 header = tny_msg_get_header (draft);
3911 if (priv->msg_uid) {
3912 g_free (priv->msg_uid);
3913 priv->msg_uid = NULL;
3915 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3918 priv->draft_msg = draft;
3922 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3923 GtkTextIter *start, GtkTextIter *end,
3926 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3927 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3930 if (tag == NULL) return;
3931 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3932 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3933 replace_with_images (window, priv->images);
3938 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3941 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3943 g_return_if_fail (TNY_IS_MIME_PART (part));
3944 tny_list_prepend (priv->attachments, (GObject *) part);
3945 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3946 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3947 gtk_widget_show_all (priv->attachments_caption);
3948 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3952 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3954 ModestMsgEditWindowPrivate *priv;
3956 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3957 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3959 return priv->msg_uid;
3963 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3964 ModestMsgEditWindowWidgetType widget_type)
3966 ModestMsgEditWindowPrivate *priv;
3968 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3969 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3971 switch (widget_type) {
3972 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3973 return priv->msg_body;
3975 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3976 return priv->to_field;
3978 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3979 return priv->cc_field;
3981 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3982 return priv->bcc_field;
3984 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3985 return priv->subject_field;
3987 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3988 return priv->attachments_view;
3996 remove_tags (WPTextBuffer *buffer)
3998 GtkTextIter start, end;
4000 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4001 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4003 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4007 on_account_removed (TnyAccountStore *account_store,
4008 TnyAccount *account,
4011 /* Do nothing if it's a store account, because we use the
4012 transport to send the messages */
4013 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4014 const gchar *parent_acc = NULL;
4015 const gchar *our_acc = NULL;
4017 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4018 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4019 /* Close this window if I'm showing a message of the removed account */
4020 if (strcmp (parent_acc, our_acc) == 0)
4021 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4026 update_signature (ModestMsgEditWindow *self,
4027 const gchar *old_account,
4028 const gchar *new_account)
4030 ModestMsgEditWindowPrivate *priv;
4031 gboolean has_old_signature, has_new_signature;
4033 ModestAccountMgr *mgr;
4036 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4038 gtk_text_buffer_begin_user_action (priv->text_buffer);
4040 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4041 mgr = modest_runtime_get_account_mgr ();
4045 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4046 if (has_old_signature) {
4047 GtkTextIter match_start, match_end;
4049 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4050 seems that the search has some problems
4051 with the blank space at the end */
4052 if (gtk_text_iter_forward_search (&iter, "--",
4053 GTK_TEXT_SEARCH_TEXT_ONLY,
4054 &match_start, NULL, NULL)) {
4055 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4056 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4058 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4059 &match_start, &match_end, NULL)) {
4063 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4068 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4069 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4070 if (has_new_signature) {
4072 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4073 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4075 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4076 g_free (full_signature);
4079 gtk_text_buffer_end_user_action (priv->text_buffer);
4082 static void update_branding (ModestMsgEditWindow *self,
4083 const gchar *new_account)
4085 ModestMsgEditWindowPrivate *priv;
4086 ModestAccountMgr *mgr;
4087 const GdkPixbuf *new_icon = NULL;
4088 gchar *new_label = NULL;
4089 gboolean show = FALSE;
4091 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4093 mgr = modest_runtime_get_account_mgr ();
4095 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4097 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4098 gtk_widget_show (priv->brand_icon);
4101 gtk_widget_hide (priv->brand_icon);
4104 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4105 gtk_widget_show (priv->brand_label);
4109 gtk_widget_hide (priv->brand_label);
4113 gtk_widget_show (priv->brand_container);
4115 gtk_widget_hide (priv->brand_container);
4119 from_field_changed (GtkWidget *button,
4120 ModestMsgEditWindow *self)
4122 ModestMsgEditWindowPrivate *priv;
4123 gchar *old_account, *new_account;
4125 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4127 old_account = priv->last_from_account;
4128 new_account = modest_selector_get_active_id (priv->from_field);
4131 g_warning ("%s, could not get the new account", __FUNCTION__);
4135 /* If the From is the same do nothing */
4136 if (old_account && new_account && !strcmp (old_account, new_account))
4139 priv->last_from_account = new_account;
4141 update_signature (self, old_account, new_account);
4142 update_branding (self, new_account);
4146 typedef struct _MessageSettingsHelper {
4147 ModestMsgEditWindow *window;
4148 GSList *priority_group;
4149 GSList *format_group;
4150 GtkToggleButton *current_priority;
4151 GtkToggleButton *current_format;
4152 } MessageSettingsHelper;
4155 on_priority_toggle (GtkToggleButton *button,
4156 MessageSettingsHelper *helper)
4159 ModestMsgEditWindowPrivate *priv;
4161 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4162 if (gtk_toggle_button_get_active (button)) {
4164 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4165 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4166 if ((node_button != button) &&
4167 gtk_toggle_button_get_active (node_button)) {
4168 gtk_toggle_button_set_active (node_button, FALSE);
4171 helper->current_priority = button;
4173 gboolean found = FALSE;
4174 /* If no one is active, activate it again */
4175 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4176 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4177 if (gtk_toggle_button_get_active (node_button)) {
4183 gtk_toggle_button_set_active (button, TRUE);
4189 on_format_toggle (GtkToggleButton *button,
4190 MessageSettingsHelper *helper)
4193 ModestMsgEditWindowPrivate *priv;
4195 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4196 if (gtk_toggle_button_get_active (button)) {
4198 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4199 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4200 if ((node_button != button) &&
4201 gtk_toggle_button_get_active (node_button)) {
4202 gtk_toggle_button_set_active (node_button, FALSE);
4205 helper->current_format = button;
4207 gboolean found = FALSE;
4208 /* If no one is active, activate it again */
4209 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4210 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4211 if (gtk_toggle_button_get_active (node_button)) {
4217 gtk_toggle_button_set_active (button, TRUE);
4224 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4229 GtkWidget *priority_hbox;
4230 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4231 GtkWidget *captioned;
4232 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4233 GtkWidget *format_hbox;
4234 GtkWidget *html_toggle, *text_toggle;
4235 ModestMsgEditWindowPrivate *priv;
4236 MessageSettingsHelper helper = {0,};
4238 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4239 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4240 helper.window = window;
4241 helper.priority_group = NULL;
4242 helper.format_group = NULL;
4244 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4245 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4247 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4248 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4249 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4250 vbox = gtk_vbox_new (FALSE, 0);
4251 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4252 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4253 gtk_container_add (GTK_CONTAINER (align), vbox);
4254 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4255 gtk_widget_show (align);
4256 gtk_widget_show (vbox);
4258 /* Priority toggles */
4259 priority_hbox = gtk_hbox_new (TRUE, 0);
4260 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4261 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4262 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4263 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4264 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4265 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4266 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4267 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4268 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4269 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4270 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4271 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4272 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4273 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4274 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4275 gtk_widget_show_all (priority_hbox);
4276 captioned = modest_toolkit_utils_create_captioned (title_sizegroup, value_sizegroup,
4277 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4278 gtk_widget_show (captioned);
4279 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4281 /* format toggles */
4282 format_hbox = gtk_hbox_new (TRUE, 0);
4283 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4284 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4285 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4286 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4287 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4288 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4289 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4290 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4291 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4292 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4293 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4294 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4295 gtk_widget_show_all (format_hbox);
4296 gtk_widget_show (format_hbox);
4297 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4300 g_object_unref (title_sizegroup);
4301 g_object_unref (value_sizegroup);
4303 /* Set current values */
4304 switch (priv->priority_flags) {
4305 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4306 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4307 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4309 case TNY_HEADER_FLAG_LOW_PRIORITY:
4310 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4311 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4314 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4315 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4319 switch (modest_msg_edit_window_get_format (window)) {
4320 case MODEST_MSG_EDIT_FORMAT_TEXT:
4321 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4322 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4324 case MODEST_MSG_EDIT_FORMAT_HTML:
4326 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4327 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4331 /* Signal connects */
4332 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4333 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4334 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4335 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4336 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4338 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4339 GTK_WINDOW (dialog), GTK_WINDOW (window));
4341 /* Save settings if the user clicked on done */
4342 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4343 TnyHeaderFlags flags;
4344 ModestMsgEditFormat old_format, new_format;
4346 /* Set priority flags */
4347 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4348 if (priv->priority_flags != flags)
4349 modest_msg_edit_window_set_priority_flags (window, flags);
4351 /* Set edit format */
4352 old_format = modest_msg_edit_window_get_format (window);
4353 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4354 if (old_format != new_format) {
4355 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4356 modest_msg_edit_window_set_file_format (window, file_format);
4360 gtk_widget_destroy (dialog);
4361 g_slist_free (helper.priority_group);
4365 on_message_settings (GtkAction *action,
4366 ModestMsgEditWindow *window)
4368 modest_msg_edit_window_show_msg_settings_dialog (window);
4372 on_cc_button_toggled (GtkWidget *button,
4373 ModestMsgEditWindow *window)
4375 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4377 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4378 modest_togglable_get_active (button));
4382 on_bcc_button_toggled (GtkWidget *button,
4383 ModestMsgEditWindow *window)
4385 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4387 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4388 modest_togglable_get_active (button));
4392 setup_menu (ModestMsgEditWindow *self)
4394 ModestMsgEditWindowPrivate *priv = NULL;
4396 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4398 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4400 /* Settings menu buttons */
4401 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4402 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4404 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4405 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4406 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4407 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4408 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4409 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4411 priv->cc_button = hildon_check_button_new (0);
4412 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4413 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4415 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4416 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4417 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4419 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4420 _("mcen_me_editor_showbcc"));
4421 modest_togglable_set_active (priv->bcc_button,
4423 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4425 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4426 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4428 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4429 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4430 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4431 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4432 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4434 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4435 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4436 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4437 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4438 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4440 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4441 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4446 emit_open_addressbook (GtkButton *button,
4447 ModestRecptEditor *editor)
4449 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4453 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4454 const gchar *label, GtkWidget *control)
4456 GtkWidget *abook_button;
4459 GtkWidget *label_widget;
4461 box = gtk_hbox_new (FALSE, 0);
4463 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4464 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4466 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4467 label_widget = gtk_label_new (label);
4468 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4469 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4471 gtk_container_add (GTK_CONTAINER (align), abook_button);
4472 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4473 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4474 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4475 if (title_size_group)
4476 gtk_size_group_add_widget (title_size_group, label_widget);
4477 if (value_size_group)
4478 gtk_size_group_add_widget (value_size_group, control);
4480 g_signal_connect (G_OBJECT (abook_button), "clicked",
4481 G_CALLBACK (emit_open_addressbook), control);
4487 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4489 ModestMsgEditWindowPrivate *priv = NULL;
4491 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4493 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4494 priv->max_chars_banner = NULL;
4498 has_pending_addresses (ModestRecptEditor *recpt_editor)
4500 const gchar *recipients = NULL;
4501 GSList *start_indexes = NULL, *end_indexes = NULL;
4502 GSList *current_start, *current_end;
4503 GtkTextBuffer *buffer;
4504 gint offset_delta = 0;
4506 gboolean has_recipients_to_add = FALSE;
4508 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4509 last_length = g_utf8_strlen (recipients, -1);
4510 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4515 current_start = start_indexes;
4516 current_end = end_indexes;
4517 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4519 while (current_start && !has_recipients_to_add) {
4521 gchar *start_ptr, *end_ptr;
4522 gint start_pos, end_pos;
4524 start_pos = (*((gint*) current_start->data)) + offset_delta;
4525 end_pos = (*((gint*) current_end->data)) + offset_delta;
4527 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4528 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4530 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4532 if (modest_text_utils_validate_recipient (address, NULL)) {
4533 if (!modest_address_book_has_address (address)) {
4534 has_recipients_to_add = TRUE;
4537 current_start = g_slist_next (current_start);
4538 current_end = g_slist_next (current_end);
4540 return has_recipients_to_add;
4544 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4546 ModestMsgEditWindowPrivate *priv = NULL;
4548 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4550 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4552 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4553 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4554 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))