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_message_settings (GtkAction *action,
176 ModestMsgEditWindow *window);
177 static void setup_menu (ModestMsgEditWindow *self);
179 static void from_field_changed (HildonPickerButton *button,
180 ModestMsgEditWindow *self);
181 static void font_size_clicked (GtkToolButton *button,
182 ModestMsgEditWindow *window);
183 static void font_face_clicked (GtkToolButton *button,
184 ModestMsgEditWindow *window);
185 static void update_signature (ModestMsgEditWindow *self,
186 const gchar *old_account,
187 const gchar *new_account);
188 static void update_branding (ModestMsgEditWindow *self,
189 const gchar *new_account);
190 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
191 const gchar *label, GtkWidget *control);
192 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
193 static void DEBUG_BUFFER (WPTextBuffer *buffer)
197 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
199 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
200 while (!gtk_text_iter_is_end (&iter)) {
201 GString *output = g_string_new ("");
202 GSList *toggled_tags;
205 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
206 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
207 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
208 GtkTextTag *tag = (GtkTextTag *) node->data;
210 g_object_get (G_OBJECT (tag), "name", &name, NULL);
211 output = g_string_append (output, name);
212 g_string_append (output, " ");
214 output = g_string_append (output, "] OPENED [ ");
215 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
216 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
217 GtkTextTag *tag = (GtkTextTag *) node->data;
219 g_object_get (G_OBJECT (tag), "name", &name, NULL);
220 output = g_string_append (output, name);
221 g_string_append (output, " ");
223 output = g_string_append (output, "]\n");
224 g_debug ("%s", output->str);
225 g_string_free (output, TRUE);
226 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
228 g_debug ("END BUFFER");
232 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
233 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
237 /* static gboolean */
238 /* on_key_pressed (GtkWidget *self, */
239 /* GdkEventKey *event, */
240 /* gpointer user_data); */
242 /* list my signals */
249 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
250 struct _ModestMsgEditWindowPrivate {
252 GtkWidget *header_box;
254 ModestPairList *from_field_protos;
255 GtkWidget *from_field;
256 gchar *last_from_account;
257 gchar *original_account_name;
262 gchar *original_mailbox;
266 GtkWidget *bcc_field;
267 GtkWidget *subject_field;
268 GtkWidget *attachments_view;
269 GtkWidget *priority_icon;
270 GtkWidget *subject_box;
271 GtkWidget *send_button;
273 GtkWidget *cc_caption;
274 GtkWidget *bcc_caption;
275 gboolean update_caption_visibility;
276 GtkWidget *attachments_caption;
278 GtkTextBuffer *text_buffer;
280 GtkWidget *font_size_toolitem;
281 GtkWidget *font_face_toolitem;
282 GtkWidget *font_color_button;
283 GtkWidget *font_color_toolitem;
284 GSList *font_items_group;
285 GtkTreeModel *faces_model;
286 gint current_face_index;
287 GtkWidget *font_tool_button_label;
288 GtkTreeModel *sizes_model;
289 gint current_size_index;
290 GtkWidget *size_tool_button_label;
292 GtkWidget *find_toolbar;
295 GtkWidget *font_dialog;
298 guint correct_scroll_idle;
299 guint scroll_drag_timeout_id;
303 TnyList *attachments;
308 TnyHeaderFlags priority_flags;
310 gboolean can_undo, can_redo;
311 gulong clipboard_change_handler_id;
312 gulong default_clipboard_change_handler_id;
313 gulong account_removed_handler_id;
314 guint clipboard_owner_idle;
315 gchar *clipboard_text;
324 GtkWidget *cc_button;
325 GtkWidget *bcc_button;
327 GtkWidget *max_chars_banner;
329 GtkWidget *brand_icon;
330 GtkWidget *brand_label;
331 GtkWidget *brand_container;
334 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
335 MODEST_TYPE_MSG_EDIT_WINDOW, \
336 ModestMsgEditWindowPrivate))
338 static GtkWindowClass *parent_class = NULL;
340 /* uncomment the following if you have defined any signals */
341 /* static guint signals[LAST_SIGNAL] = {0}; */
344 modest_msg_edit_window_get_type (void)
346 static GType my_type = 0;
348 static const GTypeInfo my_info = {
349 sizeof(ModestMsgEditWindowClass),
350 NULL, /* base init */
351 NULL, /* base finalize */
352 (GClassInitFunc) modest_msg_edit_window_class_init,
353 NULL, /* class finalize */
354 NULL, /* class data */
355 sizeof(ModestMsgEditWindow),
357 (GInstanceInitFunc) modest_msg_edit_window_init,
360 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
361 "ModestMsgEditWindow",
369 save_state (ModestWindow *self)
371 modest_widget_memory_save (modest_runtime_get_conf(),
372 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
377 restore_settings (ModestMsgEditWindow *self)
379 ModestConf *conf = NULL;
381 conf = modest_runtime_get_conf ();
383 /* Dim at start clipboard actions */
384 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
389 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
391 GObjectClass *gobject_class;
392 ModestWindowClass *modest_window_class;
393 gobject_class = (GObjectClass*) klass;
394 modest_window_class = (ModestWindowClass*) klass;
396 parent_class = g_type_class_peek_parent (klass);
397 gobject_class->finalize = modest_msg_edit_window_finalize;
399 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
400 modest_window_class->save_state_func = save_state;
401 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
403 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
407 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
409 ModestMsgEditWindowPrivate *priv;
410 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
412 priv->msg_body = NULL;
413 priv->from_field = NULL;
414 priv->to_field = NULL;
415 priv->cc_field = NULL;
416 priv->bcc_field = NULL;
417 priv->subject_field = NULL;
418 priv->attachments = TNY_LIST (tny_simple_list_new ());
419 priv->images = TNY_LIST (tny_simple_list_new ());
420 priv->images_size = 0;
421 priv->images_count = 0;
424 priv->cc_caption = NULL;
425 priv->bcc_caption = NULL;
426 priv->update_caption_visibility = FALSE;
428 priv->priority_flags = 0;
430 priv->find_toolbar = NULL;
431 priv->last_search = NULL;
433 priv->draft_msg = NULL;
434 priv->outbox_msg = NULL;
435 priv->msg_uid = NULL;
437 priv->can_undo = FALSE;
438 priv->can_redo = FALSE;
439 priv->clipboard_change_handler_id = 0;
440 priv->default_clipboard_change_handler_id = 0;
441 priv->account_removed_handler_id = 0;
442 priv->clipboard_owner_idle = 0;
443 priv->clipboard_text = NULL;
446 priv->scroll_drag_timeout_id = 0;
447 priv->correct_scroll_idle = 0;
448 priv->last_upper = 0.0;
450 priv->font_dialog = NULL;
451 priv->app_menu = NULL;
453 priv->references = NULL;
454 priv->in_reply_to = NULL;
455 priv->max_chars_banner = NULL;
457 if (!is_wp_text_buffer_started) {
458 is_wp_text_buffer_started = TRUE;
459 wp_text_buffer_library_init ();
464 hildon_program_add_window (hildon_program_get_instance(),
469 multimailbox_get_default_mailbox (const gchar *account_name)
471 gchar *transport_account;
472 gchar *result = NULL;
474 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
476 TNY_ACCOUNT_TYPE_TRANSPORT);
477 if (transport_account) {
479 ModestProtocolRegistry *registry;
481 registry = modest_runtime_get_protocol_registry ();
483 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
484 MODEST_ACCOUNT_PROTO, TRUE);
486 ModestProtocol *protocol =
487 modest_protocol_registry_get_protocol_by_name (registry,
488 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
490 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
491 ModestPairList *pair_list;
493 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
496 ModestPair *pair = (ModestPair *) pair_list->data;
497 result = g_strdup ((const gchar *) pair->first);
498 modest_pair_list_free (pair_list);
509 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
511 static ModestPairList*
512 get_transports (void)
514 GSList *transports = NULL;
516 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
517 GSList *accounts = modest_account_mgr_account_names (account_mgr,
518 TRUE /* only enabled accounts. */);
520 GSList *cursor = accounts;
522 gchar *account_name = cursor->data;
525 gchar *transport_account;
526 gboolean multi_mailbox = FALSE;
527 ModestProtocol *protocol = NULL;
529 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
531 transport_account = modest_account_mgr_get_server_account_name
532 (modest_runtime_get_account_mgr (),
534 TNY_ACCOUNT_TYPE_TRANSPORT);
535 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
536 ModestPairList *pair_list;
537 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
540 transports = g_slist_concat (transports, pair_list);
541 multi_mailbox = TRUE;
546 if (!multi_mailbox) {
547 gchar *from_string = NULL;
549 from_string = modest_account_mgr_get_from_string (account_mgr,
551 if (from_string && account_name) {
552 gchar *name = account_name;
553 ModestPair *pair = modest_pair_new ((gpointer) name,
554 (gpointer) from_string , TRUE);
555 transports = g_slist_prepend (transports, pair);
560 cursor = cursor->next;
562 g_slist_free (accounts); /* only free the accounts, not the elements,
563 * because they are used in the pairlist */
567 static void window_focus (GtkWindow *window,
571 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
575 scroll_drag_timeout (gpointer userdata)
577 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
578 ModestMsgEditWindowPrivate *priv;
580 /* It could happen that the window was already closed */
581 if (!GTK_WIDGET_VISIBLE (win))
584 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
586 correct_scroll_without_drag_check (win, TRUE);
588 priv->scroll_drag_timeout_id = 0;
594 correct_scroll_without_drag_check_idle (gpointer userdata)
596 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
597 ModestMsgEditWindowPrivate *priv;
599 GdkRectangle rectangle;
600 gint offset_min, offset_max;
604 /* It could happen that the window was already closed */
605 if (!GTK_WIDGET_VISIBLE (w))
608 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
610 insert = gtk_text_buffer_get_insert (priv->text_buffer);
611 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
613 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
614 offset_min = priv->msg_body->allocation.y + rectangle.y;
615 offset_max = offset_min + rectangle.height;
617 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
618 offset_min = MAX (offset_min - 48, 0);
619 offset_max = MIN (offset_max + 48, vadj->upper);
621 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
623 priv->correct_scroll_idle = 0;
628 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
630 ModestMsgEditWindowPrivate *priv;
632 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
634 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
637 if (priv->correct_scroll_idle > 0) {
641 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
642 (GSourceFunc) correct_scroll_without_drag_check_idle,
648 correct_scroll (ModestMsgEditWindow *w)
650 ModestMsgEditWindowPrivate *priv;
652 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
653 if (gtk_grab_get_current () == priv->msg_body) {
654 if (priv->scroll_drag_timeout_id == 0) {
655 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
657 (GSourceFunc) scroll_drag_timeout,
664 correct_scroll_without_drag_check (w, TRUE);
668 text_buffer_end_user_action (GtkTextBuffer *buffer,
669 ModestMsgEditWindow *userdata)
672 correct_scroll (userdata);
676 text_buffer_mark_set (GtkTextBuffer *buffer,
679 ModestMsgEditWindow *userdata)
681 gtk_text_buffer_begin_user_action (buffer);
682 gtk_text_buffer_end_user_action (buffer);
686 cut_clipboard_check (GtkTextView *text_view,
689 GtkTextBuffer *buffer;
691 buffer = gtk_text_view_get_buffer (text_view);
692 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
693 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
698 copy_clipboard_check (GtkTextView *text_view,
701 GtkTextBuffer *buffer;
703 buffer = gtk_text_view_get_buffer (text_view);
704 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
705 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
710 attachment_deleted (ModestAttachmentsView *attachments_view,
713 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
718 body_size_request (GtkWidget *body,
722 /* Make sure the body always get at least 70 pixels */
723 if (req->height < 70)
728 connect_signals (ModestMsgEditWindow *obj)
730 ModestMsgEditWindowPrivate *priv;
732 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
734 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
735 G_CALLBACK (text_buffer_refresh_attributes), obj);
736 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
737 G_CALLBACK (text_buffer_can_undo), obj);
738 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
739 G_CALLBACK (text_buffer_can_redo), obj);
740 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
741 G_CALLBACK (body_changed), obj);
742 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
743 G_CALLBACK (body_insert_text), obj);
744 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
745 G_CALLBACK (body_changed), obj);
746 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
747 G_CALLBACK (text_buffer_end_user_action), obj);
748 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
749 G_CALLBACK (text_buffer_mark_set), obj);
750 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
751 G_CALLBACK (text_buffer_apply_tag), obj);
752 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
753 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
754 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
755 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
756 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
757 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
759 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
760 G_CALLBACK (modest_ui_actions_on_send), obj);
762 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
763 G_CALLBACK (from_field_changed), obj);
765 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
766 G_CALLBACK (msg_body_focus), obj);
767 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
768 G_CALLBACK (msg_body_focus), obj);
769 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
770 G_CALLBACK (body_size_request), obj);
771 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
772 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
773 "changed", G_CALLBACK (recpt_field_changed), obj);
774 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
775 "changed", G_CALLBACK (recpt_field_changed), obj);
776 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
777 "changed", G_CALLBACK (recpt_field_changed), obj);
778 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
779 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
780 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
782 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
783 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
785 priv->clipboard_change_handler_id =
786 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
787 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
788 priv->default_clipboard_change_handler_id =
789 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
790 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
792 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
793 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
794 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
798 init_wp_text_view_style ()
800 static gboolean initialized = FALSE;
803 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
809 init_window (ModestMsgEditWindow *obj)
811 GtkWidget *to_caption, *subject_caption;
812 GtkWidget *main_vbox;
813 ModestMsgEditWindowPrivate *priv;
814 GtkActionGroup *action_group;
815 ModestWindowPrivate *parent_priv;
816 GdkPixbuf *window_icon = NULL;
817 GError *error = NULL;
819 GtkSizeGroup *title_size_group;
820 GtkSizeGroup *value_size_group;
821 GtkWidget *window_box;
822 GtkWidget *window_align;
823 #if (GTK_MINOR_VERSION >= 10)
824 GdkAtom deserialize_type;
826 GtkWidget *from_send_hbox;
827 GtkWidget *send_icon;
828 GtkWidget *attachments_label;
829 GtkWidget *branding_box;
831 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
832 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
834 parent_priv->ui_manager = gtk_ui_manager_new();
835 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
836 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
838 /* Add common actions */
839 gtk_action_group_add_actions (action_group,
840 modest_msg_edit_action_entries,
841 G_N_ELEMENTS (modest_msg_edit_action_entries),
843 gtk_action_group_add_actions (action_group,
844 hildon2_msg_edit_action_entries,
845 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
847 gtk_action_group_add_toggle_actions (action_group,
848 modest_msg_edit_toggle_action_entries,
849 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
851 gtk_action_group_add_radio_actions (action_group,
852 modest_msg_edit_alignment_radio_action_entries,
853 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
855 G_CALLBACK (modest_ui_actions_on_change_justify),
857 gtk_action_group_add_radio_actions (action_group,
858 modest_msg_edit_priority_action_entries,
859 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
861 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
863 gtk_action_group_add_radio_actions (action_group,
864 modest_msg_edit_file_format_action_entries,
865 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
866 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
867 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
869 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
870 g_object_unref (action_group);
872 /* Load the UI definition */
873 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
876 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
877 g_clear_error (&error);
880 /* Add accelerators */
881 gtk_window_add_accel_group (GTK_WINDOW (obj),
882 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
884 parent_priv->menubar = NULL;
886 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
887 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
889 /* Note: This ModestPairList* must exist for as long as the picker
890 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
891 * so it can't know how to manage its memory. */
892 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
893 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
895 modest_selector_picker_set_value_max_chars (MODEST_SELECTOR_PICKER (priv->from_field), MAX_FROM_VALUE);
896 modest_maemo_utils_set_hbutton_layout (title_size_group, NULL,
897 _("mail_va_from"), priv->from_field);
898 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
899 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
900 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
902 priv->to_field = modest_recpt_editor_new ();
903 priv->cc_field = modest_recpt_editor_new ();
904 priv->bcc_field = modest_recpt_editor_new ();
905 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
906 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
907 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
908 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
909 priv->priority_icon = gtk_image_new ();
910 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
911 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
912 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
913 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
914 hildon_entry_set_placeholder ((HildonEntry *) priv->subject_field, _("mail_va_no_subject"));
915 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
916 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
917 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
918 priv->attachments_view = modest_attachments_view_new (NULL);
919 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
920 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
922 priv->header_box = gtk_vbox_new (FALSE, 0);
924 to_caption = _create_addressbook_box
925 (title_size_group, value_size_group,
926 _("mail_va_to"), priv->to_field);
927 priv->cc_caption = _create_addressbook_box
928 (title_size_group, value_size_group,
929 _("mail_va_cc"), priv->cc_field);
930 priv->bcc_caption = _create_addressbook_box
931 (title_size_group, value_size_group,
932 _("mail_va_hotfix1"), priv->bcc_field);
933 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
934 _("mail_va_subject"), FALSE, priv->subject_box);
935 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (NULL, NULL,
936 _("mail_va_attachment"),
938 priv->attachments_view,
939 HILDON_SIZE_AUTO_WIDTH |
940 HILDON_SIZE_AUTO_HEIGHT);
941 attachments_label = modest_maemo_utils_captioned_get_label_widget (priv->attachments_caption);
942 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
945 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
946 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
947 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
948 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
950 g_object_unref (title_size_group);
951 g_object_unref (value_size_group);
953 priv->brand_icon = gtk_image_new ();
954 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
955 priv->brand_label = gtk_label_new (NULL);
956 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
957 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
958 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
959 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
961 from_send_hbox = gtk_hbox_new (FALSE, 0);
962 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->from_field, TRUE, TRUE, 0);
963 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
965 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
966 gtk_widget_show (branding_box);
967 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
968 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
970 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
971 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
972 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
973 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
976 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
977 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
978 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
979 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
980 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
981 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
982 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
983 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
985 init_wp_text_view_style ();
987 priv->msg_body = modest_wp_text_view_new ();
990 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
991 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
992 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
993 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
994 #if (GTK_MINOR_VERSION >= 10)
995 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
996 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
998 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
999 deserialize_type, TRUE);
1001 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1003 priv->find_toolbar = hildon_find_toolbar_new (NULL);
1004 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
1006 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1008 priv->pannable = hildon_pannable_area_new ();
1010 g_object_set (G_OBJECT (priv->pannable), "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
1012 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1013 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1014 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1016 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1017 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1018 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1020 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
1021 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
1023 window_box = gtk_vbox_new (FALSE, 0);
1024 gtk_container_add (GTK_CONTAINER(obj), window_box);
1026 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
1028 /* Set window icon */
1029 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1031 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1032 g_object_unref (window_icon);
1037 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1039 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1041 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1042 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1043 priv->clipboard_change_handler_id))
1044 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1045 priv->clipboard_change_handler_id);
1046 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1047 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1048 priv->default_clipboard_change_handler_id))
1049 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1050 priv->default_clipboard_change_handler_id);
1052 if (priv->account_removed_handler_id &&
1053 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1054 priv->account_removed_handler_id))
1055 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1056 priv->account_removed_handler_id);
1060 modest_msg_edit_window_finalize (GObject *obj)
1062 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1064 if (priv->max_chars_banner) {
1065 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1066 priv->max_chars_banner = FALSE;
1069 /* Sanity check: shouldn't be needed, the window mgr should
1070 call this function before */
1071 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1073 if (priv->font_dialog != NULL) {
1074 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1077 if (priv->clipboard_text != NULL) {
1078 g_free (priv->clipboard_text);
1079 priv->clipboard_text = NULL;
1082 if (priv->draft_msg != NULL) {
1083 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1084 if (TNY_IS_HEADER (header)) {
1085 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1086 modest_window_mgr_unregister_header (mgr, header);
1088 g_object_unref (priv->draft_msg);
1089 priv->draft_msg = NULL;
1091 if (priv->outbox_msg != NULL) {
1092 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1093 if (TNY_IS_HEADER (header)) {
1094 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1095 modest_window_mgr_unregister_header (mgr, header);
1097 g_object_unref (priv->outbox_msg);
1098 priv->outbox_msg = NULL;
1100 if (priv->correct_scroll_idle > 0) {
1101 g_source_remove (priv->correct_scroll_idle);
1102 priv->correct_scroll_idle = 0;
1104 if (priv->scroll_drag_timeout_id > 0) {
1105 g_source_remove (priv->scroll_drag_timeout_id);
1106 priv->scroll_drag_timeout_id = 0;
1108 if (priv->clipboard_owner_idle > 0) {
1109 g_source_remove (priv->clipboard_owner_idle);
1110 priv->clipboard_owner_idle = 0;
1112 if (priv->original_account_name)
1113 g_free (priv->original_account_name);
1114 if (priv->original_mailbox)
1115 g_free (priv->original_mailbox);
1116 g_free (priv->msg_uid);
1117 g_free (priv->last_search);
1118 g_free (priv->references);
1119 g_free (priv->in_reply_to);
1120 g_object_unref (priv->attachments);
1121 g_object_unref (priv->images);
1123 /* This had to stay alive for as long as the picker that used it: */
1124 modest_pair_list_free (priv->from_field_protos);
1126 G_OBJECT_CLASS(parent_class)->finalize (obj);
1130 pixbuf_size_prepared (GdkPixbufLoader *loader,
1133 ModestMsgEditWindow *self)
1135 gint new_height, new_width;
1138 new_height = height;
1142 if (width > IMAGE_MAX_WIDTH) {
1143 new_height = height * IMAGE_MAX_WIDTH / width;
1144 new_width = IMAGE_MAX_WIDTH;
1147 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1151 pixbuf_from_stream (TnyStream *stream,
1152 const gchar *mime_type,
1153 guint64 *stream_size,
1154 ModestMsgEditWindow *self)
1156 GdkPixbufLoader *loader;
1159 GError *error = NULL;
1163 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1165 if (loader == NULL) {
1170 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1172 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1174 tny_stream_reset (TNY_STREAM (stream));
1175 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1176 unsigned char read_buffer[128];
1178 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1180 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1183 /* Allow some UI responsiveness */
1184 while (gtk_events_pending ())
1185 gtk_main_iteration ();
1187 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1189 gdk_pixbuf_loader_close (loader, &error);
1192 g_error_free (error);
1193 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1195 g_object_ref (pixbuf);
1196 g_object_unref (loader);
1201 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1202 GdkPixbuf *new_pixbuf;
1204 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1205 gdk_pixbuf_get_width (pixbuf);
1206 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1207 g_object_unref (pixbuf);
1208 pixbuf = new_pixbuf;
1212 *stream_size = size;
1218 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1220 ModestMsgEditWindowPrivate *priv;
1223 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1225 g_object_ref (self);
1226 for (iter = tny_list_create_iterator (attachments);
1227 !tny_iterator_is_done (iter);
1228 tny_iterator_next (iter)) {
1229 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1230 const gchar *cid = tny_mime_part_get_content_id (part);
1231 const gchar *mime_type = tny_mime_part_get_content_type (part);
1232 if ((cid != NULL)&&(mime_type != NULL)) {
1233 guint64 stream_size;
1234 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1235 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1238 g_object_unref (stream);
1240 if (pixbuf != NULL) {
1241 priv->images_count ++;
1242 priv->images_size += stream_size;
1243 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1244 g_object_unref (pixbuf);
1247 g_object_unref (part);
1249 g_object_unref (iter);
1250 g_object_unref (self);
1254 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1256 TnyMimePart *parent = NULL;
1257 const gchar *content_type = NULL;
1258 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1260 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1262 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1263 parent = g_object_ref (msg);
1264 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1265 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1268 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1269 iter = tny_list_create_iterator (parts);
1270 while (!tny_iterator_is_done (iter)) {
1272 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1273 content_type = tny_mime_part_get_content_type (part);
1274 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1278 g_object_unref (part);
1280 tny_iterator_next (iter);
1282 g_object_unref (iter);
1283 g_object_unref (parts);
1286 if (parent != NULL) {
1287 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1290 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1291 iter = tny_list_create_iterator (parts);
1292 while (!tny_iterator_is_done (iter)) {
1294 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1295 content_type = tny_mime_part_get_content_type (part);
1296 if (content_type && g_str_has_prefix (content_type, "image/")) {
1297 tny_list_prepend (priv->images, (GObject *) part);
1299 g_object_unref (part);
1300 tny_iterator_next (iter);
1302 g_object_unref (iter);
1303 g_object_unref (parts);
1304 g_object_unref (parent);
1309 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1312 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1314 for (iter = tny_list_create_iterator (attachments) ;
1315 !tny_iterator_is_done (iter);
1316 tny_iterator_next (iter)) {
1317 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1318 const gchar *cid = tny_mime_part_get_content_id (part);
1320 char *invalid = NULL;
1321 gint int_cid = strtol (cid, &invalid, 10);
1322 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1323 priv->next_cid = int_cid + 1;
1326 g_object_unref (part);
1328 g_object_unref (iter);
1332 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1335 gchar *to, *cc, *bcc, *subject;
1337 ModestMsgEditWindowPrivate *priv;
1338 ModestWindowPrivate *parent_priv;
1340 TnyHeaderFlags priority_flags;
1341 TnyFolder *msg_folder;
1342 gboolean is_html = FALSE;
1343 gboolean field_view_set;
1345 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1346 g_return_if_fail (TNY_IS_MSG (msg));
1348 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1349 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1351 header = tny_msg_get_header (msg);
1352 to = tny_header_dup_to (header);
1353 cc = tny_header_dup_cc (header);
1354 bcc = tny_header_dup_bcc (header);
1355 subject = tny_header_dup_subject (header);
1357 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1358 priority_flags = tny_header_get_priority (header);
1361 gchar *quoted_names = modest_text_utils_quote_names (to);
1362 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1363 g_free (quoted_names);
1366 field_view_set = TRUE;
1368 gchar *quoted_names = modest_text_utils_quote_names (cc);
1369 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1370 g_free (quoted_names);
1371 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1372 gtk_widget_show (priv->cc_caption);
1373 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1374 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1375 gtk_widget_hide (priv->cc_caption);
1376 field_view_set = FALSE;
1378 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1380 field_view_set = TRUE;
1382 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1383 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1384 g_free (quoted_names);
1385 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1386 gtk_widget_show (priv->bcc_caption);
1387 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1388 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1389 gtk_widget_hide (priv->bcc_caption);
1390 field_view_set = FALSE;
1392 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1396 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1397 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1400 update_window_title (self);
1402 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1403 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1405 if ((body == NULL)||(body[0] == '\0')) {
1407 body = modest_text_utils_convert_to_html ("");
1410 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1411 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1414 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1417 /* Add attachments to the view */
1418 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1419 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1420 if (tny_list_get_length (priv->attachments) == 0) {
1421 gtk_widget_hide (priv->attachments_caption);
1423 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1424 gtk_widget_show_all (priv->attachments_caption);
1426 get_related_images (self, msg);
1427 update_next_cid (self, priv->attachments);
1428 update_next_cid (self, priv->images);
1429 replace_with_images (self, priv->images);
1431 if (preserve_is_rich && !is_html) {
1432 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1433 /* Get the default format required from configuration */
1434 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1435 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1438 /* Set the default focus depending on having already a To: field or not */
1439 if ((!to)||(*to == '\0')) {
1440 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1442 gtk_widget_grab_focus (priv->msg_body);
1445 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1447 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1448 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1450 modest_msg_edit_window_set_modified (self, FALSE);
1452 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1453 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1454 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1455 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1457 if (priv->msg_uid) {
1458 g_free (priv->msg_uid);
1459 priv->msg_uid = NULL;
1462 /* we should set a reference to the incoming message if it is a draft */
1463 msg_folder = tny_msg_get_folder (msg);
1465 if (modest_tny_folder_is_local_folder (msg_folder)) {
1466 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1467 if (type == TNY_FOLDER_TYPE_INVALID)
1468 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1470 if (type == TNY_FOLDER_TYPE_DRAFTS)
1471 priv->draft_msg = g_object_ref(msg);
1472 if (type == TNY_FOLDER_TYPE_OUTBOX)
1473 priv->outbox_msg = g_object_ref(msg);
1474 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1476 g_object_unref (msg_folder);
1486 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1488 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1489 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1490 GtkWidget *placeholder;
1491 GtkWidget *tool_item;
1496 GtkWidget *sizes_menu;
1497 GtkWidget *fonts_menu;
1503 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1504 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1505 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1506 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1508 /* Font color placeholder */
1509 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1510 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1513 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1514 priv->font_color_button = modest_color_button_new ();
1515 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1516 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1517 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1518 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1519 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1520 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1521 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1522 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1524 G_CALLBACK (modest_msg_edit_window_color_button_change),
1527 /* Font size and face placeholder */
1528 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1529 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1531 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1532 priv->size_tool_button_label = gtk_label_new (NULL);
1533 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1534 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1535 size_text, "</span>", NULL);
1536 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1537 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1539 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1540 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1541 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1542 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1543 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1544 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1545 gtk_widget_set_sensitive (arrow, FALSE);
1546 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1547 sizes_menu = gtk_menu_new ();
1548 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1549 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1552 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1553 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1555 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1559 if (wp_font_size[size_index] == 12)
1560 priv->current_size_index = size_index;
1564 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1565 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1566 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1567 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1568 priv->font_size_toolitem = tool_item;
1571 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1572 priv->font_tool_button_label = gtk_label_new (NULL);
1573 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1574 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1575 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1577 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1578 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1579 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1580 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1581 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1582 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1583 gtk_widget_set_sensitive (arrow, FALSE);
1584 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1585 fonts_menu = gtk_menu_new ();
1586 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1587 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1590 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1592 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1593 0, wp_get_font_name (font_index),
1596 if (font_index == DEFAULT_FONT)
1597 priv->current_face_index = font_index;
1599 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1600 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1601 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1602 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1603 priv->font_face_toolitem = tool_item;
1605 /* Set expand and homogeneous for remaining items */
1606 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1607 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1608 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1609 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1610 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1611 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1613 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1614 will not show the tool items added to the placeholders) */
1615 gtk_widget_show_all (parent_priv->toolbar);
1617 /* Set the no show all *after* showing all items. We do not
1618 want the toolbar to be shown with a show all because it
1619 could go agains the gconf setting regarding showing or not
1620 the toolbar of the editor window */
1621 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1627 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1630 ModestWindowPrivate *parent_priv;
1631 ModestMsgEditWindowPrivate *priv;
1632 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1633 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1634 ModestWindowMgr *mgr = NULL;
1636 g_return_val_if_fail (msg, NULL);
1637 g_return_val_if_fail (account_name, NULL);
1639 mgr = modest_runtime_get_window_mgr ();
1641 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1643 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1644 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1646 /* Menubar. Update the state of some toggles */
1647 priv->from_field_protos = get_transports ();
1648 priv->original_mailbox = NULL;
1649 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1650 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1651 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1652 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1653 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) mailbox);
1654 priv->original_mailbox = g_strdup (mailbox);
1655 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1656 /* We set the first mailbox as the active mailbox */
1657 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1658 if (priv->original_mailbox != NULL)
1659 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1660 (gpointer) priv->original_mailbox);
1662 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1663 (gpointer) account_name);
1665 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1667 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1668 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1669 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1671 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1672 hildon_touch_selector_get_current_text
1673 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1674 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1675 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1678 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1680 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1682 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1683 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1685 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1687 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1688 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1689 /* Add common dimming rules */
1690 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1691 modest_msg_edit_window_toolbar_dimming_entries,
1692 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1693 MODEST_WINDOW (obj));
1694 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1695 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1696 MODEST_WINDOW (obj));
1697 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1698 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1699 MODEST_WINDOW (obj));
1700 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1701 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1702 MODEST_WINDOW (obj));
1703 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1704 G_CALLBACK (modest_ui_dimming_rules_on_send),
1705 MODEST_WINDOW (obj));
1706 /* Insert dimming rules group for this window */
1707 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1708 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1710 /* Setup app menu */
1711 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1713 /* Checks the dimming rules */
1714 g_object_unref (toolbar_rules_group);
1715 g_object_unref (clipboard_rules_group);
1716 gtk_widget_hide (priv->priority_icon);
1717 gtk_widget_queue_resize (priv->subject_box);
1718 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1720 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1722 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1723 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1724 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1725 priv->update_caption_visibility = TRUE;
1727 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1729 /* Track account-removed signal, this window should be closed
1730 in the case we're creating a mail associated to the account
1732 priv->account_removed_handler_id =
1733 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1735 G_CALLBACK(on_account_removed),
1738 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1740 return (ModestWindow*) obj;
1744 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1746 GString **string_buffer = (GString **) user_data;
1748 *string_buffer = g_string_append (*string_buffer, buffer);
1754 * @result: A new string which should be freed with g_free().
1757 get_formatted_data (ModestMsgEditWindow *edit_window)
1759 ModestMsgEditWindowPrivate *priv;
1760 GString *string_buffer = g_string_new ("");
1762 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1764 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1766 modest_text_utils_hyperlinkify (string_buffer);
1768 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1770 return g_string_free (string_buffer, FALSE);
1775 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1778 const gchar *account_name;
1779 ModestMsgEditWindowPrivate *priv;
1780 TnyIterator *att_iter;
1781 const gchar *picker_active_id;
1783 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1785 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1787 picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1788 g_return_val_if_fail (picker_active_id, NULL);
1789 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1791 /* don't free these (except from) */
1792 data = g_slice_new0 (MsgData);
1793 data->from = g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1794 data->account_name = g_strdup (account_name);
1795 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1796 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1797 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1798 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1799 data->references = g_strdup (priv->references);
1800 data->in_reply_to = g_strdup (priv->in_reply_to);
1801 if (priv->draft_msg) {
1802 data->draft_msg = g_object_ref (priv->draft_msg);
1803 } else if (priv->outbox_msg) {
1804 data->draft_msg = g_object_ref (priv->outbox_msg);
1806 data->draft_msg = NULL;
1809 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1811 gtk_text_buffer_get_bounds (buf, &b, &e);
1812 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1814 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1815 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1817 data->html_body = NULL;
1819 /* deep-copy the data */
1820 att_iter = tny_list_create_iterator (priv->attachments);
1821 data->attachments = NULL;
1822 while (!tny_iterator_is_done (att_iter)) {
1823 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1824 if (!(TNY_IS_MIME_PART(part))) {
1825 g_warning ("strange data in attachment list");
1826 g_object_unref (part);
1827 tny_iterator_next (att_iter);
1830 data->attachments = g_list_append (data->attachments,
1832 tny_iterator_next (att_iter);
1834 g_object_unref (att_iter);
1836 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1837 att_iter = tny_list_create_iterator (priv->images);
1838 data->images = NULL;
1839 while (!tny_iterator_is_done (att_iter)) {
1840 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1842 if (!(TNY_IS_MIME_PART(part))) {
1843 g_warning ("strange data in attachment list");
1844 g_object_unref (part);
1845 tny_iterator_next (att_iter);
1848 cid = tny_mime_part_get_content_id (part);
1850 gchar *image_tag_id;
1851 GtkTextTag *image_tag;
1853 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1854 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1855 g_free (image_tag_id);
1857 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1859 ((gtk_text_iter_has_tag (&iter, image_tag))||
1860 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1861 data->images = g_list_append (data->images,
1862 g_object_ref (part));
1864 g_object_unref (part);
1865 tny_iterator_next (att_iter);
1867 g_object_unref (att_iter);
1869 data->priority_flags = priv->priority_flags;
1876 unref_gobject (GObject *obj, gpointer data)
1878 if (!G_IS_OBJECT(obj))
1880 g_object_unref (obj);
1884 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1887 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1895 g_free (data->from);
1896 g_free (data->subject);
1897 g_free (data->plain_body);
1898 g_free (data->html_body);
1899 g_free (data->account_name);
1900 g_free (data->references);
1901 g_free (data->in_reply_to);
1903 if (data->draft_msg != NULL) {
1904 g_object_unref (data->draft_msg);
1905 data->draft_msg = NULL;
1908 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1909 g_list_free (data->attachments);
1910 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1911 g_list_free (data->images);
1913 g_slice_free (MsgData, data);
1917 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1919 guint64 *parts_size)
1921 ModestMsgEditWindowPrivate *priv;
1923 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1925 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1927 /* TODO: add images */
1928 *parts_size += priv->images_size;
1929 *parts_count += priv->images_count;
1934 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1937 ModestMsgEditWindowPrivate *priv = NULL;
1938 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1940 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1942 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1944 return MODEST_MSG_EDIT_FORMAT_HTML;
1946 return MODEST_MSG_EDIT_FORMAT_TEXT;
1950 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1951 ModestMsgEditFormat format)
1953 ModestMsgEditWindowPrivate *priv;
1954 ModestWindowPrivate *parent_priv;
1956 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1957 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1958 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1961 case MODEST_MSG_EDIT_FORMAT_HTML:
1962 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1963 update_signature (self, priv->last_from_account, priv->last_from_account);
1964 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
1966 case MODEST_MSG_EDIT_FORMAT_TEXT:
1967 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1968 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
1971 g_return_if_reached ();
1975 ModestMsgEditFormatState *
1976 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1978 ModestMsgEditFormatState *format_state = NULL;
1979 ModestMsgEditWindowPrivate *priv;
1980 WPTextBufferFormat *buffer_format;
1982 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1984 buffer_format = g_new0 (WPTextBufferFormat, 1);
1985 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1987 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1989 format_state = g_new0 (ModestMsgEditFormatState, 1);
1990 format_state->bold = buffer_format->bold&0x1;
1991 format_state->italics = buffer_format->italic&0x1;
1992 format_state->bullet = buffer_format->bullet&0x1;
1993 format_state->color = buffer_format->color;
1994 format_state->font_size = buffer_format->font_size;
1995 format_state->font_family = wp_get_font_name (buffer_format->font);
1996 format_state->justification = buffer_format->justification;
1997 g_free (buffer_format);
1999 return format_state;
2004 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2005 const ModestMsgEditFormatState *format_state)
2007 ModestMsgEditWindowPrivate *priv;
2008 WPTextBufferFormat *buffer_format;
2009 WPTextBufferFormat *current_format;
2011 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2012 g_return_if_fail (format_state != NULL);
2014 buffer_format = g_new0 (WPTextBufferFormat, 1);
2015 current_format = g_new0 (WPTextBufferFormat, 1);
2017 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2018 gtk_widget_grab_focus (priv->msg_body);
2019 buffer_format->bold = (format_state->bold != FALSE);
2020 buffer_format->italic = (format_state->italics != FALSE);
2021 buffer_format->color = format_state->color;
2022 buffer_format->font_size = format_state->font_size;
2023 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2024 buffer_format->justification = format_state->justification;
2025 buffer_format->bullet = format_state->bullet;
2027 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2029 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2030 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2031 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2032 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2033 buffer_format->cs.font = (buffer_format->font != current_format->font);
2034 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2035 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2037 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2038 if (buffer_format->cs.bold) {
2039 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2040 GINT_TO_POINTER (buffer_format->bold&0x1));
2042 if (buffer_format->cs.italic) {
2043 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2044 GINT_TO_POINTER (buffer_format->italic&0x1));
2046 if (buffer_format->cs.color) {
2047 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2048 GINT_TO_POINTER (&(buffer_format->color)));
2050 if (buffer_format->cs.font_size) {
2051 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2052 GINT_TO_POINTER (buffer_format->font_size));
2054 if (buffer_format->cs.justification) {
2055 switch (buffer_format->justification) {
2056 case GTK_JUSTIFY_LEFT:
2057 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2058 GINT_TO_POINTER(TRUE));
2060 case GTK_JUSTIFY_CENTER:
2061 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2062 GINT_TO_POINTER(TRUE));
2064 case GTK_JUSTIFY_RIGHT:
2065 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2066 GINT_TO_POINTER(TRUE));
2073 if (buffer_format->cs.font) {
2074 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2075 GINT_TO_POINTER (buffer_format->font));
2077 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2078 if (buffer_format->cs.bullet) {
2079 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2080 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2082 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2084 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2086 g_free (buffer_format);
2087 g_free (current_format);
2089 /* Check dimming rules */
2090 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2091 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2095 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2097 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2099 ModestWindowPrivate *parent_priv;
2100 ModestMsgEditWindowPrivate *priv;
2102 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2103 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2105 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2106 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2107 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2108 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2110 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2111 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2112 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2115 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2117 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2118 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2120 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2121 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2123 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2124 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2127 switch (buffer_format->justification)
2129 case GTK_JUSTIFY_LEFT:
2130 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2132 case GTK_JUSTIFY_CENTER:
2133 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2135 case GTK_JUSTIFY_RIGHT:
2136 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2143 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2145 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2146 G_CALLBACK (modest_msg_edit_window_color_button_change),
2148 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2149 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2150 G_CALLBACK (modest_msg_edit_window_color_button_change),
2153 if (priv->current_size_index != buffer_format->font_size) {
2157 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2158 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2162 priv->current_size_index = buffer_format->font_size;
2164 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2165 markup = g_strconcat ("<span font_family='Sans'>",
2166 size_text, "</span>", NULL);
2168 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2172 gtk_tree_path_free (path);
2175 if (priv->current_face_index != buffer_format->font) {
2179 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2180 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2184 priv->current_face_index = buffer_format->font;
2185 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2186 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2187 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2194 g_free (buffer_format);
2200 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2202 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2203 ModestMsgEditWindowPrivate *priv;
2204 GtkWidget *dialog = NULL;
2206 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2207 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2209 dialog = hildon_color_chooser_new ();
2210 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2211 g_free (buffer_format);
2213 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2215 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2216 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2219 gtk_widget_destroy (dialog);
2224 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2226 ModestMsgEditWindowPrivate *priv;
2227 GtkWidget *dialog = NULL;
2228 GdkColor *old_color = NULL;
2230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2231 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2233 dialog = hildon_color_chooser_new ();
2234 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2236 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2238 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2239 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2241 gtk_widget_destroy (dialog);
2246 create_stream_for_uri (const gchar* uri)
2251 TnyStream *result = NULL;
2253 GnomeVFSHandle *handle = NULL;
2254 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2255 if (test == GNOME_VFS_OK) {
2256 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2257 /* Streams over OBEX (Bluetooth) are not seekable but
2258 * we expect them to be (we might need to read them
2259 * several times). So if this is a Bluetooth URI just
2260 * read the whole file into memory (this is not a fast
2261 * protocol so we can assume that these files are not
2262 * going to be very big) */
2263 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2264 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2265 TnyStream *memstream = tny_camel_mem_stream_new ();
2266 tny_stream_write_to_stream (vfssstream, memstream);
2267 g_object_unref (vfssstream);
2270 result = vfssstream;
2278 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2281 ModestMsgEditWindowPrivate *priv;
2282 GtkWidget *dialog = NULL;
2284 GSList *uris = NULL;
2285 GSList *uri_node = NULL;
2287 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2289 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2290 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2291 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2293 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2295 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2296 GTK_WINDOW (dialog), GTK_WINDOW (window));
2298 response = gtk_dialog_run (GTK_DIALOG (dialog));
2300 case GTK_RESPONSE_OK:
2302 gchar *current_folder;
2303 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2304 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2305 if (current_folder && current_folder != '\0') {
2307 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2308 current_folder, &err);
2310 g_debug ("Error storing latest used folder: %s", err->message);
2314 g_free (current_folder);
2320 gtk_widget_destroy (dialog);
2322 g_object_ref (window);
2323 /* The operation could take some time so allow the dialog to be closed */
2324 while (gtk_events_pending ())
2325 gtk_main_iteration ();
2327 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2329 GnomeVFSHandle *handle = NULL;
2330 GnomeVFSResult result;
2331 GtkTextIter position;
2332 GtkTextMark *insert_mark;
2334 uri = (const gchar *) uri_node->data;
2335 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2336 if (result == GNOME_VFS_OK) {
2338 GnomeVFSFileInfo *info;
2339 gchar *filename, *basename, *escaped_filename;
2340 TnyMimePart *mime_part;
2342 const gchar *mime_type = NULL;
2343 GnomeVFSURI *vfs_uri;
2344 guint64 stream_size;
2346 gnome_vfs_close (handle);
2347 vfs_uri = gnome_vfs_uri_new (uri);
2349 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2350 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2351 g_free (escaped_filename);
2352 gnome_vfs_uri_unref (vfs_uri);
2353 info = gnome_vfs_file_info_new ();
2355 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2356 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2358 mime_type = gnome_vfs_file_info_get_mime_type (info);
2360 mime_part = tny_platform_factory_new_mime_part
2361 (modest_runtime_get_platform_factory ());
2363 TnyStream *stream = create_stream_for_uri (uri);
2365 if (stream == NULL) {
2367 modest_platform_information_banner (NULL, NULL,
2368 _FM("sfil_ib_opening_not_allowed"));
2370 g_object_unref (mime_part);
2371 gnome_vfs_file_info_unref (info);
2375 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2377 content_id = g_strdup_printf ("%d", priv->next_cid);
2378 tny_mime_part_set_content_id (mime_part, content_id);
2379 g_free (content_id);
2382 basename = g_path_get_basename (filename);
2383 tny_mime_part_set_filename (mime_part, basename);
2386 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2388 if (pixbuf != NULL) {
2389 priv->images_size += stream_size;
2390 priv->images_count ++;
2391 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2392 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2393 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2394 tny_mime_part_get_content_id (mime_part), pixbuf);
2395 g_object_unref (pixbuf);
2397 tny_list_prepend (priv->images, (GObject *) mime_part);
2398 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2400 modest_platform_information_banner (NULL, NULL,
2401 _("mail_ib_file_operation_failed"));
2405 g_object_unref (mime_part);
2406 gnome_vfs_file_info_unref (info);
2410 g_object_unref (window);
2414 on_attach_file_response (GtkDialog *dialog,
2418 GSList *uris = NULL;
2420 GnomeVFSFileSize total_size, allowed_size;
2421 ModestMsgEditWindow *window;
2422 ModestMsgEditWindowPrivate *priv;
2427 case GTK_RESPONSE_OK:
2429 gchar *current_folder;
2431 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2432 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2433 if (current_folder && current_folder != '\0') {
2435 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2436 current_folder, &err);
2438 g_debug ("Error storing latest used folder: %s", err->message);
2442 g_free (current_folder);
2449 window = MODEST_MSG_EDIT_WINDOW (user_data);
2450 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2452 /* allowed size is the maximum size - what's already there */
2453 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2454 &att_num, &att_size);
2455 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2458 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2460 const gchar *uri = (const gchar *) uri_node->data;
2463 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2465 if (total_size > allowed_size) {
2466 g_debug ("%s: total size: %u",
2467 __FUNCTION__, (unsigned int)total_size);
2470 allowed_size -= total_size;
2472 g_slist_foreach (uris, (GFunc) g_free, NULL);
2473 g_slist_free (uris);
2475 gtk_widget_destroy (GTK_WIDGET (dialog));
2479 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2481 GtkWidget *dialog = NULL;
2482 ModestMsgEditWindowPrivate *priv;
2485 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2487 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2489 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2492 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2493 GTK_FILE_CHOOSER_ACTION_OPEN);
2494 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2495 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2496 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2497 if (conf_folder && conf_folder[0] != '\0') {
2498 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2501 /* Set the default folder to documents folder */
2502 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2505 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2506 ".documents", NULL);
2508 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2509 g_free (docs_folder);
2511 g_free (conf_folder);
2512 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2513 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2514 GTK_WINDOW (dialog), GTK_WINDOW (window));
2516 /* Connect to response & show */
2517 g_signal_connect (dialog, "response",
2518 G_CALLBACK (on_attach_file_response), window);
2519 gtk_widget_show (dialog);
2524 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2526 GnomeVFSFileSize allowed_size)
2529 GnomeVFSHandle *handle = NULL;
2530 ModestMsgEditWindowPrivate *priv;
2531 GnomeVFSResult result;
2532 GnomeVFSFileSize size = 0;
2533 g_return_val_if_fail (window, 0);
2534 g_return_val_if_fail (uri, 0);
2536 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2538 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2539 if (result == GNOME_VFS_OK) {
2540 TnyMimePart *mime_part;
2542 const gchar *mime_type = NULL;
2544 gchar *escaped_filename;
2547 GnomeVFSFileInfo *info;
2548 GnomeVFSURI *vfs_uri;
2550 gnome_vfs_close (handle);
2551 vfs_uri = gnome_vfs_uri_new (uri);
2554 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2555 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2556 g_free (escaped_filename);
2557 gnome_vfs_uri_unref (vfs_uri);
2559 info = gnome_vfs_file_info_new ();
2561 if (gnome_vfs_get_file_info (uri,
2563 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2565 mime_type = gnome_vfs_file_info_get_mime_type (info);
2566 mime_part = tny_platform_factory_new_mime_part
2567 (modest_runtime_get_platform_factory ());
2569 /* try to get the attachment's size; this may fail for weird
2570 * file systems, like obex, upnp... */
2571 if (allowed_size != 0 &&
2572 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2574 if (size > allowed_size) {
2575 modest_platform_information_banner (NULL, NULL,
2576 _("mail_ib_error_attachment_size"));
2581 g_debug ("%s: could not get attachment size", __FUNCTION__);
2583 stream = create_stream_for_uri (uri);
2585 if (stream == NULL) {
2587 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2589 g_object_unref (mime_part);
2591 gnome_vfs_file_info_unref (info);
2595 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2596 g_object_unref (stream);
2598 content_id = g_strdup_printf ("%d", priv->next_cid);
2599 tny_mime_part_set_content_id (mime_part, content_id);
2600 g_free (content_id);
2603 basename = g_path_get_basename (filename);
2604 tny_mime_part_set_filename (mime_part, basename);
2607 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2608 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2610 info->size == 0, info->size);
2611 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2612 gtk_widget_show_all (priv->attachments_caption);
2613 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2615 g_object_unref (mime_part);
2616 gnome_vfs_file_info_unref (info);
2623 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2626 ModestMsgEditWindowPrivate *priv;
2629 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2630 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2632 if (att_list == NULL) {
2633 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2634 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2635 g_object_unref (att_list);
2639 g_object_ref (att_list);
2642 if (tny_list_get_length (att_list) == 0) {
2643 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2645 gboolean dialog_response;
2646 gchar *message = NULL;
2647 gchar *filename = NULL;
2649 if (tny_list_get_length (att_list) == 1) {
2651 iter = tny_list_create_iterator (att_list);
2652 part = (TnyMimePart *) tny_iterator_get_current (iter);
2653 g_object_unref (iter);
2654 if (TNY_IS_MSG (part)) {
2655 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2657 filename = tny_header_dup_subject (header);
2658 g_object_unref (header);
2660 if (filename == NULL) {
2661 filename = g_strdup (_("mail_va_no_subject"));
2664 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2666 g_object_unref (part);
2668 filename = g_strdup ("");
2670 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2671 "emev_nc_delete_attachments",
2672 tny_list_get_length (att_list)), filename);
2675 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2679 if (dialog_response != GTK_RESPONSE_OK) {
2680 g_object_unref (att_list);
2684 for (iter = tny_list_create_iterator (att_list);
2685 !tny_iterator_is_done (iter);
2686 tny_iterator_next (iter)) {
2687 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2688 const gchar *att_id;
2689 tny_list_remove (priv->attachments, (GObject *) mime_part);
2691 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2693 if (tny_list_get_length (priv->attachments) == 0)
2694 gtk_widget_hide (priv->attachments_caption);
2695 att_id = tny_mime_part_get_content_id (mime_part);
2697 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2699 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2700 g_object_unref (mime_part);
2702 g_object_unref (iter);
2705 g_object_unref (att_list);
2707 /* if the last attachment has been removed, focus the Subject: field */
2708 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2709 gtk_widget_grab_focus (priv->subject_field);
2713 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2716 ModestMsgEditWindowPrivate *priv;
2719 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2721 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2723 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2725 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2729 font_size_clicked (GtkToolButton *button,
2730 ModestMsgEditWindow *window)
2732 ModestMsgEditWindowPrivate *priv;
2733 GtkWidget *selector, *dialog;
2735 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2737 selector = hildon_touch_selector_new ();
2738 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2739 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2741 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2742 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2743 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2745 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2749 WPTextBufferFormat format;
2751 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2753 memset (&format, 0, sizeof (format));
2754 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2756 format.cs.font_size = TRUE;
2757 format.cs.text_position = TRUE;
2758 format.cs.font = TRUE;
2759 format.font_size = new_index;
2760 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2762 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2763 GINT_TO_POINTER (new_index)))
2764 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2766 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2767 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2768 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2769 size_text, "</span>", NULL);
2771 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2775 gtk_widget_destroy (dialog);
2777 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2782 font_face_clicked (GtkToolButton *button,
2783 ModestMsgEditWindow *window)
2785 ModestMsgEditWindowPrivate *priv;
2786 GtkWidget *selector, *dialog;
2787 GtkCellRenderer *renderer;
2789 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2791 selector = hildon_touch_selector_new ();
2792 renderer = gtk_cell_renderer_text_new ();
2793 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2794 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2795 renderer, "family", 0, "text", 0, NULL);
2796 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2798 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2799 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2800 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2802 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2803 gint new_font_index;
2807 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2808 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2809 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2813 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2815 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2816 GINT_TO_POINTER(new_font_index)))
2817 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2819 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2820 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2822 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2826 gtk_tree_path_free (path);
2829 gtk_widget_destroy (dialog);
2831 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2836 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2839 ModestMsgEditWindowPrivate *priv = NULL;
2840 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2842 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2843 if (!priv->update_caption_visibility)
2846 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2848 gtk_widget_show (priv->cc_caption);
2850 gtk_widget_hide (priv->cc_caption);
2852 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2856 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2859 ModestMsgEditWindowPrivate *priv = NULL;
2860 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2862 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2863 if (!priv->update_caption_visibility)
2866 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2868 gtk_widget_show (priv->bcc_caption);
2870 gtk_widget_hide (priv->bcc_caption);
2872 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2876 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2877 ModestRecptEditor *editor)
2879 ModestMsgEditWindowPrivate *priv;
2881 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2882 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2884 /* we check for low-mem; in that case, show a warning, and don't allow
2885 * for the addressbook
2887 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2890 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2892 if (editor == NULL) {
2893 GtkWidget *view_focus, *parent;
2894 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2896 /* This code should be kept in sync with ModestRecptEditor. The
2897 textview inside the recpt editor is the one that really gets the
2898 focus. As it's inside a scrolled window, and this one inside the
2899 hbox recpt editor inherits from, we'll need to go up in the
2900 hierarchy to know if the text view is part of the recpt editor
2901 or if it's a different text entry */
2902 parent = gtk_widget_get_parent (view_focus);
2903 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2904 editor = MODEST_RECPT_EDITOR (parent);
2907 editor = MODEST_RECPT_EDITOR (priv->to_field);
2910 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2914 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2916 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2918 modest_msg_edit_window_open_addressbook (window, NULL);
2922 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2923 gboolean show_toolbar)
2925 ModestWindowPrivate *parent_priv;
2926 ModestMsgEditWindowPrivate *priv;
2928 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2929 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2930 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2932 /* We can not just use the code of
2933 modest_msg_edit_window_setup_toolbar because it has a
2934 mixture of both initialization and creation code. */
2936 gint current_format;
2937 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2938 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2939 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2940 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2942 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2945 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2950 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2951 TnyHeaderFlags priority_flags)
2953 ModestMsgEditWindowPrivate *priv;
2954 ModestWindowPrivate *parent_priv;
2956 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2958 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2959 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2961 if (priv->priority_flags != priority_flags) {
2962 GtkAction *priority_action = NULL;
2964 priv->priority_flags = priority_flags;
2966 switch (priority_flags) {
2967 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2968 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2969 MODEST_HEADER_ICON_HIGH,
2970 HILDON_ICON_SIZE_SMALL);
2971 gtk_widget_show (priv->priority_icon);
2972 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2973 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2975 case TNY_HEADER_FLAG_LOW_PRIORITY:
2976 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2977 MODEST_HEADER_ICON_LOW,
2978 HILDON_ICON_SIZE_SMALL);
2979 gtk_widget_show (priv->priority_icon);
2980 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2981 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2984 gtk_widget_hide (priv->priority_icon);
2985 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2986 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2989 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2990 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2992 gtk_widget_queue_resize (priv->subject_box);
2996 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2999 ModestMsgEditWindowPrivate *priv;
3000 ModestWindowPrivate *parent_priv;
3001 gint current_format;
3003 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3005 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3006 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3008 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3009 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3011 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3013 if (current_format != file_format) {
3014 switch (file_format) {
3015 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3016 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3017 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3018 update_signature (window, priv->last_from_account, priv->last_from_account);
3019 if (parent_priv->toolbar)
3020 gtk_widget_show (parent_priv->toolbar);
3022 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3026 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3027 response = gtk_dialog_run (GTK_DIALOG (dialog));
3028 gtk_widget_destroy (dialog);
3029 if (response == GTK_RESPONSE_OK) {
3030 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3031 if (parent_priv->toolbar)
3032 gtk_widget_hide (parent_priv->toolbar);
3034 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3035 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3040 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3041 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3042 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3047 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3050 ModestMsgEditWindowPrivate *priv;
3051 WPTextBufferFormat oldfmt, fmt;
3052 gint old_position = 0;
3056 GdkColor *color = NULL;
3057 gboolean bold, bold_set, italic, italic_set;
3058 gboolean underline, underline_set;
3059 gboolean strikethrough, strikethrough_set;
3060 gboolean position_set;
3061 gboolean font_size_set, font_set, color_set;
3064 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3065 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3067 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3068 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3069 GTK_WINDOW(dialog), GTK_WINDOW (window));
3071 /* First we get the currently selected font information */
3072 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3074 switch (oldfmt.text_position) {
3075 case TEXT_POSITION_NORMAL:
3078 case TEXT_POSITION_SUPERSCRIPT:
3086 g_object_set (G_OBJECT (dialog),
3087 "bold", oldfmt.bold != FALSE,
3088 "bold-set", !oldfmt.cs.bold,
3089 "underline", oldfmt.underline != FALSE,
3090 "underline-set", !oldfmt.cs.underline,
3091 "italic", oldfmt.italic != FALSE,
3092 "italic-set", !oldfmt.cs.italic,
3093 "strikethrough", oldfmt.strikethrough != FALSE,
3094 "strikethrough-set", !oldfmt.cs.strikethrough,
3095 "color", &oldfmt.color,
3096 "color-set", !oldfmt.cs.color,
3097 "size", wp_font_size[oldfmt.font_size],
3098 "size-set", !oldfmt.cs.font_size,
3099 "position", old_position,
3100 "position-set", !oldfmt.cs.text_position,
3101 "family", wp_get_font_name (oldfmt.font),
3102 "family-set", !oldfmt.cs.font,
3105 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3106 GTK_WINDOW (dialog), GTK_WINDOW (window));
3107 gtk_widget_show_all (dialog);
3108 priv->font_dialog = dialog;
3109 response = gtk_dialog_run (GTK_DIALOG (dialog));
3110 priv->font_dialog = NULL;
3111 if (response == GTK_RESPONSE_OK) {
3113 g_object_get( dialog,
3115 "bold-set", &bold_set,
3116 "underline", &underline,
3117 "underline-set", &underline_set,
3119 "italic-set", &italic_set,
3120 "strikethrough", &strikethrough,
3121 "strikethrough-set", &strikethrough_set,
3123 "color-set", &color_set,
3125 "size-set", &font_size_set,
3126 "family", &font_name,
3127 "family-set", &font_set,
3128 "position", &position,
3129 "position-set", &position_set,
3134 if (response == GTK_RESPONSE_OK) {
3135 memset(&fmt, 0, sizeof(fmt));
3141 fmt.italic = italic;
3142 fmt.cs.italic = TRUE;
3144 if (underline_set) {
3145 fmt.underline = underline;
3146 fmt.cs.underline = TRUE;
3148 if (strikethrough_set) {
3149 fmt.strikethrough = strikethrough;
3150 fmt.cs.strikethrough = TRUE;
3155 ? TEXT_POSITION_NORMAL
3156 : ( ( position == 1 )
3157 ? TEXT_POSITION_SUPERSCRIPT
3158 : TEXT_POSITION_SUBSCRIPT );
3159 fmt.cs.text_position = TRUE;
3160 fmt.font_size = oldfmt.font_size;
3164 fmt.cs.color = TRUE;
3167 fmt.font = wp_get_font_index(font_name,
3172 if (font_size_set) {
3173 fmt.cs.font_size = TRUE;
3174 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3176 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3177 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3179 gtk_widget_destroy (dialog);
3181 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3185 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3187 ModestMsgEditWindowPrivate *priv;
3188 ModestWindowPrivate *parent_priv;
3189 gboolean was_rich_text, is_rich_text;
3191 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3192 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3193 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3195 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3197 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3199 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3201 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3203 gtk_widget_show (parent_priv->toolbar);
3205 gtk_widget_hide (parent_priv->toolbar);
3208 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3209 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3213 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3215 ModestMsgEditWindowPrivate *priv;
3217 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3218 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3220 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3222 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3223 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3228 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3230 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3232 priv->can_undo = can_undo;
3236 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3238 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3240 priv->can_redo = can_redo;
3244 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3246 ModestMsgEditWindowPrivate *priv;
3247 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3248 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3250 return priv->can_undo;
3254 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3256 ModestMsgEditWindowPrivate *priv;
3257 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3258 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3260 return priv->can_redo;
3265 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3268 GtkTextIter match_start, match_end;
3270 if (image_id == NULL)
3273 gtk_text_buffer_get_start_iter (buffer, &iter);
3275 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3276 GSList *tags = gtk_text_iter_get_tags (&match_start);
3278 for (node = tags; node != NULL; node = g_slist_next (node)) {
3279 GtkTextTag *tag = (GtkTextTag *) node->data;
3280 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3281 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3282 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3284 offset = gtk_text_iter_get_offset (&match_start);
3285 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3286 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3290 gtk_text_iter_forward_char (&iter);
3295 message_is_empty (ModestMsgEditWindow *window)
3297 ModestMsgEditWindowPrivate *priv = NULL;
3299 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3300 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3302 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3303 * so we can ignore markup.
3305 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3308 count = gtk_text_buffer_get_char_count (buf);
3314 msg_body_focus (GtkWidget *focus,
3315 GdkEventFocus *event,
3319 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3320 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3321 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3326 recpt_field_changed (GtkTextBuffer *buffer,
3327 ModestMsgEditWindow *editor)
3329 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3330 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3334 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3336 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3337 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3341 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3344 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3345 GtkTextBuffer *buffer;
3347 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3348 gtk_text_buffer_set_modified (buffer, modified);
3349 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3350 gtk_text_buffer_set_modified (buffer, modified);
3351 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3352 gtk_text_buffer_set_modified (buffer, modified);
3353 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3357 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3359 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3360 const char *account_name;
3361 GtkTextBuffer *buffer;
3363 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3364 if (gtk_text_buffer_get_modified (buffer))
3366 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3367 if (gtk_text_buffer_get_modified (buffer))
3369 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3370 if (gtk_text_buffer_get_modified (buffer))
3372 if (gtk_text_buffer_get_modified (priv->text_buffer))
3375 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3376 if (priv->original_mailbox) {
3377 if (!account_name || strcmp (account_name, priv->original_mailbox))
3379 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3390 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3392 ModestMsgEditWindowPrivate *priv = NULL;
3393 GSList *address_list = NULL;
3395 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3396 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3398 /* check if there's no recipient added */
3399 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3400 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3401 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3402 /* no recipient contents, then select contacts */
3403 modest_msg_edit_window_open_addressbook (window, NULL);
3408 g_object_ref (window);
3409 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3410 (add_to_addressbook) ? &address_list : NULL)) {
3411 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3412 g_object_unref (window);
3415 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3416 (add_to_addressbook) ? &address_list : NULL)) {
3417 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3418 g_object_unref (window);
3421 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3422 (add_to_addressbook) ? &address_list : NULL)) {
3423 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3424 g_object_unref (window);
3428 /* Add contacts to address book */
3429 if (add_to_addressbook && address_list)
3430 modest_address_book_add_address_list (address_list);
3432 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3433 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3434 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3435 g_object_unref (window);
3442 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3444 GSList *recipients = NULL;
3445 ModestMsgEditWindowPrivate *priv;
3446 gchar *joined, *after_remove, *to, *cc, *bcc;
3448 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3450 /* First of all check names */
3451 if (!modest_msg_edit_window_check_names (self, FALSE))
3454 if (!modest_msg_edit_window_has_pending_addresses (self))
3457 /* Don't add the from obviously */
3458 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3459 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3460 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3462 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3467 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3470 recipients = modest_text_utils_split_addresses_list (after_remove);
3471 g_free (after_remove);
3474 /* Offer the user to add recipients to the address book */
3475 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3476 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3481 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3482 ModestMsgEditWindow *window)
3484 modest_msg_edit_window_offer_attach_file (window);
3488 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3490 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3492 return priv->clipboard_text;
3496 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3498 ModestMsgEditWindow *window)
3500 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3501 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3504 /* It could happen that the window was already closed */
3505 if (!GTK_WIDGET_VISIBLE (window))
3508 g_object_ref (window);
3509 text = gtk_clipboard_wait_for_text (selection_clipboard);
3511 if (priv->clipboard_text != NULL) {
3512 g_free (priv->clipboard_text);
3514 priv->clipboard_text = text;
3516 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3518 g_object_unref (window);
3521 static gboolean clipboard_owner_change_idle (gpointer userdata)
3523 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3524 ModestMsgEditWindowPrivate *priv;
3526 gdk_threads_enter ();
3527 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3528 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3530 priv->clipboard_owner_idle = 0;
3531 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3532 gdk_threads_leave ();
3538 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3540 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3541 if (priv->clipboard_owner_idle == 0) {
3542 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3543 clipboard_owner_change_idle,
3544 g_object_ref (window),
3550 subject_field_move_cursor (GtkEntry *entry,
3551 GtkMovementStep step,
3556 /* It could happen that the window was already closed */
3557 if (!GTK_WIDGET_VISIBLE (window))
3560 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3564 update_window_title (ModestMsgEditWindow *window)
3566 ModestMsgEditWindowPrivate *priv = NULL;
3567 const gchar *subject;
3569 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3570 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3571 if (subject == NULL || subject[0] == '\0')
3572 subject = _("mail_va_new_email");
3574 gtk_window_set_title (GTK_WINDOW (window), subject);
3580 body_insert_text (GtkTextBuffer *buffer,
3581 GtkTextIter *location,
3584 ModestMsgEditWindow *window)
3586 GtkTextIter end_iter;
3593 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3595 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3597 offset = gtk_text_iter_get_offset (&end_iter);
3598 line = gtk_text_iter_get_line (&end_iter);
3602 while (text_offset < text + len) {
3603 if (*text_offset == '\n')
3605 if (text_lines + line >= MAX_BODY_LINES) {
3606 len = text_offset - text;
3612 utf8_len = g_utf8_strlen (text, len);
3614 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3615 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3616 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3621 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3623 /* Prevent endless recursion */
3624 result = g_strndup (text, utf8_end - text);
3625 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3626 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3627 (gpointer) result, (gpointer) (utf8_end - text),
3629 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3633 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3634 if (priv->max_chars_banner == NULL) {
3635 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3636 _CS("ckdg_ib_maximum_characters_reached"));
3637 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3643 subject_field_changed (GtkEditable *editable,
3644 ModestMsgEditWindow *window)
3646 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3647 update_window_title (window);
3648 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3649 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3650 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3653 subject_field_insert_text (GtkEditable *editable,
3655 gint new_text_length,
3657 ModestMsgEditWindow *window)
3659 GString *result = g_string_new ("");
3661 gint result_len = 0;
3662 const gchar *entry_text = NULL;
3665 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3666 old_length = g_utf8_strlen (entry_text, -1);
3668 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3669 gunichar c = g_utf8_get_char_validated (current, 8);
3670 /* Invalid unichar, stop */
3676 result = g_string_append_unichar (result, c);
3680 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3681 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3684 /* Prevent endless recursion */
3685 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3686 g_signal_emit_by_name (editable, "insert-text",
3687 (gpointer) result->str, (gpointer) result->len,
3688 (gpointer) position, (gpointer) window);
3689 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3693 if (result_len + old_length > 1000) {
3694 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3695 _CS("ckdg_ib_maximum_characters_reached"));
3697 g_string_free (result, TRUE);
3701 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3704 ModestMsgEditWindowPrivate *priv = NULL;
3706 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3707 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3709 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3712 gtk_widget_show_all (priv->find_toolbar);
3713 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3715 gtk_widget_hide_all (priv->find_toolbar);
3716 gtk_widget_grab_focus (priv->msg_body);
3721 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3723 GtkTextIter *match_start,
3724 GtkTextIter *match_end)
3726 GtkTextIter end_iter;
3727 gchar *str_casefold;
3730 gchar *range_casefold;
3733 gboolean result = FALSE;
3740 gtk_text_iter_forward_to_end (&end_iter);
3742 str_casefold = g_utf8_casefold (str, -1);
3743 str_chars_n = strlen (str);
3745 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3746 range_casefold = g_utf8_casefold (range_text, -1);
3747 range_chars_n = strlen (range_casefold);
3749 if (range_chars_n < str_chars_n) {
3750 g_free (str_casefold);
3751 g_free (range_text);
3752 g_free (range_casefold);
3756 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3757 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3758 if (!g_utf8_collate (range_subtext, str_casefold)) {
3759 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3761 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3762 match_start, match_end, NULL)) {
3763 g_debug ("Matched string with collate, but not matched in model");
3765 g_free (found_text);
3767 g_free (range_subtext);
3771 g_free (str_casefold);
3772 g_free (range_text);
3773 g_free (range_casefold);
3780 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3781 ModestMsgEditWindow *window)
3783 gchar *current_search = NULL;
3784 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3786 GtkTextIter selection_start, selection_end;
3787 GtkTextIter match_start, match_end;
3788 gboolean continue_search = FALSE;
3790 if (message_is_empty (window)) {
3791 g_free (priv->last_search);
3792 priv->last_search = NULL;
3793 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3797 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3798 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3799 g_free (current_search);
3800 g_free (priv->last_search);
3801 priv->last_search = NULL;
3802 /* Information banner about empty search */
3803 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3807 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3808 continue_search = TRUE;
3810 g_free (priv->last_search);
3811 priv->last_search = g_strdup (current_search);
3814 if (continue_search) {
3815 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3816 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3817 &match_start, &match_end);
3819 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3821 GtkTextIter buffer_start;
3822 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3823 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3824 &match_start, &match_end);
3826 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3829 /* Mark as selected the string found in search */
3831 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3832 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3833 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3835 g_free (priv->last_search);
3836 priv->last_search = NULL;
3838 g_free (current_search);
3842 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3844 ModestMsgEditWindowPrivate *priv;
3846 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3851 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3854 ModestMsgEditWindowPrivate *priv;
3856 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3861 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3862 ModestMsgEditWindow *window)
3864 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3868 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3871 ModestMsgEditWindowPrivate *priv;
3872 TnyHeader *header = NULL;
3874 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3875 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3877 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3879 if (priv->draft_msg != NULL) {
3880 g_object_unref (priv->draft_msg);
3883 if (draft != NULL) {
3884 g_object_ref (draft);
3885 header = tny_msg_get_header (draft);
3886 if (priv->msg_uid) {
3887 g_free (priv->msg_uid);
3888 priv->msg_uid = NULL;
3890 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3893 priv->draft_msg = draft;
3897 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3898 GtkTextIter *start, GtkTextIter *end,
3901 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3902 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3905 if (tag == NULL) return;
3906 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3907 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3908 replace_with_images (window, priv->images);
3913 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3916 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3918 g_return_if_fail (TNY_IS_MIME_PART (part));
3919 tny_list_prepend (priv->attachments, (GObject *) part);
3920 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3921 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3922 gtk_widget_show_all (priv->attachments_caption);
3923 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3927 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3929 ModestMsgEditWindowPrivate *priv;
3931 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3932 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3934 return priv->msg_uid;
3938 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3939 ModestMsgEditWindowWidgetType widget_type)
3941 ModestMsgEditWindowPrivate *priv;
3943 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3944 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3946 switch (widget_type) {
3947 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3948 return priv->msg_body;
3950 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3951 return priv->to_field;
3953 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3954 return priv->cc_field;
3956 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3957 return priv->bcc_field;
3959 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3960 return priv->subject_field;
3962 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3963 return priv->attachments_view;
3971 remove_tags (WPTextBuffer *buffer)
3973 GtkTextIter start, end;
3975 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3976 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3978 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3982 on_account_removed (TnyAccountStore *account_store,
3983 TnyAccount *account,
3986 /* Do nothing if it's a store account, because we use the
3987 transport to send the messages */
3988 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3989 const gchar *parent_acc = NULL;
3990 const gchar *our_acc = NULL;
3992 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3993 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3994 /* Close this window if I'm showing a message of the removed account */
3995 if (strcmp (parent_acc, our_acc) == 0)
3996 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4001 update_signature (ModestMsgEditWindow *self,
4002 const gchar *old_account,
4003 const gchar *new_account)
4005 ModestMsgEditWindowPrivate *priv;
4006 gboolean has_old_signature, has_new_signature;
4008 ModestAccountMgr *mgr;
4011 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4013 gtk_text_buffer_begin_user_action (priv->text_buffer);
4015 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4016 mgr = modest_runtime_get_account_mgr ();
4020 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4021 if (has_old_signature) {
4022 GtkTextIter match_start, match_end;
4024 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4025 seems that the search has some problems
4026 with the blank space at the end */
4027 if (gtk_text_iter_forward_search (&iter, "--",
4028 GTK_TEXT_SEARCH_TEXT_ONLY,
4029 &match_start, NULL, NULL)) {
4030 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4031 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4033 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4034 &match_start, &match_end, NULL)) {
4038 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4043 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4044 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4045 if (has_new_signature) {
4048 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4049 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4051 is_rich = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
4053 WPTextBufferFormat *fmt;
4054 GdkColor style_color;
4055 if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
4056 gdk_color_parse ("grey", &style_color);
4058 fmt = g_new0 (WPTextBufferFormat, 1);
4059 fmt->color = style_color;
4060 fmt->cs.color = 0x1;
4061 wp_text_buffer_insert_with_attribute (WP_TEXT_BUFFER (priv->text_buffer), &iter,
4065 g_free (full_signature);
4067 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4071 gtk_text_buffer_end_user_action (priv->text_buffer);
4074 static void update_branding (ModestMsgEditWindow *self,
4075 const gchar *new_account)
4077 ModestMsgEditWindowPrivate *priv;
4078 ModestAccountMgr *mgr;
4079 const GdkPixbuf *new_icon = NULL;
4080 gchar *new_label = NULL;
4081 gboolean show = FALSE;
4083 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4085 mgr = modest_runtime_get_account_mgr ();
4087 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4089 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4090 gtk_widget_show (priv->brand_icon);
4093 gtk_widget_hide (priv->brand_icon);
4096 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4097 gtk_widget_show (priv->brand_label);
4101 gtk_widget_hide (priv->brand_label);
4105 gtk_widget_show (priv->brand_container);
4107 gtk_widget_hide (priv->brand_container);
4111 from_field_changed (HildonPickerButton *button,
4112 ModestMsgEditWindow *self)
4114 ModestMsgEditWindowPrivate *priv;
4115 gchar *old_account, *new_account;
4117 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4119 old_account = priv->last_from_account;
4120 new_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4123 g_warning ("%s, could not get the new account", __FUNCTION__);
4127 /* If the From is the same do nothing */
4128 if (old_account && new_account && !strcmp (old_account, new_account))
4131 priv->last_from_account = new_account;
4133 update_signature (self, old_account, new_account);
4134 update_branding (self, new_account);
4138 typedef struct _MessageSettingsHelper {
4139 ModestMsgEditWindow *window;
4140 GSList *priority_group;
4141 GSList *format_group;
4142 GtkToggleButton *current_priority;
4143 GtkToggleButton *current_format;
4144 } MessageSettingsHelper;
4147 on_priority_toggle (GtkToggleButton *button,
4148 MessageSettingsHelper *helper)
4151 ModestMsgEditWindowPrivate *priv;
4153 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4154 if (gtk_toggle_button_get_active (button)) {
4156 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4157 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4158 if ((node_button != button) &&
4159 gtk_toggle_button_get_active (node_button)) {
4160 gtk_toggle_button_set_active (node_button, FALSE);
4163 helper->current_priority = button;
4165 gboolean found = FALSE;
4166 /* If no one is active, activate it again */
4167 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4168 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4169 if (gtk_toggle_button_get_active (node_button)) {
4175 gtk_toggle_button_set_active (button, TRUE);
4181 on_format_toggle (GtkToggleButton *button,
4182 MessageSettingsHelper *helper)
4185 ModestMsgEditWindowPrivate *priv;
4187 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4188 if (gtk_toggle_button_get_active (button)) {
4190 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4191 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4192 if ((node_button != button) &&
4193 gtk_toggle_button_get_active (node_button)) {
4194 gtk_toggle_button_set_active (node_button, FALSE);
4197 helper->current_format = button;
4199 gboolean found = FALSE;
4200 /* If no one is active, activate it again */
4201 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4202 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4203 if (gtk_toggle_button_get_active (node_button)) {
4209 gtk_toggle_button_set_active (button, TRUE);
4216 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4221 GtkWidget *priority_hbox;
4222 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4223 GtkWidget *captioned;
4224 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4225 GtkWidget *format_hbox;
4226 GtkWidget *html_toggle, *text_toggle;
4227 ModestMsgEditWindowPrivate *priv;
4228 MessageSettingsHelper helper = {0,};
4230 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4231 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4232 helper.window = window;
4233 helper.priority_group = NULL;
4234 helper.format_group = NULL;
4236 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4237 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4239 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4240 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4241 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4242 vbox = gtk_vbox_new (FALSE, 0);
4243 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4244 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4245 gtk_container_add (GTK_CONTAINER (align), vbox);
4246 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4247 gtk_widget_show (align);
4248 gtk_widget_show (vbox);
4250 /* Priority toggles */
4251 priority_hbox = gtk_hbox_new (TRUE, 0);
4252 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4253 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4254 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4255 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4256 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4257 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4258 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4259 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4260 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4261 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4262 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4263 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4264 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4265 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4266 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4267 gtk_widget_show_all (priority_hbox);
4268 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4269 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4270 gtk_widget_show (captioned);
4271 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4273 /* format toggles */
4274 format_hbox = gtk_hbox_new (TRUE, 0);
4275 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4276 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4277 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4278 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4279 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4280 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4281 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4282 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4283 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4284 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4285 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4286 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4287 gtk_widget_show_all (format_hbox);
4288 gtk_widget_show (format_hbox);
4289 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4292 g_object_unref (title_sizegroup);
4293 g_object_unref (value_sizegroup);
4295 /* Set current values */
4296 switch (priv->priority_flags) {
4297 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4298 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4299 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4301 case TNY_HEADER_FLAG_LOW_PRIORITY:
4302 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4303 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4306 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4307 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4311 switch (modest_msg_edit_window_get_format (window)) {
4312 case MODEST_MSG_EDIT_FORMAT_TEXT:
4313 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4314 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4316 case MODEST_MSG_EDIT_FORMAT_HTML:
4318 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4319 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4323 /* Signal connects */
4324 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4325 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4326 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4327 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4328 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4330 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4331 GTK_WINDOW (dialog), GTK_WINDOW (window));
4333 /* Save settings if the user clicked on done */
4334 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4335 TnyHeaderFlags flags;
4336 ModestMsgEditFormat old_format, new_format;
4338 /* Set priority flags */
4339 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4340 if (priv->priority_flags != flags)
4341 modest_msg_edit_window_set_priority_flags (window, flags);
4343 /* Set edit format */
4344 old_format = modest_msg_edit_window_get_format (window);
4345 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4346 if (old_format != new_format) {
4347 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4348 modest_msg_edit_window_set_file_format (window, file_format);
4352 gtk_widget_destroy (dialog);
4353 g_slist_free (helper.priority_group);
4357 on_message_settings (GtkAction *action,
4358 ModestMsgEditWindow *window)
4360 modest_msg_edit_window_show_msg_settings_dialog (window);
4364 on_cc_button_toggled (HildonCheckButton *button,
4365 ModestMsgEditWindow *window)
4367 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4369 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4370 hildon_check_button_get_active (button));
4374 on_bcc_button_toggled (HildonCheckButton *button,
4375 ModestMsgEditWindow *window)
4377 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4379 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4380 hildon_check_button_get_active (button));
4384 setup_menu (ModestMsgEditWindow *self)
4386 ModestMsgEditWindowPrivate *priv = NULL;
4388 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4390 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4392 /* Settings menu buttons */
4393 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4394 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4396 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4397 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4398 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4399 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4400 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4401 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4403 priv->cc_button = hildon_check_button_new (0);
4404 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4405 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4407 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4409 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4410 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4411 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4412 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4414 priv->bcc_button = hildon_check_button_new (0);
4415 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4416 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4418 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4420 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4421 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4422 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4423 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4425 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4426 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4427 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4428 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4429 APP_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4431 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4432 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4433 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4434 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4435 APP_MENU_CALLBACK (on_message_settings),
4437 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4438 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4443 emit_open_addressbook (GtkButton *button,
4444 ModestRecptEditor *editor)
4446 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4450 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4451 const gchar *label, GtkWidget *control)
4453 GtkWidget *abook_button;
4456 GtkWidget *label_widget;
4458 box = gtk_hbox_new (FALSE, 0);
4460 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4461 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4463 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4464 label_widget = gtk_label_new (label);
4465 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4466 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4468 gtk_container_add (GTK_CONTAINER (align), abook_button);
4469 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4470 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4471 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4472 if (title_size_group)
4473 gtk_size_group_add_widget (title_size_group, label_widget);
4474 if (value_size_group)
4475 gtk_size_group_add_widget (value_size_group, control);
4477 g_signal_connect (G_OBJECT (abook_button), "clicked",
4478 G_CALLBACK (emit_open_addressbook), control);
4484 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4486 ModestMsgEditWindowPrivate *priv = NULL;
4488 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4490 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4491 priv->max_chars_banner = NULL;
4495 has_pending_addresses (ModestRecptEditor *recpt_editor)
4497 const gchar *recipients = NULL;
4498 GSList *start_indexes = NULL, *end_indexes = NULL;
4499 GSList *current_start, *current_end;
4500 GtkTextBuffer *buffer;
4501 gint offset_delta = 0;
4503 gboolean has_recipients_to_add = FALSE;
4505 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4506 last_length = g_utf8_strlen (recipients, -1);
4507 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4512 current_start = start_indexes;
4513 current_end = end_indexes;
4514 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4516 while (current_start && !has_recipients_to_add) {
4518 gchar *start_ptr, *end_ptr;
4519 gint start_pos, end_pos;
4521 start_pos = (*((gint*) current_start->data)) + offset_delta;
4522 end_pos = (*((gint*) current_end->data)) + offset_delta;
4524 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4525 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4527 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4529 if (modest_text_utils_validate_recipient (address, NULL)) {
4530 if (!modest_address_book_has_address (address)) {
4531 has_recipients_to_add = TRUE;
4534 current_start = g_slist_next (current_start);
4535 current_end = g_slist_next (current_end);
4537 return has_recipients_to_add;
4541 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4543 ModestMsgEditWindowPrivate *priv = NULL;
4545 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4547 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4549 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4550 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4551 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))