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 <modest-selector-picker.h>
48 #include <widgets/modest-recpt-editor.h>
49 #include <widgets/modest-attachments-view.h>
51 #include <modest-runtime.h>
53 #include "modest-platform.h"
54 #include "modest-icon-names.h"
55 #include "modest-widget-memory.h"
56 #include "modest-window-priv.h"
57 #include "modest-mail-operation.h"
58 #include "modest-tny-platform-factory.h"
59 #include "modest-tny-msg.h"
60 #include "modest-tny-folder.h"
61 #include "modest-tny-account.h"
62 #include "modest-address-book.h"
63 #include "modest-text-utils.h"
64 #include <tny-simple-list.h>
65 #include <modest-wp-text-view.h>
66 #include <wptextbuffer.h>
67 #include <hildon/hildon-pannable-area.h>
68 #include <hildon/hildon-touch-selector.h>
69 #include <hildon/hildon-picker-dialog.h>
70 #include "modest-msg-edit-window-ui-dimming.h"
72 #include "modest-hildon-includes.h"
73 #include "widgets/modest-msg-edit-window-ui.h"
74 #include <libgnomevfs/gnome-vfs-mime.h>
75 #include <modest-utils.h>
76 #include "modest-maemo-utils.h"
77 #include <modest-ui-constants.h>
78 #include "modest-color-button.h"
80 #ifdef MODEST_USE_CALENDAR_WIDGETS
81 #include <calendar-ui-widgets.h>
84 #define DEFAULT_FONT_SIZE 3
85 #define DEFAULT_FONT 2
86 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
87 #define DEFAULT_MAIN_VBOX_SPACING 0
88 #define SUBJECT_MAX_LENGTH 1000
89 #define IMAGE_MAX_WIDTH 560
90 #define DEFAULT_FONT_SCALE 1.5
91 #define ATTACHMENT_BUTTON_WIDTH 118
92 #define MAX_FROM_VALUE 36
93 #define MAX_BODY_LENGTH 128*1024
94 #define MAX_BODY_LINES 2048
96 static gboolean is_wp_text_buffer_started = FALSE;
98 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
99 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
100 static void modest_msg_edit_window_finalize (GObject *obj);
102 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
103 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
104 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
106 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
107 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
108 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
109 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
110 GtkTextIter *start, GtkTextIter *end,
112 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
113 static void body_insert_text (GtkTextBuffer *buffer,
114 GtkTextIter *location,
117 ModestMsgEditWindow *window);
118 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
119 static void subject_field_insert_text (GtkEditable *editable,
121 gint new_text_length,
123 ModestMsgEditWindow *window);
124 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
126 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
128 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
129 ModestRecptEditor *editor);
130 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
131 ModestMsgEditWindow *window);
133 /* ModestWindow methods implementation */
134 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
135 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
136 gboolean show_toolbar);
137 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
139 ModestMsgEditWindow *window);
140 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
141 static void subject_field_move_cursor (GtkEntry *entry,
142 GtkMovementStep step,
146 static void update_window_title (ModestMsgEditWindow *window);
149 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
150 ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
152 ModestMsgEditWindow *window);
153 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
155 GtkTextIter *match_start,
156 GtkTextIter *match_end);
158 static void remove_tags (WPTextBuffer *buffer);
160 static void on_account_removed (TnyAccountStore *account_store,
164 static void init_window (ModestMsgEditWindow *obj);
166 gboolean scroll_drag_timeout (gpointer userdata);
167 static void correct_scroll (ModestMsgEditWindow *w);
168 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
169 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
170 ModestMsgEditWindow *userdata);
171 static void text_buffer_mark_set (GtkTextBuffer *buffer,
174 ModestMsgEditWindow *userdata);
175 static void on_show_toolbar_button_toggled (HildonCheckButton *button,
176 ModestMsgEditWindow *window);
177 static void on_message_settings (GtkAction *action,
178 ModestMsgEditWindow *window);
179 static void setup_menu (ModestMsgEditWindow *self);
181 static void from_field_changed (HildonPickerButton *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;
274 GtkWidget *bottom_send_button;
275 GtkWidget *bottom_send_button_container;
277 GtkWidget *cc_caption;
278 GtkWidget *bcc_caption;
279 gboolean update_caption_visibility;
280 GtkWidget *attachments_caption;
282 GtkTextBuffer *text_buffer;
284 GtkWidget *font_size_toolitem;
285 GtkWidget *font_face_toolitem;
286 GtkWidget *font_color_button;
287 GtkWidget *font_color_toolitem;
288 GSList *font_items_group;
289 GtkTreeModel *faces_model;
290 gint current_face_index;
291 GtkWidget *font_tool_button_label;
292 GtkTreeModel *sizes_model;
293 gint current_size_index;
294 GtkWidget *size_tool_button_label;
296 GtkWidget *find_toolbar;
299 GtkWidget *font_dialog;
302 guint correct_scroll_idle;
303 guint scroll_drag_timeout_id;
307 TnyList *attachments;
312 TnyHeaderFlags priority_flags;
314 gboolean can_undo, can_redo;
315 gulong clipboard_change_handler_id;
316 gulong default_clipboard_change_handler_id;
317 gulong account_removed_handler_id;
318 guint clipboard_owner_idle;
319 gchar *clipboard_text;
328 GtkWidget *cc_button;
329 GtkWidget *bcc_button;
330 GtkWidget *show_toolbar_button;
332 GtkWidget *max_chars_banner;
334 GtkWidget *brand_icon;
335 GtkWidget *brand_label;
336 GtkWidget *brand_container;
338 TnyList *custom_header_pairs;
341 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
342 MODEST_TYPE_MSG_EDIT_WINDOW, \
343 ModestMsgEditWindowPrivate))
345 static GtkWindowClass *parent_class = NULL;
347 /* uncomment the following if you have defined any signals */
348 /* static guint signals[LAST_SIGNAL] = {0}; */
351 modest_msg_edit_window_get_type (void)
353 static GType my_type = 0;
355 static const GTypeInfo my_info = {
356 sizeof(ModestMsgEditWindowClass),
357 NULL, /* base init */
358 NULL, /* base finalize */
359 (GClassInitFunc) modest_msg_edit_window_class_init,
360 NULL, /* class finalize */
361 NULL, /* class data */
362 sizeof(ModestMsgEditWindow),
364 (GInstanceInitFunc) modest_msg_edit_window_init,
367 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
368 "ModestMsgEditWindow",
376 save_state (ModestWindow *self)
378 modest_widget_memory_save (modest_runtime_get_conf(),
379 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
384 restore_settings (ModestMsgEditWindow *self)
386 ModestConf *conf = NULL;
388 conf = modest_runtime_get_conf ();
390 /* Dim at start clipboard actions */
391 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
396 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
398 GObjectClass *gobject_class;
399 ModestWindowClass *modest_window_class;
400 gobject_class = (GObjectClass*) klass;
401 modest_window_class = (ModestWindowClass*) klass;
403 parent_class = g_type_class_peek_parent (klass);
404 gobject_class->finalize = modest_msg_edit_window_finalize;
406 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
407 modest_window_class->save_state_func = save_state;
408 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
410 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
414 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
416 ModestMsgEditWindowPrivate *priv;
417 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
419 priv->msg_body = NULL;
420 priv->from_field = NULL;
421 priv->to_field = NULL;
422 priv->cc_field = NULL;
423 priv->bcc_field = NULL;
424 priv->subject_field = NULL;
425 priv->attachments = TNY_LIST (tny_simple_list_new ());
426 priv->images = TNY_LIST (tny_simple_list_new ());
427 priv->images_size = 0;
428 priv->images_count = 0;
431 priv->cc_caption = NULL;
432 priv->bcc_caption = NULL;
433 priv->update_caption_visibility = FALSE;
435 priv->priority_flags = 0;
437 priv->find_toolbar = NULL;
438 priv->last_search = NULL;
440 priv->draft_msg = NULL;
441 priv->outbox_msg = NULL;
442 priv->msg_uid = NULL;
444 priv->can_undo = FALSE;
445 priv->can_redo = FALSE;
446 priv->clipboard_change_handler_id = 0;
447 priv->default_clipboard_change_handler_id = 0;
448 priv->account_removed_handler_id = 0;
449 priv->clipboard_owner_idle = 0;
450 priv->clipboard_text = NULL;
453 priv->scroll_drag_timeout_id = 0;
454 priv->correct_scroll_idle = 0;
455 priv->last_upper = 0.0;
457 priv->font_dialog = NULL;
458 priv->app_menu = NULL;
460 priv->references = NULL;
461 priv->in_reply_to = NULL;
462 priv->max_chars_banner = NULL;
463 priv->custom_header_pairs = TNY_LIST (tny_simple_list_new ());
465 if (!is_wp_text_buffer_started) {
466 is_wp_text_buffer_started = TRUE;
467 wp_text_buffer_library_init ();
472 hildon_program_add_window (hildon_program_get_instance(),
477 multimailbox_get_default_mailbox (const gchar *account_name)
479 gchar *transport_account;
480 gchar *result = NULL;
482 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
484 TNY_ACCOUNT_TYPE_TRANSPORT);
485 if (transport_account) {
487 ModestProtocolRegistry *registry;
489 registry = modest_runtime_get_protocol_registry ();
491 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
492 MODEST_ACCOUNT_PROTO, TRUE);
494 ModestProtocol *protocol =
495 modest_protocol_registry_get_protocol_by_name (registry,
496 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
498 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
499 ModestPairList *pair_list;
501 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
504 ModestPair *pair = (ModestPair *) pair_list->data;
505 result = g_strdup ((const gchar *) pair->first);
506 modest_pair_list_free (pair_list);
517 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
519 static ModestPairList*
520 get_transports (void)
522 GSList *transports = NULL;
524 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
525 GSList *accounts = modest_account_mgr_account_names (account_mgr,
526 TRUE /* only enabled accounts. */);
528 GSList *cursor = accounts;
530 gchar *account_name = cursor->data;
533 gchar *transport_account;
534 gboolean multi_mailbox = FALSE;
535 ModestProtocol *protocol = NULL;
537 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
539 transport_account = modest_account_mgr_get_server_account_name
540 (modest_runtime_get_account_mgr (),
542 TNY_ACCOUNT_TYPE_TRANSPORT);
543 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
544 ModestPairList *pair_list;
545 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
548 transports = g_slist_concat (transports, pair_list);
549 multi_mailbox = TRUE;
554 if (!multi_mailbox) {
555 gchar *from_string = NULL;
557 from_string = modest_account_mgr_get_from_string (account_mgr,
559 if (from_string && account_name) {
560 gchar *name = account_name;
561 ModestPair *pair = modest_pair_new ((gpointer) name,
562 (gpointer) from_string , TRUE);
563 transports = g_slist_prepend (transports, pair);
568 cursor = cursor->next;
570 g_slist_free (accounts); /* only free the accounts, not the elements,
571 * because they are used in the pairlist */
575 static void window_focus (GtkWindow *window,
579 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
583 scroll_drag_timeout (gpointer userdata)
585 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
586 ModestMsgEditWindowPrivate *priv;
588 /* It could happen that the window was already closed */
589 if (!GTK_WIDGET_VISIBLE (win))
592 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
594 correct_scroll_without_drag_check (win, TRUE);
596 priv->scroll_drag_timeout_id = 0;
602 correct_scroll_without_drag_check_idle (gpointer userdata)
604 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
605 ModestMsgEditWindowPrivate *priv;
607 GdkRectangle rectangle;
608 gint offset_min, offset_max;
612 /* It could happen that the window was already closed */
613 if (!GTK_WIDGET_VISIBLE (w))
616 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
618 insert = gtk_text_buffer_get_insert (priv->text_buffer);
619 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
621 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
622 offset_min = priv->msg_body->allocation.y + rectangle.y;
623 offset_max = offset_min + rectangle.height;
625 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
626 offset_min = MAX (offset_min - 48, 0);
627 offset_max = MIN (offset_max + 48, vadj->upper);
629 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
631 priv->correct_scroll_idle = 0;
636 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
638 ModestMsgEditWindowPrivate *priv;
640 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
642 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
645 if (priv->correct_scroll_idle > 0) {
649 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
650 (GSourceFunc) correct_scroll_without_drag_check_idle,
656 correct_scroll (ModestMsgEditWindow *w)
658 ModestMsgEditWindowPrivate *priv;
660 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
661 if (gtk_grab_get_current () == priv->msg_body) {
662 if (priv->scroll_drag_timeout_id == 0) {
663 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
665 (GSourceFunc) scroll_drag_timeout,
672 correct_scroll_without_drag_check (w, TRUE);
676 text_buffer_end_user_action (GtkTextBuffer *buffer,
677 ModestMsgEditWindow *userdata)
680 correct_scroll (userdata);
684 text_buffer_mark_set (GtkTextBuffer *buffer,
687 ModestMsgEditWindow *userdata)
689 gtk_text_buffer_begin_user_action (buffer);
690 gtk_text_buffer_end_user_action (buffer);
694 cut_clipboard_check (GtkTextView *text_view,
697 GtkTextBuffer *buffer;
699 buffer = gtk_text_view_get_buffer (text_view);
700 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
701 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
706 copy_clipboard_check (GtkTextView *text_view,
709 GtkTextBuffer *buffer;
711 buffer = gtk_text_view_get_buffer (text_view);
712 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
713 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
718 attachment_deleted (ModestAttachmentsView *attachments_view,
721 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
726 body_size_request (GtkWidget *body,
730 ModestMsgEditWindowPrivate *priv;
733 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(user_data);
735 /* Make sure the body always get at least 70 pixels */
736 if (req->height < 70)
739 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
740 if (priv->header_box->allocation.height + req->height > GTK_WIDGET (user_data)->allocation.height) {
741 if (!GTK_WIDGET_VISIBLE (priv->bottom_send_button_container)) {
742 gtk_widget_show (priv->bottom_send_button_container);
745 if (GTK_WIDGET_VISIBLE (priv->bottom_send_button_container)) {
746 gtk_widget_hide (priv->bottom_send_button_container);
752 connect_signals (ModestMsgEditWindow *obj)
754 ModestMsgEditWindowPrivate *priv;
756 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
758 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
759 G_CALLBACK (text_buffer_refresh_attributes), obj);
760 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
761 G_CALLBACK (text_buffer_can_undo), obj);
762 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
763 G_CALLBACK (text_buffer_can_redo), obj);
764 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
765 G_CALLBACK (body_changed), obj);
766 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
767 G_CALLBACK (body_insert_text), obj);
768 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
769 G_CALLBACK (body_changed), obj);
770 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
771 G_CALLBACK (text_buffer_end_user_action), obj);
772 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
773 G_CALLBACK (text_buffer_mark_set), obj);
774 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
775 G_CALLBACK (text_buffer_apply_tag), obj);
776 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
777 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
778 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
779 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
780 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
781 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
783 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
784 G_CALLBACK (modest_ui_actions_on_send), obj);
786 g_signal_connect (G_OBJECT (priv->bottom_send_button), "clicked",
787 G_CALLBACK (modest_ui_actions_on_send), obj);
789 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
790 G_CALLBACK (from_field_changed), obj);
792 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
793 G_CALLBACK (msg_body_focus), obj);
794 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
795 G_CALLBACK (msg_body_focus), obj);
796 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
797 G_CALLBACK (body_size_request), obj);
798 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
799 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
800 "changed", G_CALLBACK (recpt_field_changed), obj);
801 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
802 "changed", G_CALLBACK (recpt_field_changed), obj);
803 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
804 "changed", G_CALLBACK (recpt_field_changed), obj);
805 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
806 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
807 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
809 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
810 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
812 priv->clipboard_change_handler_id =
813 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
814 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
815 priv->default_clipboard_change_handler_id =
816 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
817 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
819 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
820 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
821 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
825 init_wp_text_view_style ()
827 static gboolean initialized = FALSE;
830 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
836 init_window (ModestMsgEditWindow *obj)
838 GtkWidget *to_caption, *subject_caption;
839 GtkWidget *main_vbox;
840 ModestMsgEditWindowPrivate *priv;
841 GtkActionGroup *action_group;
842 ModestWindowPrivate *parent_priv;
843 GdkPixbuf *window_icon = NULL;
844 GError *error = NULL;
846 GtkSizeGroup *title_size_group;
847 GtkSizeGroup *value_size_group;
848 GtkWidget *window_box;
849 GtkWidget *window_align;
850 #if (GTK_MINOR_VERSION >= 10)
851 GdkAtom deserialize_type;
853 GtkWidget *from_send_hbox;
854 GtkWidget *send_icon;
855 GtkWidget *attachments_label;
856 GtkWidget *branding_box;
858 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
859 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
861 parent_priv->ui_manager = gtk_ui_manager_new();
862 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
863 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
865 /* Add common actions */
866 gtk_action_group_add_actions (action_group,
867 modest_msg_edit_action_entries,
868 G_N_ELEMENTS (modest_msg_edit_action_entries),
870 gtk_action_group_add_actions (action_group,
871 hildon2_msg_edit_action_entries,
872 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
874 gtk_action_group_add_toggle_actions (action_group,
875 modest_msg_edit_toggle_action_entries,
876 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
878 gtk_action_group_add_radio_actions (action_group,
879 modest_msg_edit_alignment_radio_action_entries,
880 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
882 G_CALLBACK (modest_ui_actions_on_change_justify),
884 gtk_action_group_add_radio_actions (action_group,
885 modest_msg_edit_priority_action_entries,
886 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
888 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
890 gtk_action_group_add_radio_actions (action_group,
891 modest_msg_edit_file_format_action_entries,
892 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
893 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
894 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
896 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
897 g_object_unref (action_group);
899 /* Load the UI definition */
900 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
903 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
904 g_clear_error (&error);
907 /* Add accelerators */
908 gtk_window_add_accel_group (GTK_WINDOW (obj),
909 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
911 parent_priv->menubar = NULL;
913 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
914 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
916 /* Note: This ModestPairList* must exist for as long as the picker
917 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
918 * so it can't know how to manage its memory. */
919 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
920 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
922 modest_selector_picker_set_value_max_chars (MODEST_SELECTOR_PICKER (priv->from_field), MAX_FROM_VALUE);
923 modest_maemo_utils_set_hbutton_layout (title_size_group, NULL,
924 _("mail_va_from"), priv->from_field);
925 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
926 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
927 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
929 priv->to_field = modest_recpt_editor_new ();
930 priv->cc_field = modest_recpt_editor_new ();
931 priv->bcc_field = modest_recpt_editor_new ();
932 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
933 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
934 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
935 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
936 priv->priority_icon = gtk_image_new ();
937 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
938 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
939 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
940 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
941 hildon_entry_set_placeholder ((HildonEntry *) priv->subject_field, _("mail_va_no_subject"));
942 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
943 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
944 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
945 priv->attachments_view = modest_attachments_view_new (NULL);
946 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
947 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
949 priv->header_box = gtk_vbox_new (FALSE, 0);
951 to_caption = _create_addressbook_box
952 (title_size_group, value_size_group,
953 _("mail_va_to"), priv->to_field);
954 priv->cc_caption = _create_addressbook_box
955 (title_size_group, value_size_group,
956 _("mail_va_cc"), priv->cc_field);
957 priv->bcc_caption = _create_addressbook_box
958 (title_size_group, value_size_group,
959 _("mail_va_hotfix1"), priv->bcc_field);
960 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
961 _("mail_va_subject"), FALSE, priv->subject_box);
962 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (NULL, NULL,
963 _("mail_va_attachment"),
965 priv->attachments_view,
966 HILDON_SIZE_AUTO_WIDTH |
967 HILDON_SIZE_AUTO_HEIGHT);
968 attachments_label = modest_maemo_utils_captioned_get_label_widget (priv->attachments_caption);
969 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
972 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
973 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
974 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
975 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
977 priv->bottom_send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
978 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
979 gtk_container_add (GTK_CONTAINER (priv->bottom_send_button), send_icon);
980 gtk_widget_set_size_request (GTK_WIDGET (priv->bottom_send_button), 148, -1);
982 priv->bottom_send_button_container = gtk_hbox_new (FALSE, 0);
983 gtk_widget_show (priv->bottom_send_button_container);
984 gtk_box_pack_end (GTK_BOX (priv->bottom_send_button_container), priv->bottom_send_button, FALSE, FALSE, 0);
985 gtk_widget_show (priv->bottom_send_button_container);
987 g_object_unref (title_size_group);
988 g_object_unref (value_size_group);
990 priv->brand_icon = gtk_image_new ();
991 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
992 priv->brand_label = gtk_label_new (NULL);
993 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
994 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
995 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
996 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
998 from_send_hbox = gtk_hbox_new (FALSE, 0);
999 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->from_field, TRUE, TRUE, 0);
1000 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
1002 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
1003 gtk_widget_show (branding_box);
1004 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
1005 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
1007 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
1008 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1009 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
1010 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
1013 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
1014 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
1015 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
1016 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
1017 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
1018 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
1019 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
1020 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1022 init_wp_text_view_style ();
1024 priv->msg_body = modest_wp_text_view_new ();
1027 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1028 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1029 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1030 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1031 #if (GTK_MINOR_VERSION >= 10)
1032 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1033 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1035 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1036 deserialize_type, TRUE);
1038 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1040 priv->find_toolbar = hildon_find_toolbar_new (NULL);
1041 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
1043 priv->pannable = hildon_pannable_area_new ();
1045 g_object_set (G_OBJECT (priv->pannable), "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
1047 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1048 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1049 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), MODEST_MARGIN_HALF, 0,
1050 MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1052 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1053 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1054 gtk_box_pack_start (GTK_BOX (main_vbox), priv->bottom_send_button_container, FALSE, FALSE, 0);
1055 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1057 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
1058 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
1060 window_box = gtk_vbox_new (FALSE, 0);
1061 gtk_container_add (GTK_CONTAINER(obj), window_box);
1063 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
1065 /* Set window icon */
1066 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1068 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1069 g_object_unref (window_icon);
1074 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1076 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1078 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1079 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1080 priv->clipboard_change_handler_id))
1081 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1082 priv->clipboard_change_handler_id);
1083 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1084 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1085 priv->default_clipboard_change_handler_id))
1086 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1087 priv->default_clipboard_change_handler_id);
1089 if (priv->account_removed_handler_id &&
1090 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1091 priv->account_removed_handler_id))
1092 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1093 priv->account_removed_handler_id);
1097 modest_msg_edit_window_finalize (GObject *obj)
1099 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1101 g_object_unref (priv->custom_header_pairs);
1103 if (priv->max_chars_banner) {
1104 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1105 priv->max_chars_banner = FALSE;
1108 /* Sanity check: shouldn't be needed, the window mgr should
1109 call this function before */
1110 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1112 if (priv->font_dialog != NULL) {
1113 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1116 if (priv->clipboard_text != NULL) {
1117 g_free (priv->clipboard_text);
1118 priv->clipboard_text = NULL;
1121 if (priv->draft_msg != NULL) {
1122 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1123 if (TNY_IS_HEADER (header)) {
1124 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1125 modest_window_mgr_unregister_header (mgr, header);
1127 g_object_unref (priv->draft_msg);
1128 priv->draft_msg = NULL;
1130 if (priv->outbox_msg != NULL) {
1131 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1132 if (TNY_IS_HEADER (header)) {
1133 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1134 modest_window_mgr_unregister_header (mgr, header);
1136 g_object_unref (priv->outbox_msg);
1137 priv->outbox_msg = NULL;
1139 if (priv->correct_scroll_idle > 0) {
1140 g_source_remove (priv->correct_scroll_idle);
1141 priv->correct_scroll_idle = 0;
1143 if (priv->scroll_drag_timeout_id > 0) {
1144 g_source_remove (priv->scroll_drag_timeout_id);
1145 priv->scroll_drag_timeout_id = 0;
1147 if (priv->clipboard_owner_idle > 0) {
1148 g_source_remove (priv->clipboard_owner_idle);
1149 priv->clipboard_owner_idle = 0;
1151 if (priv->original_account_name)
1152 g_free (priv->original_account_name);
1153 if (priv->original_mailbox)
1154 g_free (priv->original_mailbox);
1155 g_free (priv->msg_uid);
1156 g_free (priv->last_search);
1157 g_free (priv->references);
1158 g_free (priv->in_reply_to);
1159 g_object_unref (priv->attachments);
1160 g_object_unref (priv->images);
1162 /* This had to stay alive for as long as the picker that used it: */
1163 modest_pair_list_free (priv->from_field_protos);
1165 G_OBJECT_CLASS(parent_class)->finalize (obj);
1169 pixbuf_size_prepared (GdkPixbufLoader *loader,
1172 ModestMsgEditWindow *self)
1174 gint new_height, new_width;
1177 new_height = height;
1181 if (width > IMAGE_MAX_WIDTH) {
1182 new_height = height * IMAGE_MAX_WIDTH / width;
1183 new_width = IMAGE_MAX_WIDTH;
1186 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1190 pixbuf_from_stream (TnyStream *stream,
1191 const gchar *mime_type,
1192 guint64 *stream_size,
1193 ModestMsgEditWindow *self)
1195 GdkPixbufLoader *loader;
1198 GError *error = NULL;
1202 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1204 if (loader == NULL) {
1209 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1211 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1213 tny_stream_reset (TNY_STREAM (stream));
1214 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1215 unsigned char read_buffer[128];
1217 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1219 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1222 /* Allow some UI responsiveness */
1223 while (gtk_events_pending ())
1224 gtk_main_iteration ();
1226 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1228 gdk_pixbuf_loader_close (loader, &error);
1231 g_error_free (error);
1232 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1234 g_object_ref (pixbuf);
1235 g_object_unref (loader);
1240 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1241 GdkPixbuf *new_pixbuf;
1243 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1244 gdk_pixbuf_get_width (pixbuf);
1245 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1246 g_object_unref (pixbuf);
1247 pixbuf = new_pixbuf;
1251 *stream_size = size;
1257 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1259 ModestMsgEditWindowPrivate *priv;
1262 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1264 g_object_ref (self);
1265 for (iter = tny_list_create_iterator (attachments);
1266 !tny_iterator_is_done (iter);
1267 tny_iterator_next (iter)) {
1268 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1269 const gchar *cid = tny_mime_part_get_content_id (part);
1270 const gchar *mime_type = tny_mime_part_get_content_type (part);
1271 if ((cid != NULL)&&(mime_type != NULL)) {
1272 guint64 stream_size;
1273 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1274 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1277 g_object_unref (stream);
1279 if (pixbuf != NULL) {
1280 priv->images_count ++;
1281 priv->images_size += stream_size;
1282 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1283 g_object_unref (pixbuf);
1286 g_object_unref (part);
1288 g_object_unref (iter);
1289 g_object_unref (self);
1293 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1295 TnyMimePart *parent = NULL;
1296 const gchar *content_type = NULL;
1297 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1299 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1301 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1302 parent = g_object_ref (msg);
1303 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1304 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1307 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1308 iter = tny_list_create_iterator (parts);
1309 while (!tny_iterator_is_done (iter)) {
1311 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1312 content_type = tny_mime_part_get_content_type (part);
1313 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1317 g_object_unref (part);
1319 tny_iterator_next (iter);
1321 g_object_unref (iter);
1322 g_object_unref (parts);
1325 if (parent != NULL) {
1326 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1329 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1330 iter = tny_list_create_iterator (parts);
1331 while (!tny_iterator_is_done (iter)) {
1333 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1334 content_type = tny_mime_part_get_content_type (part);
1335 if (content_type && g_str_has_prefix (content_type, "image/")) {
1336 tny_list_prepend (priv->images, (GObject *) part);
1338 g_object_unref (part);
1339 tny_iterator_next (iter);
1341 g_object_unref (iter);
1342 g_object_unref (parts);
1343 g_object_unref (parent);
1348 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1351 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1353 for (iter = tny_list_create_iterator (attachments) ;
1354 !tny_iterator_is_done (iter);
1355 tny_iterator_next (iter)) {
1356 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1357 const gchar *cid = tny_mime_part_get_content_id (part);
1359 char *invalid = NULL;
1360 gint int_cid = strtol (cid, &invalid, 10);
1361 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1362 priv->next_cid = int_cid + 1;
1365 g_object_unref (part);
1367 g_object_unref (iter);
1371 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1374 gchar *to, *cc, *bcc, *subject;
1376 ModestMsgEditWindowPrivate *priv;
1377 ModestWindowPrivate *parent_priv;
1379 TnyHeaderFlags priority_flags;
1380 TnyFolder *msg_folder;
1381 gboolean is_html = FALSE;
1382 gboolean field_view_set;
1383 TnyList *orig_header_pairs;
1385 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1386 g_return_if_fail (TNY_IS_MSG (msg));
1388 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1389 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1391 header = tny_msg_get_header (msg);
1392 to = tny_header_dup_to (header);
1393 cc = tny_header_dup_cc (header);
1394 bcc = tny_header_dup_bcc (header);
1395 subject = tny_header_dup_subject (header);
1397 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1398 priority_flags = tny_header_get_priority (header);
1401 gchar *quoted_names = modest_text_utils_quote_names (to);
1402 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1403 g_free (quoted_names);
1406 field_view_set = TRUE;
1408 gchar *quoted_names = modest_text_utils_quote_names (cc);
1409 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1410 g_free (quoted_names);
1411 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1412 gtk_widget_show (priv->cc_caption);
1413 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1414 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1415 gtk_widget_hide (priv->cc_caption);
1416 field_view_set = FALSE;
1418 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1420 field_view_set = TRUE;
1422 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1423 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1424 g_free (quoted_names);
1425 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1426 gtk_widget_show (priv->bcc_caption);
1427 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1428 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1429 gtk_widget_hide (priv->bcc_caption);
1430 field_view_set = FALSE;
1432 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1436 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1437 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1440 update_window_title (self);
1442 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1443 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1445 if ((body == NULL)||(body[0] == '\0')) {
1447 body = modest_text_utils_convert_to_html ("");
1450 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1451 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1454 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1457 /* Add attachments to the view */
1458 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1459 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1460 if (tny_list_get_length (priv->attachments) == 0) {
1461 gtk_widget_hide (priv->attachments_caption);
1463 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1464 gtk_widget_show_all (priv->attachments_caption);
1466 get_related_images (self, msg);
1467 update_next_cid (self, priv->attachments);
1468 update_next_cid (self, priv->images);
1469 replace_with_images (self, priv->images);
1471 if (preserve_is_rich && !is_html) {
1472 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1473 /* Get the default format required from configuration */
1474 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1475 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1478 /* Set the default focus depending on having already a To: field or not */
1479 if ((!to)||(*to == '\0')) {
1480 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1482 gtk_widget_grab_focus (priv->msg_body);
1485 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1487 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1488 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1490 modest_msg_edit_window_set_modified (self, FALSE);
1492 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1493 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1494 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1495 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1497 if (priv->msg_uid) {
1498 g_free (priv->msg_uid);
1499 priv->msg_uid = NULL;
1502 /* we should set a reference to the incoming message if it is a draft */
1503 msg_folder = tny_msg_get_folder (msg);
1505 if (modest_tny_folder_is_local_folder (msg_folder)) {
1506 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1507 if (type == TNY_FOLDER_TYPE_INVALID)
1508 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1510 if (type == TNY_FOLDER_TYPE_DRAFTS)
1511 priv->draft_msg = g_object_ref(msg);
1512 if (type == TNY_FOLDER_TYPE_OUTBOX)
1513 priv->outbox_msg = g_object_ref(msg);
1514 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1516 g_object_unref (msg_folder);
1519 orig_header_pairs = TNY_LIST (tny_simple_list_new ());
1520 tny_mime_part_get_header_pairs (TNY_MIME_PART (msg), orig_header_pairs);
1521 modest_msg_edit_window_set_custom_header_pairs (self, orig_header_pairs);
1522 g_object_unref (orig_header_pairs);
1531 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1533 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1534 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1535 GtkWidget *placeholder;
1536 GtkWidget *tool_item;
1541 GtkWidget *sizes_menu;
1542 GtkWidget *fonts_menu;
1548 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1549 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1550 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1551 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1553 /* Font color placeholder */
1554 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1555 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1558 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1559 priv->font_color_button = modest_color_button_new ();
1560 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1561 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1562 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1563 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1564 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1565 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1566 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1567 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1569 G_CALLBACK (modest_msg_edit_window_color_button_change),
1572 /* Font size and face placeholder */
1573 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1574 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1576 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1577 priv->size_tool_button_label = gtk_label_new (NULL);
1578 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1579 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1580 size_text, "</span>", NULL);
1581 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1582 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1584 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1585 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1586 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1587 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1588 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1589 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1590 gtk_widget_set_sensitive (arrow, FALSE);
1591 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1592 sizes_menu = gtk_menu_new ();
1593 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1594 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1597 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1598 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1600 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1604 if (wp_font_size[size_index] == 12)
1605 priv->current_size_index = size_index;
1609 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1610 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1611 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1612 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1613 priv->font_size_toolitem = tool_item;
1616 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1617 priv->font_tool_button_label = gtk_label_new (NULL);
1618 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1619 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1620 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1622 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1623 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1624 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1625 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1626 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1627 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1628 gtk_widget_set_sensitive (arrow, FALSE);
1629 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1630 fonts_menu = gtk_menu_new ();
1631 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1632 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1635 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1637 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1638 0, wp_get_font_name (font_index),
1641 if (font_index == DEFAULT_FONT)
1642 priv->current_face_index = font_index;
1644 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1645 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1646 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1647 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1648 priv->font_face_toolitem = tool_item;
1650 /* Set expand and homogeneous for remaining items */
1651 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1652 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1653 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1654 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1655 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1656 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1657 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsInsertImage");
1658 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1659 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1661 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1662 will not show the tool items added to the placeholders) */
1663 gtk_widget_show_all (parent_priv->toolbar);
1665 /* Set the no show all *after* showing all items. We do not
1666 want the toolbar to be shown with a show all because it
1667 could go against the gconf setting regarding showing or not
1668 the toolbar of the editor window */
1669 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1675 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1678 ModestWindowPrivate *parent_priv;
1679 ModestMsgEditWindowPrivate *priv;
1680 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1681 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1682 ModestWindowMgr *mgr = NULL;
1684 g_return_val_if_fail (msg, NULL);
1685 g_return_val_if_fail (account_name, NULL);
1687 mgr = modest_runtime_get_window_mgr ();
1689 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1691 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1692 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1694 /* Menubar. Update the state of some toggles */
1695 priv->from_field_protos = get_transports ();
1696 priv->original_mailbox = NULL;
1697 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1698 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1699 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1700 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1701 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) mailbox);
1702 priv->original_mailbox = g_strdup (mailbox);
1703 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1704 /* We set the first mailbox as the active mailbox */
1705 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1706 if (priv->original_mailbox != NULL)
1707 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1708 (gpointer) priv->original_mailbox);
1710 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1711 (gpointer) account_name);
1713 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1715 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1716 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1717 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1719 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1720 hildon_touch_selector_get_current_text
1721 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1722 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1723 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1726 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1728 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1730 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1731 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1733 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1735 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1736 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1737 /* Add common dimming rules */
1738 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1739 modest_msg_edit_window_toolbar_dimming_entries,
1740 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1741 MODEST_WINDOW (obj));
1742 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1743 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1744 MODEST_WINDOW (obj));
1745 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1746 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1747 MODEST_WINDOW (obj));
1748 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1749 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1750 MODEST_WINDOW (obj));
1751 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1752 G_CALLBACK (modest_ui_dimming_rules_on_send),
1753 MODEST_WINDOW (obj));
1754 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->bottom_send_button,
1755 G_CALLBACK (modest_ui_dimming_rules_on_send),
1756 MODEST_WINDOW (obj));
1757 /* Insert dimming rules group for this window */
1758 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1759 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1761 /* Setup app menu */
1762 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1764 /* Checks the dimming rules */
1765 g_object_unref (toolbar_rules_group);
1766 g_object_unref (clipboard_rules_group);
1767 gtk_widget_hide (priv->priority_icon);
1768 gtk_widget_queue_resize (priv->subject_box);
1769 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1771 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1773 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1774 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1775 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1776 priv->update_caption_visibility = TRUE;
1778 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1780 /* Track account-removed signal, this window should be closed
1781 in the case we're creating a mail associated to the account
1783 priv->account_removed_handler_id =
1784 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1786 G_CALLBACK(on_account_removed),
1789 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1791 return (ModestWindow*) obj;
1795 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1797 GString **string_buffer = (GString **) user_data;
1799 *string_buffer = g_string_append (*string_buffer, buffer);
1805 * @result: A new string which should be freed with g_free().
1808 get_formatted_data (ModestMsgEditWindow *edit_window)
1810 ModestMsgEditWindowPrivate *priv;
1811 GString *string_buffer = g_string_new ("");
1813 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1815 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1817 modest_text_utils_hyperlinkify (string_buffer);
1819 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1821 return g_string_free (string_buffer, FALSE);
1826 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1829 const gchar *account_name;
1830 ModestMsgEditWindowPrivate *priv;
1831 TnyIterator *att_iter;
1832 const gchar *picker_active_id;
1834 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1836 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1838 picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1839 g_return_val_if_fail (picker_active_id, NULL);
1840 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1842 /* don't free these (except from) */
1843 data = g_slice_new0 (MsgData);
1844 data->from = g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1845 data->account_name = g_strdup (account_name);
1846 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1847 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1848 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1849 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1850 data->references = g_strdup (priv->references);
1851 data->in_reply_to = g_strdup (priv->in_reply_to);
1852 if (priv->draft_msg) {
1853 data->draft_msg = g_object_ref (priv->draft_msg);
1854 } else if (priv->outbox_msg) {
1855 data->draft_msg = g_object_ref (priv->outbox_msg);
1857 data->draft_msg = NULL;
1860 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1862 gtk_text_buffer_get_bounds (buf, &b, &e);
1863 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1865 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1866 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1868 data->html_body = NULL;
1870 /* deep-copy the data */
1871 att_iter = tny_list_create_iterator (priv->attachments);
1872 data->attachments = NULL;
1873 while (!tny_iterator_is_done (att_iter)) {
1874 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1875 if (!(TNY_IS_MIME_PART(part))) {
1876 g_warning ("strange data in attachment list");
1877 g_object_unref (part);
1878 tny_iterator_next (att_iter);
1881 data->attachments = g_list_append (data->attachments,
1883 tny_iterator_next (att_iter);
1885 g_object_unref (att_iter);
1887 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1888 att_iter = tny_list_create_iterator (priv->images);
1889 data->images = NULL;
1890 while (!tny_iterator_is_done (att_iter)) {
1891 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1893 if (!(TNY_IS_MIME_PART(part))) {
1894 g_warning ("strange data in attachment list");
1895 g_object_unref (part);
1896 tny_iterator_next (att_iter);
1899 cid = tny_mime_part_get_content_id (part);
1901 gchar *image_tag_id;
1902 GtkTextTag *image_tag;
1904 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1905 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1906 g_free (image_tag_id);
1908 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1910 ((gtk_text_iter_has_tag (&iter, image_tag))||
1911 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1912 data->images = g_list_append (data->images,
1913 g_object_ref (part));
1915 g_object_unref (part);
1916 tny_iterator_next (att_iter);
1918 g_object_unref (att_iter);
1920 data->priority_flags = priv->priority_flags;
1921 data->custom_header_pairs = tny_list_copy (priv->custom_header_pairs);
1928 unref_gobject (GObject *obj, gpointer data)
1930 if (!G_IS_OBJECT(obj))
1932 g_object_unref (obj);
1936 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1939 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1947 g_free (data->from);
1948 g_free (data->subject);
1949 g_free (data->plain_body);
1950 g_free (data->html_body);
1951 g_free (data->account_name);
1952 g_free (data->references);
1953 g_free (data->in_reply_to);
1955 g_object_unref (data->custom_header_pairs);
1957 if (data->draft_msg != NULL) {
1958 g_object_unref (data->draft_msg);
1959 data->draft_msg = NULL;
1962 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1963 g_list_free (data->attachments);
1964 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1965 g_list_free (data->images);
1967 g_slice_free (MsgData, data);
1971 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1973 guint64 *parts_size)
1975 ModestMsgEditWindowPrivate *priv;
1977 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1979 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1981 /* TODO: add images */
1982 *parts_size += priv->images_size;
1983 *parts_count += priv->images_count;
1988 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1991 ModestMsgEditWindowPrivate *priv = NULL;
1992 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1994 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1996 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1998 return MODEST_MSG_EDIT_FORMAT_HTML;
2000 return MODEST_MSG_EDIT_FORMAT_TEXT;
2004 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
2005 ModestMsgEditFormat format)
2007 ModestMsgEditWindowPrivate *priv;
2008 ModestWindowPrivate *parent_priv;
2010 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2011 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2012 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2015 case MODEST_MSG_EDIT_FORMAT_HTML:
2016 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2017 update_signature (self, priv->last_from_account, priv->last_from_account);
2018 if (parent_priv->toolbar)
2019 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
2020 MODEST_MSG_EDIT_WINDOW (self));
2022 case MODEST_MSG_EDIT_FORMAT_TEXT:
2023 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2024 if (parent_priv->toolbar)
2025 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
2026 MODEST_MSG_EDIT_WINDOW (self));
2029 g_return_if_reached ();
2033 ModestMsgEditFormatState *
2034 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2036 ModestMsgEditFormatState *format_state = NULL;
2037 ModestMsgEditWindowPrivate *priv;
2038 WPTextBufferFormat *buffer_format;
2040 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2042 buffer_format = g_new0 (WPTextBufferFormat, 1);
2043 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2045 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2047 format_state = g_new0 (ModestMsgEditFormatState, 1);
2048 format_state->bold = buffer_format->bold&0x1;
2049 format_state->italics = buffer_format->italic&0x1;
2050 format_state->bullet = buffer_format->bullet&0x1;
2051 format_state->color = buffer_format->color;
2052 format_state->font_size = buffer_format->font_size;
2053 format_state->font_family = wp_get_font_name (buffer_format->font);
2054 format_state->justification = buffer_format->justification;
2055 g_free (buffer_format);
2057 return format_state;
2062 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2063 const ModestMsgEditFormatState *format_state)
2065 ModestMsgEditWindowPrivate *priv;
2066 WPTextBufferFormat *buffer_format;
2067 WPTextBufferFormat *current_format;
2069 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2070 g_return_if_fail (format_state != NULL);
2072 buffer_format = g_new0 (WPTextBufferFormat, 1);
2073 current_format = g_new0 (WPTextBufferFormat, 1);
2075 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2076 gtk_widget_grab_focus (priv->msg_body);
2077 buffer_format->bold = (format_state->bold != FALSE);
2078 buffer_format->italic = (format_state->italics != FALSE);
2079 buffer_format->color = format_state->color;
2080 buffer_format->font_size = format_state->font_size;
2081 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2082 buffer_format->justification = format_state->justification;
2083 buffer_format->bullet = format_state->bullet;
2085 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2087 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2088 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2089 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2090 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2091 buffer_format->cs.font = (buffer_format->font != current_format->font);
2092 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2093 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2095 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2096 if (buffer_format->cs.bold) {
2097 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2098 GINT_TO_POINTER (buffer_format->bold&0x1));
2100 if (buffer_format->cs.italic) {
2101 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2102 GINT_TO_POINTER (buffer_format->italic&0x1));
2104 if (buffer_format->cs.color) {
2105 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2106 GINT_TO_POINTER (&(buffer_format->color)));
2108 if (buffer_format->cs.font_size) {
2109 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2110 GINT_TO_POINTER (buffer_format->font_size));
2112 if (buffer_format->cs.justification) {
2113 switch (buffer_format->justification) {
2114 case GTK_JUSTIFY_LEFT:
2115 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2116 GINT_TO_POINTER(TRUE));
2118 case GTK_JUSTIFY_CENTER:
2119 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2120 GINT_TO_POINTER(TRUE));
2122 case GTK_JUSTIFY_RIGHT:
2123 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2124 GINT_TO_POINTER(TRUE));
2131 if (buffer_format->cs.font) {
2132 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2133 GINT_TO_POINTER (buffer_format->font));
2135 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2136 if (buffer_format->cs.bullet) {
2137 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2138 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2140 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2142 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2144 g_free (buffer_format);
2145 g_free (current_format);
2147 /* Check dimming rules */
2148 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2149 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2153 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2155 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2157 ModestWindowPrivate *parent_priv;
2158 ModestMsgEditWindowPrivate *priv;
2160 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2161 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2163 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2164 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2165 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2166 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2168 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2169 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2170 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2173 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2175 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2176 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2178 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2179 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2181 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2182 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2185 switch (buffer_format->justification)
2187 case GTK_JUSTIFY_LEFT:
2188 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2190 case GTK_JUSTIFY_CENTER:
2191 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2193 case GTK_JUSTIFY_RIGHT:
2194 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2201 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2203 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2204 G_CALLBACK (modest_msg_edit_window_color_button_change),
2206 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2207 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2208 G_CALLBACK (modest_msg_edit_window_color_button_change),
2211 if (priv->current_size_index != buffer_format->font_size) {
2215 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2216 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2220 priv->current_size_index = buffer_format->font_size;
2222 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2223 markup = g_strconcat ("<span font_family='Sans'>",
2224 size_text, "</span>", NULL);
2226 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2230 gtk_tree_path_free (path);
2233 if (priv->current_face_index != buffer_format->font) {
2237 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2238 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2242 priv->current_face_index = buffer_format->font;
2243 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2244 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2245 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2252 g_free (buffer_format);
2258 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2260 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2261 ModestMsgEditWindowPrivate *priv;
2262 GtkWidget *dialog = NULL;
2264 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2265 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2267 dialog = hildon_color_chooser_new ();
2268 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2269 g_free (buffer_format);
2271 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2273 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2274 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2277 gtk_widget_destroy (dialog);
2282 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2284 ModestMsgEditWindowPrivate *priv;
2285 GtkWidget *dialog = NULL;
2286 GdkColor *old_color = NULL;
2288 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2289 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2291 dialog = hildon_color_chooser_new ();
2292 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2294 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2296 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2297 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2299 gtk_widget_destroy (dialog);
2304 create_stream_for_uri (const gchar* uri)
2309 TnyStream *result = NULL;
2311 GnomeVFSHandle *handle = NULL;
2312 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2313 if (test == GNOME_VFS_OK) {
2314 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2315 /* Streams over OBEX (Bluetooth) are not seekable but
2316 * we expect them to be (we might need to read them
2317 * several times). So if this is a Bluetooth URI just
2318 * read the whole file into memory (this is not a fast
2319 * protocol so we can assume that these files are not
2320 * going to be very big) */
2321 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2322 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2323 TnyStream *memstream = tny_camel_mem_stream_new ();
2324 tny_stream_write_to_stream (vfssstream, memstream);
2325 g_object_unref (vfssstream);
2328 result = vfssstream;
2336 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2339 ModestMsgEditWindowPrivate *priv;
2340 GtkWidget *dialog = NULL;
2342 GSList *uris = NULL;
2343 GSList *uri_node = NULL;
2345 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2347 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2348 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2349 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2351 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2353 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2354 GTK_WINDOW (dialog), GTK_WINDOW (window));
2356 response = gtk_dialog_run (GTK_DIALOG (dialog));
2358 case GTK_RESPONSE_OK:
2360 gchar *current_folder;
2361 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2362 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2363 if (current_folder && current_folder != '\0') {
2365 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2366 current_folder, &err);
2368 g_debug ("Error storing latest used folder: %s", err->message);
2372 g_free (current_folder);
2378 gtk_widget_destroy (dialog);
2380 g_object_ref (window);
2381 /* The operation could take some time so allow the dialog to be closed */
2382 while (gtk_events_pending ())
2383 gtk_main_iteration ();
2385 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2387 GnomeVFSHandle *handle = NULL;
2388 GnomeVFSResult result;
2389 GtkTextIter position;
2390 GtkTextMark *insert_mark;
2392 uri = (const gchar *) uri_node->data;
2393 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2394 if (result == GNOME_VFS_OK) {
2396 GnomeVFSFileInfo *info;
2397 gchar *filename, *basename, *escaped_filename;
2398 TnyMimePart *mime_part;
2400 const gchar *mime_type = NULL;
2401 GnomeVFSURI *vfs_uri;
2402 guint64 stream_size;
2404 gnome_vfs_close (handle);
2405 vfs_uri = gnome_vfs_uri_new (uri);
2407 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2408 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2409 g_free (escaped_filename);
2410 gnome_vfs_uri_unref (vfs_uri);
2411 info = gnome_vfs_file_info_new ();
2413 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2414 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2416 mime_type = gnome_vfs_file_info_get_mime_type (info);
2418 mime_part = tny_platform_factory_new_mime_part
2419 (modest_runtime_get_platform_factory ());
2421 TnyStream *stream = create_stream_for_uri (uri);
2423 if (stream == NULL) {
2425 modest_platform_information_banner (NULL, NULL,
2426 _FM("sfil_ib_opening_not_allowed"));
2428 g_object_unref (mime_part);
2429 gnome_vfs_file_info_unref (info);
2433 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2435 content_id = g_strdup_printf ("%d", priv->next_cid);
2436 tny_mime_part_set_content_id (mime_part, content_id);
2437 g_free (content_id);
2440 basename = g_path_get_basename (filename);
2441 tny_mime_part_set_filename (mime_part, basename);
2444 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2446 if (pixbuf != NULL) {
2447 priv->images_size += stream_size;
2448 priv->images_count ++;
2449 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2450 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2451 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2452 tny_mime_part_get_content_id (mime_part), pixbuf);
2453 g_object_unref (pixbuf);
2455 tny_list_prepend (priv->images, (GObject *) mime_part);
2456 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2458 modest_platform_information_banner (NULL, NULL,
2459 _("mail_ib_file_operation_failed"));
2463 g_object_unref (mime_part);
2464 gnome_vfs_file_info_unref (info);
2468 g_object_unref (window);
2472 on_attach_file_response (GtkDialog *dialog,
2476 GSList *uris = NULL;
2478 GnomeVFSFileSize total_size, allowed_size;
2479 ModestMsgEditWindow *window;
2480 ModestMsgEditWindowPrivate *priv;
2485 case GTK_RESPONSE_OK:
2487 gchar *current_folder;
2489 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2490 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2491 if (current_folder && current_folder != '\0') {
2493 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2494 current_folder, &err);
2496 g_debug ("Error storing latest used folder: %s", err->message);
2500 g_free (current_folder);
2507 window = MODEST_MSG_EDIT_WINDOW (user_data);
2508 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2510 /* allowed size is the maximum size - what's already there */
2511 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2512 &att_num, &att_size);
2513 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2516 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2518 const gchar *uri = (const gchar *) uri_node->data;
2521 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2523 if (total_size > allowed_size) {
2524 g_debug ("%s: total size: %u",
2525 __FUNCTION__, (unsigned int)total_size);
2528 allowed_size -= total_size;
2530 g_slist_foreach (uris, (GFunc) g_free, NULL);
2531 g_slist_free (uris);
2533 gtk_widget_destroy (GTK_WIDGET (dialog));
2537 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2539 GtkWidget *dialog = NULL;
2540 ModestMsgEditWindowPrivate *priv;
2543 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2545 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2547 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2550 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2551 GTK_FILE_CHOOSER_ACTION_OPEN);
2552 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2553 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2554 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2555 if (conf_folder && conf_folder[0] != '\0') {
2556 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2559 /* Set the default folder to documents folder */
2560 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2563 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2564 ".documents", NULL);
2566 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2567 g_free (docs_folder);
2569 g_free (conf_folder);
2570 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2571 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2572 GTK_WINDOW (dialog), GTK_WINDOW (window));
2574 /* Connect to response & show */
2575 g_signal_connect (dialog, "response",
2576 G_CALLBACK (on_attach_file_response), window);
2577 gtk_widget_show (dialog);
2582 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2584 GnomeVFSFileSize allowed_size)
2587 GnomeVFSHandle *handle = NULL;
2588 ModestMsgEditWindowPrivate *priv;
2589 GnomeVFSResult result;
2590 GnomeVFSFileSize size = 0;
2591 g_return_val_if_fail (window, 0);
2592 g_return_val_if_fail (uri, 0);
2594 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2596 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2597 if (result == GNOME_VFS_OK) {
2598 TnyMimePart *mime_part;
2600 const gchar *mime_type = NULL;
2602 gchar *escaped_filename;
2605 GnomeVFSFileInfo *info;
2606 GnomeVFSURI *vfs_uri;
2608 gnome_vfs_close (handle);
2609 vfs_uri = gnome_vfs_uri_new (uri);
2612 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2613 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2614 g_free (escaped_filename);
2615 gnome_vfs_uri_unref (vfs_uri);
2617 info = gnome_vfs_file_info_new ();
2619 if (gnome_vfs_get_file_info (uri,
2621 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2623 mime_type = gnome_vfs_file_info_get_mime_type (info);
2624 mime_part = tny_platform_factory_new_mime_part
2625 (modest_runtime_get_platform_factory ());
2627 /* try to get the attachment's size; this may fail for weird
2628 * file systems, like obex, upnp... */
2629 if (allowed_size != 0 &&
2630 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2632 if (size > allowed_size) {
2633 modest_platform_information_banner (NULL, NULL,
2634 _("mail_ib_error_attachment_size"));
2639 g_debug ("%s: could not get attachment size", __FUNCTION__);
2641 stream = create_stream_for_uri (uri);
2643 if (stream == NULL) {
2645 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2647 g_object_unref (mime_part);
2649 gnome_vfs_file_info_unref (info);
2653 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2654 g_object_unref (stream);
2656 content_id = g_strdup_printf ("%d", priv->next_cid);
2657 tny_mime_part_set_content_id (mime_part, content_id);
2658 g_free (content_id);
2661 basename = g_path_get_basename (filename);
2662 tny_mime_part_set_filename (mime_part, basename);
2665 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2666 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2668 info->size == 0, info->size);
2669 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2670 gtk_widget_show_all (priv->attachments_caption);
2671 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2673 g_object_unref (mime_part);
2674 gnome_vfs_file_info_unref (info);
2681 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2684 ModestMsgEditWindowPrivate *priv;
2687 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2688 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2690 if (att_list == NULL) {
2691 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2692 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2693 g_object_unref (att_list);
2697 g_object_ref (att_list);
2700 if (tny_list_get_length (att_list) == 0) {
2701 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2703 gboolean dialog_response;
2704 gchar *message = NULL;
2705 gchar *filename = NULL;
2707 if (tny_list_get_length (att_list) == 1) {
2709 iter = tny_list_create_iterator (att_list);
2710 part = (TnyMimePart *) tny_iterator_get_current (iter);
2711 g_object_unref (iter);
2712 if (TNY_IS_MSG (part)) {
2713 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2715 filename = tny_header_dup_subject (header);
2716 g_object_unref (header);
2718 if (filename == NULL) {
2719 filename = g_strdup (_("mail_va_no_subject"));
2722 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2724 g_object_unref (part);
2726 filename = g_strdup ("");
2728 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2729 "emev_nc_delete_attachments",
2730 tny_list_get_length (att_list)), filename);
2733 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2737 if (dialog_response != GTK_RESPONSE_OK) {
2738 g_object_unref (att_list);
2742 for (iter = tny_list_create_iterator (att_list);
2743 !tny_iterator_is_done (iter);
2744 tny_iterator_next (iter)) {
2745 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2746 const gchar *att_id;
2747 tny_list_remove (priv->attachments, (GObject *) mime_part);
2749 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2751 if (tny_list_get_length (priv->attachments) == 0)
2752 gtk_widget_hide (priv->attachments_caption);
2753 att_id = tny_mime_part_get_content_id (mime_part);
2755 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2757 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2758 g_object_unref (mime_part);
2760 g_object_unref (iter);
2763 g_object_unref (att_list);
2765 /* if the last attachment has been removed, focus the Subject: field */
2766 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2767 gtk_widget_grab_focus (priv->subject_field);
2771 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2774 ModestMsgEditWindowPrivate *priv;
2777 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2779 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2781 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2783 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2787 font_size_clicked (GtkToolButton *button,
2788 ModestMsgEditWindow *window)
2790 ModestMsgEditWindowPrivate *priv;
2791 GtkWidget *selector, *dialog;
2793 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2795 selector = hildon_touch_selector_new ();
2796 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2797 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2799 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2800 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2801 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2803 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2807 WPTextBufferFormat format;
2809 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2811 memset (&format, 0, sizeof (format));
2812 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2814 format.cs.font_size = TRUE;
2815 format.cs.text_position = TRUE;
2816 format.cs.font = TRUE;
2817 format.font_size = new_index;
2818 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2820 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2821 GINT_TO_POINTER (new_index)))
2822 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2824 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2825 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2826 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2827 size_text, "</span>", NULL);
2829 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2833 gtk_widget_destroy (dialog);
2835 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2840 font_face_clicked (GtkToolButton *button,
2841 ModestMsgEditWindow *window)
2843 ModestMsgEditWindowPrivate *priv;
2844 GtkWidget *selector, *dialog;
2845 GtkCellRenderer *renderer;
2847 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2849 selector = hildon_touch_selector_new ();
2850 renderer = gtk_cell_renderer_text_new ();
2851 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2852 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2853 renderer, "family", 0, "text", 0, NULL);
2854 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2856 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2857 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2858 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2860 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2861 gint new_font_index;
2865 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2866 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2867 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2871 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2873 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2874 GINT_TO_POINTER(new_font_index)))
2875 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2877 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2878 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2880 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2884 gtk_tree_path_free (path);
2887 gtk_widget_destroy (dialog);
2889 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2894 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2897 ModestMsgEditWindowPrivate *priv = NULL;
2898 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2900 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2901 if (!priv->update_caption_visibility)
2904 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2906 gtk_widget_show (priv->cc_caption);
2908 gtk_widget_hide (priv->cc_caption);
2910 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2914 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2917 ModestMsgEditWindowPrivate *priv = NULL;
2918 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2920 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2921 if (!priv->update_caption_visibility)
2924 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2926 gtk_widget_show (priv->bcc_caption);
2928 gtk_widget_hide (priv->bcc_caption);
2930 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2934 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2935 ModestRecptEditor *editor)
2937 ModestMsgEditWindowPrivate *priv;
2939 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2940 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2942 /* we check for low-mem; in that case, show a warning, and don't allow
2943 * for the addressbook
2945 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2948 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2950 if (editor == NULL) {
2951 GtkWidget *view_focus, *parent;
2952 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2954 /* This code should be kept in sync with ModestRecptEditor. The
2955 textview inside the recpt editor is the one that really gets the
2956 focus. As it's inside a scrolled window, and this one inside the
2957 hbox recpt editor inherits from, we'll need to go up in the
2958 hierarchy to know if the text view is part of the recpt editor
2959 or if it's a different text entry */
2960 parent = gtk_widget_get_parent (view_focus);
2961 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2962 editor = MODEST_RECPT_EDITOR (parent);
2965 editor = MODEST_RECPT_EDITOR (priv->to_field);
2968 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2972 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2974 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2976 modest_msg_edit_window_open_addressbook (window, NULL);
2980 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2981 gboolean show_toolbar)
2983 ModestWindowPrivate *parent_priv;
2984 ModestMsgEditWindowPrivate *priv;
2986 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2987 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2988 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2990 /* We can not just use the code of
2991 modest_msg_edit_window_setup_toolbar because it has a
2992 mixture of both initialization and creation code. */
2994 gint current_format;
2995 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2996 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2997 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2998 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3000 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
3003 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3005 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, show_toolbar, NULL);
3006 if (hildon_check_button_get_active (HILDON_CHECK_BUTTON (priv->show_toolbar_button)) != show_toolbar) {
3007 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->show_toolbar_button), show_toolbar);
3012 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
3013 TnyHeaderFlags priority_flags)
3015 ModestMsgEditWindowPrivate *priv;
3016 ModestWindowPrivate *parent_priv;
3018 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3020 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3021 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3023 if (priv->priority_flags != priority_flags) {
3024 GtkAction *priority_action = NULL;
3026 priv->priority_flags = priority_flags;
3028 switch (priority_flags) {
3029 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3030 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3031 MODEST_HEADER_ICON_HIGH,
3032 HILDON_ICON_SIZE_SMALL);
3033 gtk_widget_show (priv->priority_icon);
3034 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3035 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3037 case TNY_HEADER_FLAG_LOW_PRIORITY:
3038 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3039 MODEST_HEADER_ICON_LOW,
3040 HILDON_ICON_SIZE_SMALL);
3041 gtk_widget_show (priv->priority_icon);
3042 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3043 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3046 gtk_widget_hide (priv->priority_icon);
3047 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3048 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3051 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3052 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3054 gtk_widget_queue_resize (priv->subject_box);
3058 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3061 ModestMsgEditWindowPrivate *priv;
3062 ModestWindowPrivate *parent_priv;
3063 gint current_format;
3065 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3067 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3068 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3070 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3071 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3073 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3075 if (current_format != file_format) {
3076 switch (file_format) {
3077 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3078 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3079 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3080 update_signature (window, priv->last_from_account, priv->last_from_account);
3081 if (parent_priv->toolbar)
3082 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
3083 MODEST_MSG_EDIT_WINDOW (window));
3085 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3089 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3090 response = gtk_dialog_run (GTK_DIALOG (dialog));
3091 gtk_widget_destroy (dialog);
3092 if (response == GTK_RESPONSE_OK) {
3093 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3094 if (parent_priv->toolbar)
3095 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
3096 MODEST_MSG_EDIT_WINDOW (window));
3098 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3099 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3104 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3105 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3106 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3111 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3114 ModestMsgEditWindowPrivate *priv;
3115 WPTextBufferFormat oldfmt, fmt;
3116 gint old_position = 0;
3120 GdkColor *color = NULL;
3121 gboolean bold, bold_set, italic, italic_set;
3122 gboolean underline, underline_set;
3123 gboolean strikethrough, strikethrough_set;
3124 gboolean position_set;
3125 gboolean font_size_set, font_set, color_set;
3128 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3129 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3131 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3132 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3133 GTK_WINDOW(dialog), GTK_WINDOW (window));
3135 /* First we get the currently selected font information */
3136 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3138 switch (oldfmt.text_position) {
3139 case TEXT_POSITION_NORMAL:
3142 case TEXT_POSITION_SUPERSCRIPT:
3150 g_object_set (G_OBJECT (dialog),
3151 "bold", oldfmt.bold != FALSE,
3152 "bold-set", !oldfmt.cs.bold,
3153 "underline", oldfmt.underline != FALSE,
3154 "underline-set", !oldfmt.cs.underline,
3155 "italic", oldfmt.italic != FALSE,
3156 "italic-set", !oldfmt.cs.italic,
3157 "strikethrough", oldfmt.strikethrough != FALSE,
3158 "strikethrough-set", !oldfmt.cs.strikethrough,
3159 "color", &oldfmt.color,
3160 "color-set", !oldfmt.cs.color,
3161 "size", wp_font_size[oldfmt.font_size],
3162 "size-set", !oldfmt.cs.font_size,
3163 "position", old_position,
3164 "position-set", !oldfmt.cs.text_position,
3165 "family", wp_get_font_name (oldfmt.font),
3166 "family-set", !oldfmt.cs.font,
3169 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3170 GTK_WINDOW (dialog), GTK_WINDOW (window));
3171 gtk_widget_show_all (dialog);
3172 priv->font_dialog = dialog;
3173 response = gtk_dialog_run (GTK_DIALOG (dialog));
3174 priv->font_dialog = NULL;
3175 if (response == GTK_RESPONSE_OK) {
3177 g_object_get( dialog,
3179 "bold-set", &bold_set,
3180 "underline", &underline,
3181 "underline-set", &underline_set,
3183 "italic-set", &italic_set,
3184 "strikethrough", &strikethrough,
3185 "strikethrough-set", &strikethrough_set,
3187 "color-set", &color_set,
3189 "size-set", &font_size_set,
3190 "family", &font_name,
3191 "family-set", &font_set,
3192 "position", &position,
3193 "position-set", &position_set,
3198 if (response == GTK_RESPONSE_OK) {
3199 memset(&fmt, 0, sizeof(fmt));
3205 fmt.italic = italic;
3206 fmt.cs.italic = TRUE;
3208 if (underline_set) {
3209 fmt.underline = underline;
3210 fmt.cs.underline = TRUE;
3212 if (strikethrough_set) {
3213 fmt.strikethrough = strikethrough;
3214 fmt.cs.strikethrough = TRUE;
3219 ? TEXT_POSITION_NORMAL
3220 : ( ( position == 1 )
3221 ? TEXT_POSITION_SUPERSCRIPT
3222 : TEXT_POSITION_SUBSCRIPT );
3223 fmt.cs.text_position = TRUE;
3224 fmt.font_size = oldfmt.font_size;
3228 fmt.cs.color = TRUE;
3231 fmt.font = wp_get_font_index(font_name,
3236 if (font_size_set) {
3237 fmt.cs.font_size = TRUE;
3238 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3240 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3241 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3243 gtk_widget_destroy (dialog);
3245 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3249 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3251 ModestMsgEditWindowPrivate *priv;
3252 ModestWindowPrivate *parent_priv;
3253 gboolean was_rich_text, is_rich_text;
3255 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3256 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3257 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3259 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3261 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3263 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3265 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3266 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
3267 MODEST_MSG_EDIT_WINDOW (window));
3270 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3271 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3275 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3277 ModestMsgEditWindowPrivate *priv;
3279 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3280 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3282 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3284 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3285 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3290 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3292 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3294 priv->can_undo = can_undo;
3298 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3300 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3302 priv->can_redo = can_redo;
3306 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3308 ModestMsgEditWindowPrivate *priv;
3309 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3310 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3312 return priv->can_undo;
3316 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3318 ModestMsgEditWindowPrivate *priv;
3319 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3320 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3322 return priv->can_redo;
3327 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3330 GtkTextIter match_start, match_end;
3332 if (image_id == NULL)
3335 gtk_text_buffer_get_start_iter (buffer, &iter);
3337 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3338 GSList *tags = gtk_text_iter_get_tags (&match_start);
3340 for (node = tags; node != NULL; node = g_slist_next (node)) {
3341 GtkTextTag *tag = (GtkTextTag *) node->data;
3342 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3343 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3344 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3346 offset = gtk_text_iter_get_offset (&match_start);
3347 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3348 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3352 gtk_text_iter_forward_char (&iter);
3357 message_is_empty (ModestMsgEditWindow *window)
3359 ModestMsgEditWindowPrivate *priv = NULL;
3361 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3362 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3364 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3365 * so we can ignore markup.
3367 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3370 count = gtk_text_buffer_get_char_count (buf);
3376 msg_body_focus (GtkWidget *focus,
3377 GdkEventFocus *event,
3381 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3382 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3383 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3388 recpt_field_changed (GtkTextBuffer *buffer,
3389 ModestMsgEditWindow *editor)
3391 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3392 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3396 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3398 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3399 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3403 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3406 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3407 GtkTextBuffer *buffer;
3409 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3410 gtk_text_buffer_set_modified (buffer, modified);
3411 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3412 gtk_text_buffer_set_modified (buffer, modified);
3413 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3414 gtk_text_buffer_set_modified (buffer, modified);
3415 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3419 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3421 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3422 const char *account_name;
3423 GtkTextBuffer *buffer;
3425 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3426 if (gtk_text_buffer_get_modified (buffer))
3428 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3429 if (gtk_text_buffer_get_modified (buffer))
3431 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3432 if (gtk_text_buffer_get_modified (buffer))
3434 if (gtk_text_buffer_get_modified (priv->text_buffer))
3437 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3438 if (priv->original_mailbox) {
3439 if (!account_name || strcmp (account_name, priv->original_mailbox))
3441 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3452 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3454 ModestMsgEditWindowPrivate *priv = NULL;
3455 GSList *address_list = NULL;
3456 gboolean no_to, no_cc, no_bcc;
3458 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3459 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3461 /* check if there's no recipient added */
3462 no_to = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)));
3463 no_cc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field)));
3464 no_bcc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field)));
3467 if (no_to && no_cc && no_bcc) {
3468 /* no recipient contents, then select contacts */
3469 modest_msg_edit_window_open_addressbook (window, NULL);
3474 g_object_ref (window);
3475 if (!no_to && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3476 (add_to_addressbook) ? &address_list : NULL)) {
3477 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3478 g_object_unref (window);
3481 if (!no_cc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3482 (add_to_addressbook) ? &address_list : NULL)) {
3483 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3484 g_object_unref (window);
3487 if (!no_bcc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3488 (add_to_addressbook) ? &address_list : NULL)) {
3489 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3490 g_object_unref (window);
3494 /* Add contacts to address book */
3495 if (add_to_addressbook && address_list)
3496 modest_address_book_add_address_list (address_list);
3498 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3499 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3500 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3501 g_object_unref (window);
3508 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3510 GSList *recipients = NULL;
3511 ModestMsgEditWindowPrivate *priv;
3512 gchar *joined, *after_remove, *to, *cc, *bcc;
3514 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3516 /* First of all check names */
3517 if (!modest_msg_edit_window_check_names (self, FALSE))
3520 if (!modest_msg_edit_window_has_pending_addresses (self))
3523 /* Don't add the from obviously */
3524 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3525 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3526 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3528 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3533 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3536 recipients = modest_text_utils_split_addresses_list (after_remove);
3537 g_free (after_remove);
3540 /* Offer the user to add recipients to the address book */
3541 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3542 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3547 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3548 ModestMsgEditWindow *window)
3550 modest_msg_edit_window_offer_attach_file (window);
3554 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3556 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3558 return priv->clipboard_text;
3562 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3564 ModestMsgEditWindow *window)
3566 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3567 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3570 /* It could happen that the window was already closed */
3571 if (!GTK_WIDGET_VISIBLE (window))
3574 g_object_ref (window);
3575 text = gtk_clipboard_wait_for_text (selection_clipboard);
3577 if (priv->clipboard_text != NULL) {
3578 g_free (priv->clipboard_text);
3580 priv->clipboard_text = text;
3582 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3584 g_object_unref (window);
3587 static gboolean clipboard_owner_change_idle (gpointer userdata)
3589 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3590 ModestMsgEditWindowPrivate *priv;
3592 gdk_threads_enter ();
3593 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3594 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3596 priv->clipboard_owner_idle = 0;
3597 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3598 gdk_threads_leave ();
3604 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3606 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3607 if (priv->clipboard_owner_idle == 0) {
3608 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3609 clipboard_owner_change_idle,
3610 g_object_ref (window),
3616 subject_field_move_cursor (GtkEntry *entry,
3617 GtkMovementStep step,
3622 /* It could happen that the window was already closed */
3623 if (!GTK_WIDGET_VISIBLE (window))
3626 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3630 update_window_title (ModestMsgEditWindow *window)
3632 ModestMsgEditWindowPrivate *priv = NULL;
3633 const gchar *subject;
3635 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3636 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3637 if (subject == NULL || subject[0] == '\0')
3638 subject = _("mail_va_new_email");
3640 gtk_window_set_title (GTK_WINDOW (window), subject);
3646 body_insert_text (GtkTextBuffer *buffer,
3647 GtkTextIter *location,
3650 ModestMsgEditWindow *window)
3652 GtkTextIter end_iter;
3659 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3661 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3663 offset = gtk_text_iter_get_offset (&end_iter);
3664 line = gtk_text_iter_get_line (&end_iter);
3668 while (text_offset < text + len) {
3669 if (*text_offset == '\n')
3671 if (text_lines + line >= MAX_BODY_LINES) {
3672 len = text_offset - text;
3678 utf8_len = g_utf8_strlen (text, len);
3680 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3681 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3682 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3687 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3689 /* Prevent endless recursion */
3690 result = g_strndup (text, utf8_end - text);
3691 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3692 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3693 (gpointer) result, (gpointer) (utf8_end - text),
3695 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3699 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3700 if (priv->max_chars_banner == NULL) {
3701 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3702 _CS("ckdg_ib_maximum_characters_reached"));
3703 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3709 subject_field_changed (GtkEditable *editable,
3710 ModestMsgEditWindow *window)
3712 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3713 update_window_title (window);
3714 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3715 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3716 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3719 subject_field_insert_text (GtkEditable *editable,
3721 gint new_text_length,
3723 ModestMsgEditWindow *window)
3725 GString *result = g_string_new ("");
3727 gint result_len = 0;
3728 const gchar *entry_text = NULL;
3731 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3732 old_length = g_utf8_strlen (entry_text, -1);
3734 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3735 gunichar c = g_utf8_get_char_validated (current, 8);
3736 /* Invalid unichar, stop */
3742 result = g_string_append_unichar (result, c);
3746 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3747 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3750 /* Prevent endless recursion */
3751 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3752 g_signal_emit_by_name (editable, "insert-text",
3753 (gpointer) result->str, (gpointer) result->len,
3754 (gpointer) position, (gpointer) window);
3755 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3759 if (result_len + old_length > 1000) {
3760 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3761 _CS("ckdg_ib_maximum_characters_reached"));
3763 g_string_free (result, TRUE);
3767 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3770 ModestMsgEditWindowPrivate *priv = NULL;
3772 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3773 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3775 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3778 gtk_widget_show_all (priv->find_toolbar);
3779 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3781 gtk_widget_hide_all (priv->find_toolbar);
3782 gtk_widget_grab_focus (priv->msg_body);
3787 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3789 GtkTextIter *match_start,
3790 GtkTextIter *match_end)
3792 GtkTextIter end_iter;
3793 gchar *str_casefold;
3796 gchar *range_casefold;
3799 gboolean result = FALSE;
3806 gtk_text_iter_forward_to_end (&end_iter);
3808 str_casefold = g_utf8_casefold (str, -1);
3809 str_chars_n = strlen (str);
3811 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3812 range_casefold = g_utf8_casefold (range_text, -1);
3813 range_chars_n = strlen (range_casefold);
3815 if (range_chars_n < str_chars_n) {
3816 g_free (str_casefold);
3817 g_free (range_text);
3818 g_free (range_casefold);
3822 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3823 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3824 if (!g_utf8_collate (range_subtext, str_casefold)) {
3825 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3827 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3828 match_start, match_end, NULL)) {
3829 g_debug ("Matched string with collate, but not matched in model");
3831 g_free (found_text);
3833 g_free (range_subtext);
3837 g_free (str_casefold);
3838 g_free (range_text);
3839 g_free (range_casefold);
3846 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3847 ModestMsgEditWindow *window)
3849 gchar *current_search = NULL;
3850 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3852 GtkTextIter selection_start, selection_end;
3853 GtkTextIter match_start, match_end;
3854 gboolean continue_search = FALSE;
3856 if (message_is_empty (window)) {
3857 g_free (priv->last_search);
3858 priv->last_search = NULL;
3859 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3863 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3864 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3865 g_free (current_search);
3866 g_free (priv->last_search);
3867 priv->last_search = NULL;
3868 /* Information banner about empty search */
3869 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3873 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3874 continue_search = TRUE;
3876 g_free (priv->last_search);
3877 priv->last_search = g_strdup (current_search);
3880 if (continue_search) {
3881 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3882 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3883 &match_start, &match_end);
3885 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3887 GtkTextIter buffer_start;
3888 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3889 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3890 &match_start, &match_end);
3892 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3895 /* Mark as selected the string found in search */
3897 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3898 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3899 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3901 g_free (priv->last_search);
3902 priv->last_search = NULL;
3904 g_free (current_search);
3908 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3910 ModestMsgEditWindowPrivate *priv;
3912 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3917 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3920 ModestMsgEditWindowPrivate *priv;
3922 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3927 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3928 ModestMsgEditWindow *window)
3930 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3934 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3937 ModestMsgEditWindowPrivate *priv;
3938 TnyHeader *header = NULL;
3940 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3941 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3943 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3945 if (priv->draft_msg != NULL) {
3946 g_object_unref (priv->draft_msg);
3949 if (draft != NULL) {
3950 g_object_ref (draft);
3951 header = tny_msg_get_header (draft);
3952 if (priv->msg_uid) {
3953 g_free (priv->msg_uid);
3954 priv->msg_uid = NULL;
3956 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3959 priv->draft_msg = draft;
3963 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3964 GtkTextIter *start, GtkTextIter *end,
3967 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3968 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3971 if (tag == NULL) return;
3972 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3973 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3974 replace_with_images (window, priv->images);
3979 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3982 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3984 g_return_if_fail (TNY_IS_MIME_PART (part));
3985 tny_list_prepend (priv->attachments, (GObject *) part);
3986 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3987 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3988 gtk_widget_show_all (priv->attachments_caption);
3989 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3993 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3995 ModestMsgEditWindowPrivate *priv;
3997 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3998 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4000 return priv->msg_uid;
4004 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
4005 ModestMsgEditWindowWidgetType widget_type)
4007 ModestMsgEditWindowPrivate *priv;
4009 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
4010 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
4012 switch (widget_type) {
4013 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
4014 return priv->msg_body;
4016 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
4017 return priv->to_field;
4019 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
4020 return priv->cc_field;
4022 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4023 return priv->bcc_field;
4025 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4026 return priv->subject_field;
4028 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4029 return priv->attachments_view;
4037 remove_tags (WPTextBuffer *buffer)
4039 GtkTextIter start, end;
4041 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4042 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4044 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4048 on_account_removed (TnyAccountStore *account_store,
4049 TnyAccount *account,
4052 /* Do nothing if it's a store account, because we use the
4053 transport to send the messages */
4054 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4055 const gchar *parent_acc = NULL;
4056 const gchar *our_acc = NULL;
4058 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4059 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4060 /* Close this window if I'm showing a message of the removed account */
4061 if (strcmp (parent_acc, our_acc) == 0)
4062 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4067 update_signature (ModestMsgEditWindow *self,
4068 const gchar *old_account,
4069 const gchar *new_account)
4071 ModestMsgEditWindowPrivate *priv;
4072 gboolean has_old_signature, has_new_signature;
4074 ModestAccountMgr *mgr;
4077 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4079 gtk_text_buffer_begin_user_action (priv->text_buffer);
4081 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4082 mgr = modest_runtime_get_account_mgr ();
4086 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4087 if (has_old_signature) {
4088 GtkTextIter match_start, match_end;
4090 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4091 seems that the search has some problems
4092 with the blank space at the end */
4093 if (gtk_text_iter_forward_search (&iter, "--",
4094 GTK_TEXT_SEARCH_TEXT_ONLY,
4095 &match_start, NULL, NULL)) {
4096 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4097 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4099 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4100 &match_start, &match_end, NULL)) {
4104 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4109 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4110 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4111 if (has_new_signature) {
4114 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4115 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4117 is_rich = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
4119 WPTextBufferFormat *fmt;
4120 GdkColor style_color;
4121 if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
4122 gdk_color_parse ("grey", &style_color);
4124 fmt = g_new0 (WPTextBufferFormat, 1);
4125 fmt->color = style_color;
4126 fmt->cs.color = 0x1;
4127 wp_text_buffer_insert_with_attribute (WP_TEXT_BUFFER (priv->text_buffer), &iter,
4131 g_free (full_signature);
4133 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4137 gtk_text_buffer_end_user_action (priv->text_buffer);
4140 static void update_branding (ModestMsgEditWindow *self,
4141 const gchar *new_account)
4143 ModestMsgEditWindowPrivate *priv;
4144 ModestAccountMgr *mgr;
4145 const GdkPixbuf *new_icon = NULL;
4146 gchar *new_label = NULL;
4147 gboolean show = FALSE;
4149 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4151 mgr = modest_runtime_get_account_mgr ();
4153 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4155 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4156 gtk_widget_show (priv->brand_icon);
4159 gtk_widget_hide (priv->brand_icon);
4162 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4163 gtk_widget_show (priv->brand_label);
4167 gtk_widget_hide (priv->brand_label);
4171 gtk_widget_show (priv->brand_container);
4173 gtk_widget_hide (priv->brand_container);
4177 from_field_changed (HildonPickerButton *button,
4178 ModestMsgEditWindow *self)
4180 ModestMsgEditWindowPrivate *priv;
4181 gchar *old_account, *new_account;
4183 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4185 old_account = priv->last_from_account;
4186 new_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4189 g_warning ("%s, could not get the new account", __FUNCTION__);
4193 /* If the From is the same do nothing */
4194 if (old_account && new_account && !strcmp (old_account, new_account))
4197 priv->last_from_account = new_account;
4199 update_signature (self, old_account, new_account);
4200 update_branding (self, new_account);
4204 typedef struct _MessageSettingsHelper {
4205 ModestMsgEditWindow *window;
4206 GSList *priority_group;
4207 GSList *format_group;
4208 GtkToggleButton *current_priority;
4209 GtkToggleButton *current_format;
4210 } MessageSettingsHelper;
4213 on_priority_toggle (GtkToggleButton *button,
4214 MessageSettingsHelper *helper)
4217 ModestMsgEditWindowPrivate *priv;
4219 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4220 if (gtk_toggle_button_get_active (button)) {
4222 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4223 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4224 if ((node_button != button) &&
4225 gtk_toggle_button_get_active (node_button)) {
4226 gtk_toggle_button_set_active (node_button, FALSE);
4229 helper->current_priority = button;
4231 gboolean found = FALSE;
4232 /* If no one is active, activate it again */
4233 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4234 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4235 if (gtk_toggle_button_get_active (node_button)) {
4241 gtk_toggle_button_set_active (button, TRUE);
4247 on_format_toggle (GtkToggleButton *button,
4248 MessageSettingsHelper *helper)
4251 ModestMsgEditWindowPrivate *priv;
4253 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4254 if (gtk_toggle_button_get_active (button)) {
4256 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4257 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4258 if ((node_button != button) &&
4259 gtk_toggle_button_get_active (node_button)) {
4260 gtk_toggle_button_set_active (node_button, FALSE);
4263 helper->current_format = button;
4265 gboolean found = FALSE;
4266 /* If no one is active, activate it again */
4267 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4268 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4269 if (gtk_toggle_button_get_active (node_button)) {
4275 gtk_toggle_button_set_active (button, TRUE);
4282 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4287 GtkWidget *priority_hbox;
4288 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4289 GtkWidget *captioned;
4290 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4291 GtkWidget *format_hbox;
4292 GtkWidget *html_toggle, *text_toggle;
4293 ModestMsgEditWindowPrivate *priv;
4294 MessageSettingsHelper helper = {0,};
4296 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4297 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4298 helper.window = window;
4299 helper.priority_group = NULL;
4300 helper.format_group = NULL;
4302 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4303 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4305 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4306 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4307 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4308 vbox = gtk_vbox_new (FALSE, 0);
4309 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4310 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4311 gtk_container_add (GTK_CONTAINER (align), vbox);
4312 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4313 gtk_widget_show (align);
4314 gtk_widget_show (vbox);
4316 /* Priority toggles */
4317 priority_hbox = gtk_hbox_new (TRUE, 0);
4318 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4319 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4320 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4321 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4322 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4323 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4324 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4325 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4326 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4327 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4328 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4329 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4330 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4331 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4332 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4333 gtk_widget_show_all (priority_hbox);
4334 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4335 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4336 gtk_widget_show (captioned);
4337 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4339 /* format toggles */
4340 format_hbox = gtk_hbox_new (TRUE, 0);
4341 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4342 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4343 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4344 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4345 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4346 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4347 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4348 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4349 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4350 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4351 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4352 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4353 gtk_widget_show_all (format_hbox);
4354 gtk_widget_show (format_hbox);
4355 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4358 g_object_unref (title_sizegroup);
4359 g_object_unref (value_sizegroup);
4361 /* Set current values */
4362 switch (priv->priority_flags) {
4363 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4364 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4365 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4367 case TNY_HEADER_FLAG_LOW_PRIORITY:
4368 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4369 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4372 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4373 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4377 switch (modest_msg_edit_window_get_format (window)) {
4378 case MODEST_MSG_EDIT_FORMAT_TEXT:
4379 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4380 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4382 case MODEST_MSG_EDIT_FORMAT_HTML:
4384 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4385 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4389 /* Signal connects */
4390 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4391 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4392 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4393 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4394 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4396 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4397 GTK_WINDOW (dialog), GTK_WINDOW (window));
4399 /* Save settings if the user clicked on done */
4400 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4401 TnyHeaderFlags flags;
4402 ModestMsgEditFormat old_format, new_format;
4404 /* Set priority flags */
4405 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4406 if (priv->priority_flags != flags)
4407 modest_msg_edit_window_set_priority_flags (window, flags);
4409 /* Set edit format */
4410 old_format = modest_msg_edit_window_get_format (window);
4411 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4412 if (old_format != new_format) {
4413 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4414 modest_msg_edit_window_set_file_format (window, file_format);
4418 gtk_widget_destroy (dialog);
4419 g_slist_free (helper.priority_group);
4423 on_message_settings (GtkAction *action,
4424 ModestMsgEditWindow *window)
4426 modest_msg_edit_window_show_msg_settings_dialog (window);
4430 on_show_toolbar_button_toggled (HildonCheckButton *button,
4431 ModestMsgEditWindow *window)
4433 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4435 modest_msg_edit_window_show_toolbar (MODEST_WINDOW (window),
4436 hildon_check_button_get_active (button));
4440 on_cc_button_toggled (HildonCheckButton *button,
4441 ModestMsgEditWindow *window)
4443 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4445 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4446 hildon_check_button_get_active (button));
4450 on_bcc_button_toggled (HildonCheckButton *button,
4451 ModestMsgEditWindow *window)
4453 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4455 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4456 hildon_check_button_get_active (button));
4460 setup_menu (ModestMsgEditWindow *self)
4462 ModestMsgEditWindowPrivate *priv = NULL;
4464 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4466 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4468 /* Settings menu buttons */
4469 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4470 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4472 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4473 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4474 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4475 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4476 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4477 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4479 priv->cc_button = hildon_check_button_new (0);
4480 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4481 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4483 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4485 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4486 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4487 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4488 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4490 priv->bcc_button = hildon_check_button_new (0);
4491 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4492 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4494 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4496 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4497 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4498 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4499 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4501 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4502 APP_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4504 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4505 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4506 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4507 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4508 APP_MENU_CALLBACK (on_message_settings),
4510 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4511 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4513 priv->show_toolbar_button = hildon_check_button_new (0);
4514 gtk_button_set_label (GTK_BUTTON (priv->show_toolbar_button), _("mcen_bd_show_toolbar"));
4515 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
4517 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->show_toolbar_button),
4518 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_show_toolbar));
4519 g_signal_connect (G_OBJECT (priv->show_toolbar_button), "toggled",
4520 G_CALLBACK (on_show_toolbar_button_toggled), (gpointer) self);
4521 gtk_button_set_alignment (GTK_BUTTON (priv->show_toolbar_button), 0.5, 0.5);
4522 gtk_button_set_alignment (GTK_BUTTON (priv->show_toolbar_button), 0.5, 0.5);
4527 emit_open_addressbook (GtkButton *button,
4528 ModestRecptEditor *editor)
4530 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4534 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4535 const gchar *label, GtkWidget *control)
4537 GtkWidget *abook_button;
4540 GtkWidget *label_widget;
4542 box = gtk_hbox_new (FALSE, 0);
4544 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4545 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4547 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4548 label_widget = gtk_label_new (label);
4549 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4550 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4552 gtk_container_add (GTK_CONTAINER (align), abook_button);
4553 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4554 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4555 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4556 if (title_size_group)
4557 gtk_size_group_add_widget (title_size_group, label_widget);
4558 if (value_size_group)
4559 gtk_size_group_add_widget (value_size_group, control);
4561 g_signal_connect (G_OBJECT (abook_button), "clicked",
4562 G_CALLBACK (emit_open_addressbook), control);
4568 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4570 ModestMsgEditWindowPrivate *priv = NULL;
4572 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4574 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4575 priv->max_chars_banner = NULL;
4579 has_pending_addresses (ModestRecptEditor *recpt_editor)
4581 const gchar *recipients = NULL;
4582 GSList *start_indexes = NULL, *end_indexes = NULL;
4583 GSList *current_start, *current_end;
4584 GtkTextBuffer *buffer;
4585 gint offset_delta = 0;
4587 gboolean has_recipients_to_add = FALSE;
4589 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4590 last_length = g_utf8_strlen (recipients, -1);
4591 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4596 current_start = start_indexes;
4597 current_end = end_indexes;
4598 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4600 while (current_start && !has_recipients_to_add) {
4602 gchar *start_ptr, *end_ptr;
4603 gint start_pos, end_pos;
4605 start_pos = (*((gint*) current_start->data)) + offset_delta;
4606 end_pos = (*((gint*) current_end->data)) + offset_delta;
4608 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4609 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4611 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4613 if (modest_text_utils_validate_recipient (address, NULL)) {
4614 if (!modest_address_book_has_address (address)) {
4615 has_recipients_to_add = TRUE;
4618 current_start = g_slist_next (current_start);
4619 current_end = g_slist_next (current_end);
4621 return has_recipients_to_add;
4625 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4627 ModestMsgEditWindowPrivate *priv = NULL;
4629 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4631 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4633 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4634 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4635 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))
4642 modest_msg_edit_window_set_custom_header_pairs (ModestMsgEditWindow *self,
4643 TnyList *header_pairs)
4645 ModestMsgEditWindowPrivate *priv = NULL;
4647 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
4648 g_return_if_fail (TNY_IS_LIST (header_pairs));
4650 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4651 g_object_unref (priv->custom_header_pairs);
4652 priv->custom_header_pairs = tny_list_copy (header_pairs);