1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38 #include <tny-camel-mem-stream.h>
39 #include <modest-account-protocol.h>
43 #include <modest-account-mgr.h>
44 #include <modest-account-mgr-helpers.h>
46 #include <widgets/modest-msg-edit-window.h>
47 #include <widgets/modest-recpt-editor.h>
48 #include <widgets/modest-attachments-view.h>
50 #include <modest-runtime.h>
52 #include "modest-platform.h"
53 #include "modest-icon-names.h"
54 #include "modest-widget-memory.h"
55 #include "modest-window-priv.h"
56 #include "modest-mail-operation.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-tny-folder.h"
60 #include "modest-tny-account.h"
61 #include "modest-address-book.h"
62 #include "modest-text-utils.h"
63 #include <tny-simple-list.h>
64 #include <modest-wp-text-view.h>
65 #include <wptextbuffer.h>
66 #include <modest-scrollable.h>
67 #include <modest-isearch-toolbar.h>
68 #include "modest-msg-edit-window-ui-dimming.h"
70 #include "widgets/modest-msg-edit-window-ui.h"
71 #include <libgnomevfs/gnome-vfs-mime.h>
72 #include <modest-utils.h>
73 #include <modest-ui-constants.h>
74 #include <modest-toolkit-utils.h>
76 #ifdef MODEST_USE_CALENDAR_WIDGETS
77 #include <calendar-ui-widgets.h>
79 #ifdef MODEST_TOOLKIT_HILDON2
80 #include <hildon/hildon.h>
81 #include "modest-maemo-utils.h"
82 #include "modest-hildon-includes.h"
83 #include "modest-color-button.h"
86 #define DEFAULT_FONT_SIZE 3
87 #define DEFAULT_FONT 2
88 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
89 #define DEFAULT_MAIN_VBOX_SPACING 0
90 #define SUBJECT_MAX_LENGTH 1000
91 #define IMAGE_MAX_WIDTH 560
92 #define DEFAULT_FONT_SCALE 1.5
93 #define ATTACHMENT_BUTTON_WIDTH 118
94 #define MAX_FROM_VALUE 36
95 #define MAX_BODY_LENGTH 128*1024
96 #define MAX_BODY_LINES 2048
98 static gboolean is_wp_text_buffer_started = FALSE;
100 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
101 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
102 static void modest_msg_edit_window_finalize (GObject *obj);
104 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
105 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
106 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
108 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
109 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
110 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
111 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
112 GtkTextIter *start, GtkTextIter *end,
114 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
115 static void body_insert_text (GtkTextBuffer *buffer,
116 GtkTextIter *location,
119 ModestMsgEditWindow *window);
120 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
121 static void subject_field_insert_text (GtkEditable *editable,
123 gint new_text_length,
125 ModestMsgEditWindow *window);
126 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
128 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
130 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
131 ModestRecptEditor *editor);
132 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
133 ModestMsgEditWindow *window);
135 /* ModestWindow methods implementation */
136 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
137 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
138 gboolean show_toolbar);
139 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
141 ModestMsgEditWindow *window);
142 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
143 static void subject_field_move_cursor (GtkEntry *entry,
144 GtkMovementStep step,
148 static void update_window_title (ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
152 ModestMsgEditWindow *window);
153 static void modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
154 ModestMsgEditWindow *window);
155 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
157 GtkTextIter *match_start,
158 GtkTextIter *match_end);
160 static void remove_tags (WPTextBuffer *buffer);
162 static void on_account_removed (TnyAccountStore *account_store,
166 static void init_window (ModestMsgEditWindow *obj);
168 gboolean scroll_drag_timeout (gpointer userdata);
169 static void correct_scroll (ModestMsgEditWindow *w);
170 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
171 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
172 ModestMsgEditWindow *userdata);
173 static void text_buffer_mark_set (GtkTextBuffer *buffer,
176 ModestMsgEditWindow *userdata);
177 static void on_message_settings (GtkAction *action,
178 ModestMsgEditWindow *window);
179 static void setup_menu (ModestMsgEditWindow *self);
181 static void from_field_changed (GtkWidget *button,
182 ModestMsgEditWindow *self);
183 static void font_size_clicked (GtkToolButton *button,
184 ModestMsgEditWindow *window);
185 static void font_face_clicked (GtkToolButton *button,
186 ModestMsgEditWindow *window);
187 static void update_signature (ModestMsgEditWindow *self,
188 const gchar *old_account,
189 const gchar *new_account);
190 static void update_branding (ModestMsgEditWindow *self,
191 const gchar *new_account);
192 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
193 const gchar *label, GtkWidget *control);
194 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
195 static void DEBUG_BUFFER (WPTextBuffer *buffer)
199 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
201 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
202 while (!gtk_text_iter_is_end (&iter)) {
203 GString *output = g_string_new ("");
204 GSList *toggled_tags;
207 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
208 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
209 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
210 GtkTextTag *tag = (GtkTextTag *) node->data;
212 g_object_get (G_OBJECT (tag), "name", &name, NULL);
213 output = g_string_append (output, name);
214 g_string_append (output, " ");
216 output = g_string_append (output, "] OPENED [ ");
217 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
218 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
219 GtkTextTag *tag = (GtkTextTag *) node->data;
221 g_object_get (G_OBJECT (tag), "name", &name, NULL);
222 output = g_string_append (output, name);
223 g_string_append (output, " ");
225 output = g_string_append (output, "]\n");
226 g_debug ("%s", output->str);
227 g_string_free (output, TRUE);
228 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
230 g_debug ("END BUFFER");
234 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
235 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
239 /* static gboolean */
240 /* on_key_pressed (GtkWidget *self, */
241 /* GdkEventKey *event, */
242 /* gpointer user_data); */
244 /* list my signals */
251 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
252 struct _ModestMsgEditWindowPrivate {
254 GtkWidget *header_box;
256 ModestPairList *from_field_protos;
257 GtkWidget *from_field;
258 gchar *last_from_account;
259 gchar *original_account_name;
264 gchar *original_mailbox;
268 GtkWidget *bcc_field;
269 GtkWidget *subject_field;
270 GtkWidget *attachments_view;
271 GtkWidget *priority_icon;
272 GtkWidget *subject_box;
273 GtkWidget *send_button;
275 GtkWidget *cc_caption;
276 GtkWidget *bcc_caption;
277 gboolean update_caption_visibility;
278 GtkWidget *attachments_caption;
280 GtkTextBuffer *text_buffer;
282 GtkWidget *font_size_toolitem;
283 GtkWidget *font_face_toolitem;
284 GtkWidget *font_color_button;
285 GtkWidget *font_color_toolitem;
286 GSList *font_items_group;
287 GtkTreeModel *faces_model;
288 gint current_face_index;
289 GtkWidget *font_tool_button_label;
290 GtkTreeModel *sizes_model;
291 gint current_size_index;
292 GtkWidget *size_tool_button_label;
294 GtkWidget *isearch_toolbar;
297 GtkWidget *font_dialog;
299 GtkWidget *scrollable;
300 guint correct_scroll_idle;
301 guint scroll_drag_timeout_id;
305 TnyList *attachments;
310 TnyHeaderFlags priority_flags;
312 gboolean can_undo, can_redo;
313 gulong clipboard_change_handler_id;
314 gulong default_clipboard_change_handler_id;
315 gulong account_removed_handler_id;
316 guint clipboard_owner_idle;
317 gchar *clipboard_text;
326 GtkWidget *cc_button;
327 GtkWidget *bcc_button;
329 GtkWidget *max_chars_banner;
331 GtkWidget *brand_icon;
332 GtkWidget *brand_label;
333 GtkWidget *brand_container;
336 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
337 MODEST_TYPE_MSG_EDIT_WINDOW, \
338 ModestMsgEditWindowPrivate))
340 static GtkWindowClass *parent_class = NULL;
342 /* uncomment the following if you have defined any signals */
343 /* static guint signals[LAST_SIGNAL] = {0}; */
346 modest_msg_edit_window_get_type (void)
348 static GType my_type = 0;
350 static const GTypeInfo my_info = {
351 sizeof(ModestMsgEditWindowClass),
352 NULL, /* base init */
353 NULL, /* base finalize */
354 (GClassInitFunc) modest_msg_edit_window_class_init,
355 NULL, /* class finalize */
356 NULL, /* class data */
357 sizeof(ModestMsgEditWindow),
359 (GInstanceInitFunc) modest_msg_edit_window_init,
362 my_type = g_type_register_static (
363 #ifdef MODEST_TOOLKIT_HILDON2
364 MODEST_TYPE_HILDON2_WINDOW,
366 MODEST_TYPE_SHELL_WINDOW,
368 "ModestMsgEditWindow",
376 save_state (ModestWindow *self)
378 modest_widget_memory_save (modest_runtime_get_conf(),
379 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
384 restore_settings (ModestMsgEditWindow *self)
386 ModestConf *conf = NULL;
388 conf = modest_runtime_get_conf ();
390 /* Dim at start clipboard actions */
391 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
396 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
398 GObjectClass *gobject_class;
399 ModestWindowClass *modest_window_class;
400 gobject_class = (GObjectClass*) klass;
401 modest_window_class = (ModestWindowClass*) klass;
403 parent_class = g_type_class_peek_parent (klass);
404 gobject_class->finalize = modest_msg_edit_window_finalize;
406 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
407 modest_window_class->save_state_func = save_state;
408 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
410 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
414 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
416 ModestMsgEditWindowPrivate *priv;
417 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
419 priv->msg_body = NULL;
420 priv->from_field = NULL;
421 priv->to_field = NULL;
422 priv->cc_field = NULL;
423 priv->bcc_field = NULL;
424 priv->subject_field = NULL;
425 priv->attachments = TNY_LIST (tny_simple_list_new ());
426 priv->images = TNY_LIST (tny_simple_list_new ());
427 priv->images_size = 0;
428 priv->images_count = 0;
431 priv->cc_caption = NULL;
432 priv->bcc_caption = NULL;
433 priv->update_caption_visibility = FALSE;
435 priv->priority_flags = 0;
437 priv->isearch_toolbar = NULL;
438 priv->last_search = NULL;
440 priv->draft_msg = NULL;
441 priv->outbox_msg = NULL;
442 priv->msg_uid = NULL;
444 priv->can_undo = FALSE;
445 priv->can_redo = FALSE;
446 priv->clipboard_change_handler_id = 0;
447 priv->default_clipboard_change_handler_id = 0;
448 priv->account_removed_handler_id = 0;
449 priv->clipboard_owner_idle = 0;
450 priv->clipboard_text = NULL;
453 priv->scroll_drag_timeout_id = 0;
454 priv->correct_scroll_idle = 0;
455 priv->last_upper = 0.0;
457 priv->font_dialog = NULL;
458 priv->app_menu = NULL;
460 priv->references = NULL;
461 priv->in_reply_to = NULL;
462 priv->max_chars_banner = NULL;
464 if (!is_wp_text_buffer_started) {
465 is_wp_text_buffer_started = TRUE;
466 wp_text_buffer_library_init ();
470 #ifdef MODEST_TOOLKIT_HILDON2
471 hildon_program_add_window (hildon_program_get_instance(),
477 multimailbox_get_default_mailbox (const gchar *account_name)
479 gchar *transport_account;
480 gchar *result = NULL;
482 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
484 TNY_ACCOUNT_TYPE_TRANSPORT);
485 if (transport_account) {
487 ModestProtocolRegistry *registry;
489 registry = modest_runtime_get_protocol_registry ();
491 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
492 MODEST_ACCOUNT_PROTO, TRUE);
494 ModestProtocol *protocol =
495 modest_protocol_registry_get_protocol_by_name (registry,
496 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
498 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
499 ModestPairList *pair_list;
501 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
504 ModestPair *pair = (ModestPair *) pair_list->data;
505 result = g_strdup ((const gchar *) pair->first);
506 modest_pair_list_free (pair_list);
517 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
519 static ModestPairList*
520 get_transports (void)
522 GSList *transports = NULL;
524 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
525 GSList *accounts = modest_account_mgr_account_names (account_mgr,
526 TRUE /* only enabled accounts. */);
528 GSList *cursor = accounts;
530 gchar *account_name = cursor->data;
533 gchar *transport_account;
534 gboolean multi_mailbox = FALSE;
535 ModestProtocol *protocol = NULL;
537 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
539 transport_account = modest_account_mgr_get_server_account_name
540 (modest_runtime_get_account_mgr (),
542 TNY_ACCOUNT_TYPE_TRANSPORT);
543 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
544 ModestPairList *pair_list;
545 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
548 transports = g_slist_concat (transports, pair_list);
549 multi_mailbox = TRUE;
554 if (!multi_mailbox) {
555 gchar *from_string = NULL;
557 from_string = modest_account_mgr_get_from_string (account_mgr,
559 if (from_string && account_name) {
560 gchar *name = account_name;
561 ModestPair *pair = modest_pair_new ((gpointer) name,
562 (gpointer) from_string , TRUE);
563 transports = g_slist_prepend (transports, pair);
568 cursor = cursor->next;
570 g_slist_free (accounts); /* only free the accounts, not the elements,
571 * because they are used in the pairlist */
575 static void window_focus (GtkWindow *window,
579 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
583 scroll_drag_timeout (gpointer userdata)
585 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
586 ModestMsgEditWindowPrivate *priv;
588 /* It could happen that the window was already closed */
589 if (!GTK_WIDGET_VISIBLE (win))
592 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
594 correct_scroll_without_drag_check (win, TRUE);
596 priv->scroll_drag_timeout_id = 0;
602 correct_scroll_without_drag_check_idle (gpointer userdata)
604 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
605 ModestMsgEditWindowPrivate *priv;
607 GdkRectangle rectangle;
608 gint offset_min, offset_max;
612 /* It could happen that the window was already closed */
613 if (!GTK_WIDGET_VISIBLE (w))
616 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
618 insert = gtk_text_buffer_get_insert (priv->text_buffer);
619 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
621 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
622 offset_min = priv->msg_body->allocation.y + rectangle.y;
623 offset_max = offset_min + rectangle.height;
625 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
626 offset_min = MAX (offset_min - 48, 0);
627 offset_max = MIN (offset_max + 48, vadj->upper);
629 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
631 priv->correct_scroll_idle = 0;
636 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
638 ModestMsgEditWindowPrivate *priv;
640 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
642 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
645 if (priv->correct_scroll_idle > 0) {
649 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
650 (GSourceFunc) correct_scroll_without_drag_check_idle,
656 correct_scroll (ModestMsgEditWindow *w)
658 ModestMsgEditWindowPrivate *priv;
660 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
661 if (gtk_grab_get_current () == priv->msg_body) {
662 if (priv->scroll_drag_timeout_id == 0) {
663 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
665 (GSourceFunc) scroll_drag_timeout,
672 correct_scroll_without_drag_check (w, TRUE);
676 text_buffer_end_user_action (GtkTextBuffer *buffer,
677 ModestMsgEditWindow *userdata)
680 correct_scroll (userdata);
684 text_buffer_mark_set (GtkTextBuffer *buffer,
687 ModestMsgEditWindow *userdata)
689 gtk_text_buffer_begin_user_action (buffer);
690 gtk_text_buffer_end_user_action (buffer);
694 cut_clipboard_check (GtkTextView *text_view,
697 GtkTextBuffer *buffer;
699 buffer = gtk_text_view_get_buffer (text_view);
700 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
701 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
706 copy_clipboard_check (GtkTextView *text_view,
709 GtkTextBuffer *buffer;
711 buffer = gtk_text_view_get_buffer (text_view);
712 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
713 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
718 attachment_deleted (ModestAttachmentsView *attachments_view,
721 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
726 body_size_request (GtkWidget *body,
730 /* Make sure the body always get at least 70 pixels */
731 if (req->height < 70)
736 connect_signals (ModestMsgEditWindow *obj)
738 ModestMsgEditWindowPrivate *priv;
740 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
742 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
743 G_CALLBACK (text_buffer_refresh_attributes), obj);
744 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
745 G_CALLBACK (text_buffer_can_undo), obj);
746 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
747 G_CALLBACK (text_buffer_can_redo), obj);
748 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
749 G_CALLBACK (body_changed), obj);
750 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
751 G_CALLBACK (body_insert_text), obj);
752 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
753 G_CALLBACK (body_changed), obj);
754 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
755 G_CALLBACK (text_buffer_end_user_action), obj);
756 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
757 G_CALLBACK (text_buffer_mark_set), obj);
758 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
759 G_CALLBACK (text_buffer_apply_tag), obj);
760 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
761 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
762 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
763 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
764 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
765 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
767 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
768 G_CALLBACK (modest_ui_actions_on_send), obj);
770 if (GTK_IS_COMBO_BOX (priv->from_field)) {
771 g_signal_connect (G_OBJECT (priv->from_field), "changed",
772 G_CALLBACK (from_field_changed), obj);
774 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
775 G_CALLBACK (from_field_changed), obj);
778 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
779 G_CALLBACK (msg_body_focus), obj);
780 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
781 G_CALLBACK (msg_body_focus), obj);
782 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
783 G_CALLBACK (body_size_request), obj);
784 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
785 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
786 "changed", G_CALLBACK (recpt_field_changed), obj);
787 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
788 "changed", G_CALLBACK (recpt_field_changed), obj);
789 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
790 "changed", G_CALLBACK (recpt_field_changed), obj);
791 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
792 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
793 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
795 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
796 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
797 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
798 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_close), obj);
800 priv->clipboard_change_handler_id =
801 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
802 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
803 priv->default_clipboard_change_handler_id =
804 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
805 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
807 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
808 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
809 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
813 init_wp_text_view_style ()
815 static gboolean initialized = FALSE;
818 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
824 init_window (ModestMsgEditWindow *obj)
826 GtkWidget *to_caption, *subject_caption;
827 GtkWidget *main_vbox;
828 ModestMsgEditWindowPrivate *priv;
829 GtkActionGroup *action_group;
830 ModestWindowPrivate *parent_priv;
831 GError *error = NULL;
833 GtkSizeGroup *title_size_group;
834 GtkSizeGroup *value_size_group;
835 GtkWidget *window_box;
836 GtkWidget *window_align;
837 #if (GTK_MINOR_VERSION >= 10)
838 GdkAtom deserialize_type;
840 GtkWidget *from_send_hbox;
841 GtkWidget *send_icon;
842 GtkWidget *attachments_label;
843 GtkWidget *branding_box;
844 GtkWidget *from_caption;
846 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
847 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
849 parent_priv->ui_manager = gtk_ui_manager_new();
850 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
851 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
853 /* Add common actions */
854 gtk_action_group_add_actions (action_group,
855 modest_msg_edit_action_entries,
856 G_N_ELEMENTS (modest_msg_edit_action_entries),
858 gtk_action_group_add_actions (action_group,
859 hildon2_msg_edit_action_entries,
860 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
862 gtk_action_group_add_toggle_actions (action_group,
863 modest_msg_edit_toggle_action_entries,
864 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
866 gtk_action_group_add_radio_actions (action_group,
867 modest_msg_edit_alignment_radio_action_entries,
868 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
870 G_CALLBACK (modest_ui_actions_on_change_justify),
872 gtk_action_group_add_radio_actions (action_group,
873 modest_msg_edit_priority_action_entries,
874 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
876 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
878 gtk_action_group_add_radio_actions (action_group,
879 modest_msg_edit_file_format_action_entries,
880 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
881 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
882 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
884 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
885 g_object_unref (action_group);
887 /* Load the UI definition */
888 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
891 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
892 g_clear_error (&error);
895 /* Add accelerators */
896 gtk_window_add_accel_group (GTK_WINDOW (obj),
897 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
899 parent_priv->menubar = NULL;
901 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
902 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
904 /* Note: This ModestPairList* must exist for as long as the picker
905 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
906 * so it can't know how to manage its memory. */
907 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
909 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
910 if (GTK_IS_COMBO_BOX (priv->from_field)) {
911 from_caption = modest_toolkit_utils_create_captioned (title_size_group, NULL,
912 _("mail_va_from"), FALSE,
914 gtk_widget_show (from_caption);
916 #ifdef MODEST_TOOLKIT_HILDON2
917 modest_toolkit_utils_set_hbutton_layout (title_size_group, NULL,
918 _("mail_va_from"), priv->from_field);
919 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
920 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
921 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
922 from_caption = priv->from_field;
926 priv->to_field = modest_recpt_editor_new ();
927 priv->cc_field = modest_recpt_editor_new ();
928 priv->bcc_field = modest_recpt_editor_new ();
929 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
930 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
931 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
932 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
933 priv->priority_icon = gtk_image_new ();
934 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
935 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
936 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
937 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
938 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
940 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
941 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
943 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
944 priv->attachments_view = modest_attachments_view_new (NULL);
945 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
946 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
948 priv->header_box = gtk_vbox_new (FALSE, 0);
950 to_caption = _create_addressbook_box
951 (title_size_group, value_size_group,
952 _("mail_va_to"), priv->to_field);
953 priv->cc_caption = _create_addressbook_box
954 (title_size_group, value_size_group,
955 _("mail_va_cc"), priv->cc_field);
956 priv->bcc_caption = _create_addressbook_box
957 (title_size_group, value_size_group,
958 _("mail_va_hotfix1"), priv->bcc_field);
959 subject_caption = modest_toolkit_utils_create_captioned (title_size_group, value_size_group,
960 _("mail_va_subject"), FALSE, priv->subject_box);
961 priv->attachments_caption = modest_toolkit_utils_create_captioned_with_size_type (NULL, NULL,
962 _("mail_va_attachment"),
964 priv->attachments_view,
965 #ifdef MODEST_TOOLKIT_HILDON2
966 HILDON_SIZE_AUTO_WIDTH |
967 HILDON_SIZE_AUTO_HEIGHT
972 attachments_label = modest_toolkit_utils_captioned_get_label_widget (priv->attachments_caption);
974 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
978 #ifdef MODEST_TOOLKIT_HILDON2
979 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
980 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
982 priv->send_button = gtk_button_new ();
983 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, GTK_ICON_SIZE_BUTTON);
985 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
986 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
988 g_object_unref (title_size_group);
989 g_object_unref (value_size_group);
991 priv->brand_icon = gtk_image_new ();
992 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
993 priv->brand_label = gtk_label_new (NULL);
994 #ifdef MODEST_TOOLKIT_HILDON2
995 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
997 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
998 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
999 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
1001 from_send_hbox = gtk_hbox_new (FALSE, 0);
1002 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
1003 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
1005 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
1006 gtk_widget_show (branding_box);
1007 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
1008 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
1010 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
1011 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1012 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
1013 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
1016 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
1017 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
1018 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
1019 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
1020 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
1021 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
1022 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
1023 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1025 init_wp_text_view_style ();
1027 priv->msg_body = modest_wp_text_view_new ();
1030 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1031 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1032 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1033 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1034 #if (GTK_MINOR_VERSION >= 10)
1035 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1036 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1038 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1039 deserialize_type, TRUE);
1041 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1043 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1045 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1047 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1049 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1051 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1053 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1054 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1055 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1057 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1058 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1059 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1061 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1062 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1064 window_box = gtk_vbox_new (FALSE, 0);
1065 gtk_container_add (GTK_CONTAINER(obj), window_box);
1067 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1072 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1074 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1076 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1077 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1078 priv->clipboard_change_handler_id))
1079 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1080 priv->clipboard_change_handler_id);
1081 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1082 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1083 priv->default_clipboard_change_handler_id))
1084 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1085 priv->default_clipboard_change_handler_id);
1087 if (priv->account_removed_handler_id &&
1088 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1089 priv->account_removed_handler_id))
1090 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1091 priv->account_removed_handler_id);
1095 modest_msg_edit_window_finalize (GObject *obj)
1097 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1099 if (priv->max_chars_banner) {
1100 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1101 priv->max_chars_banner = FALSE;
1104 /* Sanity check: shouldn't be needed, the window mgr should
1105 call this function before */
1106 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1108 if (priv->font_dialog != NULL) {
1109 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1112 if (priv->clipboard_text != NULL) {
1113 g_free (priv->clipboard_text);
1114 priv->clipboard_text = NULL;
1117 if (priv->draft_msg != NULL) {
1118 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1119 if (TNY_IS_HEADER (header)) {
1120 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1121 modest_window_mgr_unregister_header (mgr, header);
1123 g_object_unref (priv->draft_msg);
1124 priv->draft_msg = NULL;
1126 if (priv->outbox_msg != NULL) {
1127 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1128 if (TNY_IS_HEADER (header)) {
1129 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1130 modest_window_mgr_unregister_header (mgr, header);
1132 g_object_unref (priv->outbox_msg);
1133 priv->outbox_msg = NULL;
1135 if (priv->correct_scroll_idle > 0) {
1136 g_source_remove (priv->correct_scroll_idle);
1137 priv->correct_scroll_idle = 0;
1139 if (priv->scroll_drag_timeout_id > 0) {
1140 g_source_remove (priv->scroll_drag_timeout_id);
1141 priv->scroll_drag_timeout_id = 0;
1143 if (priv->clipboard_owner_idle > 0) {
1144 g_source_remove (priv->clipboard_owner_idle);
1145 priv->clipboard_owner_idle = 0;
1147 if (priv->original_account_name)
1148 g_free (priv->original_account_name);
1149 if (priv->original_mailbox)
1150 g_free (priv->original_mailbox);
1151 g_free (priv->msg_uid);
1152 g_free (priv->last_search);
1153 g_free (priv->references);
1154 g_free (priv->in_reply_to);
1155 g_object_unref (priv->attachments);
1156 g_object_unref (priv->images);
1158 /* This had to stay alive for as long as the picker that used it: */
1159 modest_pair_list_free (priv->from_field_protos);
1161 G_OBJECT_CLASS(parent_class)->finalize (obj);
1165 pixbuf_size_prepared (GdkPixbufLoader *loader,
1168 ModestMsgEditWindow *self)
1170 gint new_height, new_width;
1173 new_height = height;
1177 if (width > IMAGE_MAX_WIDTH) {
1178 new_height = height * IMAGE_MAX_WIDTH / width;
1179 new_width = IMAGE_MAX_WIDTH;
1182 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1186 pixbuf_from_stream (TnyStream *stream,
1187 const gchar *mime_type,
1188 guint64 *stream_size,
1189 ModestMsgEditWindow *self)
1191 GdkPixbufLoader *loader;
1194 GError *error = NULL;
1198 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1200 if (loader == NULL) {
1205 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1207 modest_window_show_progress (MODEST_WINDOW (self), TRUE);
1209 tny_stream_reset (TNY_STREAM (stream));
1210 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1211 unsigned char read_buffer[128];
1213 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1215 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1218 /* Allow some UI responsiveness */
1219 while (gtk_events_pending ())
1220 gtk_main_iteration ();
1222 modest_window_show_progress (MODEST_WINDOW (self), FALSE);
1224 gdk_pixbuf_loader_close (loader, &error);
1227 g_error_free (error);
1228 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1230 g_object_ref (pixbuf);
1231 g_object_unref (loader);
1236 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1237 GdkPixbuf *new_pixbuf;
1239 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1240 gdk_pixbuf_get_width (pixbuf);
1241 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1242 g_object_unref (pixbuf);
1243 pixbuf = new_pixbuf;
1247 *stream_size = size;
1253 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1255 ModestMsgEditWindowPrivate *priv;
1258 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1260 g_object_ref (self);
1261 for (iter = tny_list_create_iterator (attachments);
1262 !tny_iterator_is_done (iter);
1263 tny_iterator_next (iter)) {
1264 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1265 const gchar *cid = tny_mime_part_get_content_id (part);
1266 const gchar *mime_type = tny_mime_part_get_content_type (part);
1267 if ((cid != NULL)&&(mime_type != NULL)) {
1268 guint64 stream_size;
1269 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1270 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1273 g_object_unref (stream);
1275 if (pixbuf != NULL) {
1276 priv->images_count ++;
1277 priv->images_size += stream_size;
1278 #ifndef MODEST_HAVE_LIBWPEDITOR_PLUS
1279 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1281 g_object_unref (pixbuf);
1284 g_object_unref (part);
1286 g_object_unref (iter);
1287 g_object_unref (self);
1291 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1293 TnyMimePart *parent = NULL;
1294 const gchar *content_type = NULL;
1295 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1297 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1299 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1300 parent = g_object_ref (msg);
1301 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1302 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1305 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1306 iter = tny_list_create_iterator (parts);
1307 while (!tny_iterator_is_done (iter)) {
1309 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1310 content_type = tny_mime_part_get_content_type (part);
1311 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1315 g_object_unref (part);
1317 tny_iterator_next (iter);
1319 g_object_unref (iter);
1320 g_object_unref (parts);
1323 if (parent != NULL) {
1324 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1327 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1328 iter = tny_list_create_iterator (parts);
1329 while (!tny_iterator_is_done (iter)) {
1331 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1332 content_type = tny_mime_part_get_content_type (part);
1333 if (content_type && g_str_has_prefix (content_type, "image/")) {
1334 tny_list_prepend (priv->images, (GObject *) part);
1336 g_object_unref (part);
1337 tny_iterator_next (iter);
1339 g_object_unref (iter);
1340 g_object_unref (parts);
1341 g_object_unref (parent);
1346 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1349 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1351 for (iter = tny_list_create_iterator (attachments) ;
1352 !tny_iterator_is_done (iter);
1353 tny_iterator_next (iter)) {
1354 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1355 const gchar *cid = tny_mime_part_get_content_id (part);
1357 char *invalid = NULL;
1358 gint int_cid = strtol (cid, &invalid, 10);
1359 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1360 priv->next_cid = int_cid + 1;
1363 g_object_unref (part);
1365 g_object_unref (iter);
1369 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1372 gchar *to, *cc, *bcc, *subject;
1374 ModestMsgEditWindowPrivate *priv;
1375 ModestWindowPrivate *parent_priv;
1377 TnyHeaderFlags priority_flags;
1378 TnyFolder *msg_folder;
1379 gboolean is_html = FALSE;
1380 gboolean field_view_set;
1382 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1383 g_return_if_fail (TNY_IS_MSG (msg));
1385 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1386 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1388 header = tny_msg_get_header (msg);
1389 to = tny_header_dup_to (header);
1390 cc = tny_header_dup_cc (header);
1391 bcc = tny_header_dup_bcc (header);
1392 subject = tny_header_dup_subject (header);
1394 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1395 priority_flags = tny_header_get_priority (header);
1398 gchar *quoted_names = modest_text_utils_quote_names (to);
1399 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1400 g_free (quoted_names);
1403 field_view_set = TRUE;
1405 gchar *quoted_names = modest_text_utils_quote_names (cc);
1406 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1407 g_free (quoted_names);
1408 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1409 gtk_widget_show (priv->cc_caption);
1410 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1411 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1412 gtk_widget_hide (priv->cc_caption);
1413 field_view_set = FALSE;
1415 modest_togglable_set_active (priv->cc_button, field_view_set);
1417 field_view_set = TRUE;
1419 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1420 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1421 g_free (quoted_names);
1422 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1423 gtk_widget_show (priv->bcc_caption);
1424 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1425 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1426 gtk_widget_hide (priv->bcc_caption);
1427 field_view_set = FALSE;
1429 modest_togglable_set_active (priv->bcc_button, field_view_set);
1433 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1434 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1437 update_window_title (self);
1439 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1440 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1442 if ((body == NULL)||(body[0] == '\0')) {
1444 body = modest_text_utils_convert_to_html ("");
1447 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1448 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1451 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1454 /* Add attachments to the view */
1455 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1456 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1457 if (tny_list_get_length (priv->attachments) == 0) {
1458 gtk_widget_hide (priv->attachments_caption);
1460 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1461 gtk_widget_show_all (priv->attachments_caption);
1463 get_related_images (self, msg);
1464 update_next_cid (self, priv->attachments);
1465 update_next_cid (self, priv->images);
1466 replace_with_images (self, priv->images);
1468 if (preserve_is_rich && !is_html) {
1469 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1470 /* Get the default format required from configuration */
1471 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1472 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1475 /* Set the default focus depending on having already a To: field or not */
1476 if ((!to)||(*to == '\0')) {
1477 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1479 gtk_widget_grab_focus (priv->msg_body);
1482 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1484 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1485 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1487 modest_msg_edit_window_set_modified (self, FALSE);
1489 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1490 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1491 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1492 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1494 if (priv->msg_uid) {
1495 g_free (priv->msg_uid);
1496 priv->msg_uid = NULL;
1499 /* we should set a reference to the incoming message if it is a draft */
1500 msg_folder = tny_msg_get_folder (msg);
1502 if (modest_tny_folder_is_local_folder (msg_folder)) {
1503 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1504 if (type == TNY_FOLDER_TYPE_INVALID)
1505 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1507 if (type == TNY_FOLDER_TYPE_DRAFTS)
1508 priv->draft_msg = g_object_ref(msg);
1509 if (type == TNY_FOLDER_TYPE_OUTBOX)
1510 priv->outbox_msg = g_object_ref(msg);
1511 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1513 g_object_unref (msg_folder);
1523 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1525 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1526 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1527 GtkWidget *placeholder;
1528 GtkWidget *tool_item;
1533 GtkWidget *sizes_menu;
1534 GtkWidget *fonts_menu;
1540 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1541 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1542 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar),
1543 #ifdef MODEST_TOOLKIT_HILDON2
1544 HILDON_ICON_SIZE_FINGER
1546 GTK_ICON_SIZE_LARGE_TOOLBAR
1549 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1551 /* Font color placeholder */
1552 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1553 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1556 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1557 #ifdef MODEST_TOOLKIT_HILDON2
1558 priv->font_color_button = modest_color_button_new ();
1560 priv->font_color_button = gtk_color_button_new ();
1562 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1563 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1564 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1565 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1566 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1567 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1568 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1569 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1571 G_CALLBACK (modest_msg_edit_window_color_button_change),
1574 /* Font size and face placeholder */
1575 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1576 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1578 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1579 priv->size_tool_button_label = gtk_label_new (NULL);
1580 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1581 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1582 size_text, "</span>", NULL);
1583 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1584 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1586 #ifdef MODEST_TOOLKIT_HILDON2
1587 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1589 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1590 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1591 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1592 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1593 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1594 gtk_widget_set_sensitive (arrow, FALSE);
1595 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1596 sizes_menu = gtk_menu_new ();
1597 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1598 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1601 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1602 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1604 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1608 if (wp_font_size[size_index] == 12)
1609 priv->current_size_index = size_index;
1613 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1614 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1615 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1616 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1617 priv->font_size_toolitem = tool_item;
1620 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1621 priv->font_tool_button_label = gtk_label_new (NULL);
1622 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1623 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1624 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1626 #ifdef MODEST_TOOLKIT_HILDON2
1627 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1629 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1630 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1631 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1632 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1633 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1634 gtk_widget_set_sensitive (arrow, FALSE);
1635 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1636 fonts_menu = gtk_menu_new ();
1637 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1638 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1641 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1643 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1644 0, wp_get_font_name (font_index),
1647 if (font_index == DEFAULT_FONT)
1648 priv->current_face_index = font_index;
1650 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1651 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1652 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1653 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1654 priv->font_face_toolitem = tool_item;
1656 /* Set expand and homogeneous for remaining items */
1657 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1658 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1659 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1660 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1661 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1662 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1664 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1665 will not show the tool items added to the placeholders) */
1666 gtk_widget_show_all (parent_priv->toolbar);
1668 /* Set the no show all *after* showing all items. We do not
1669 want the toolbar to be shown with a show all because it
1670 could go agains the gconf setting regarding showing or not
1671 the toolbar of the editor window */
1672 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1678 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1681 ModestWindowPrivate *parent_priv;
1682 ModestMsgEditWindowPrivate *priv;
1683 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1684 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1685 ModestWindowMgr *mgr = NULL;
1687 g_return_val_if_fail (msg, NULL);
1688 g_return_val_if_fail (account_name, NULL);
1690 mgr = modest_runtime_get_window_mgr ();
1692 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1694 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1695 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1697 /* Menubar. Update the state of some toggles */
1698 priv->from_field_protos = get_transports ();
1699 priv->original_mailbox = NULL;
1700 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1701 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1702 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1703 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1704 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1705 priv->original_mailbox = g_strdup (mailbox);
1706 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1707 /* We set the first mailbox as the active mailbox */
1708 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1709 if (priv->original_mailbox != NULL)
1710 modest_selector_set_active_id (priv->from_field,
1711 (gpointer) priv->original_mailbox);
1713 modest_selector_set_active_id (priv->from_field,
1714 (gpointer) account_name);
1716 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1718 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1719 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1720 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1721 #ifdef HILDON_TOOLKIT_HILDON2
1722 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1724 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1725 hildon_touch_selector_get_current_text
1726 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1729 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1730 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1733 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1735 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1737 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1738 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1740 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1742 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1743 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1744 /* Add common dimming rules */
1745 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1746 modest_msg_edit_window_toolbar_dimming_entries,
1747 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1748 MODEST_WINDOW (obj));
1749 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1750 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1751 MODEST_WINDOW (obj));
1752 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1753 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1754 MODEST_WINDOW (obj));
1755 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1756 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1757 MODEST_WINDOW (obj));
1758 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1759 G_CALLBACK (modest_ui_dimming_rules_on_send),
1760 MODEST_WINDOW (obj));
1761 /* Insert dimming rules group for this window */
1762 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1763 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1765 /* Setup app menu */
1766 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1768 /* Checks the dimming rules */
1769 g_object_unref (toolbar_rules_group);
1770 g_object_unref (clipboard_rules_group);
1771 gtk_widget_hide (priv->priority_icon);
1772 gtk_widget_queue_resize (priv->subject_box);
1773 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1775 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1777 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1778 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1779 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1780 priv->update_caption_visibility = TRUE;
1782 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1784 /* Track account-removed signal, this window should be closed
1785 in the case we're creating a mail associated to the account
1787 priv->account_removed_handler_id =
1788 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1790 G_CALLBACK(on_account_removed),
1793 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1795 return (ModestWindow*) obj;
1799 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1801 GString **string_buffer = (GString **) user_data;
1803 *string_buffer = g_string_append (*string_buffer, buffer);
1809 * @result: A new string which should be freed with g_free().
1812 get_formatted_data (ModestMsgEditWindow *edit_window)
1814 ModestMsgEditWindowPrivate *priv;
1815 GString *string_buffer = g_string_new ("");
1817 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1819 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1821 modest_text_utils_hyperlinkify (string_buffer);
1823 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1825 return g_string_free (string_buffer, FALSE);
1830 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1833 const gchar *account_name;
1834 ModestMsgEditWindowPrivate *priv;
1835 TnyIterator *att_iter;
1836 const gchar *picker_active_id;
1838 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1840 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1842 picker_active_id = modest_selector_get_active_id (priv->from_field);
1843 g_return_val_if_fail (picker_active_id, NULL);
1844 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1846 /* don't free these (except from) */
1847 data = g_slice_new0 (MsgData);
1848 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1849 data->account_name = g_strdup (account_name);
1850 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1851 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1852 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1853 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1854 data->references = g_strdup (priv->references);
1855 data->in_reply_to = g_strdup (priv->in_reply_to);
1856 if (priv->draft_msg) {
1857 data->draft_msg = g_object_ref (priv->draft_msg);
1858 } else if (priv->outbox_msg) {
1859 data->draft_msg = g_object_ref (priv->outbox_msg);
1861 data->draft_msg = NULL;
1864 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1866 gtk_text_buffer_get_bounds (buf, &b, &e);
1867 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1869 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1870 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1872 data->html_body = NULL;
1874 /* deep-copy the data */
1875 att_iter = tny_list_create_iterator (priv->attachments);
1876 data->attachments = NULL;
1877 while (!tny_iterator_is_done (att_iter)) {
1878 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1879 if (!(TNY_IS_MIME_PART(part))) {
1880 g_warning ("strange data in attachment list");
1881 g_object_unref (part);
1882 tny_iterator_next (att_iter);
1885 data->attachments = g_list_append (data->attachments,
1887 tny_iterator_next (att_iter);
1889 g_object_unref (att_iter);
1891 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1892 att_iter = tny_list_create_iterator (priv->images);
1893 data->images = NULL;
1894 while (!tny_iterator_is_done (att_iter)) {
1895 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1897 if (!(TNY_IS_MIME_PART(part))) {
1898 g_warning ("strange data in attachment list");
1899 g_object_unref (part);
1900 tny_iterator_next (att_iter);
1903 cid = tny_mime_part_get_content_id (part);
1905 gchar *image_tag_id;
1906 GtkTextTag *image_tag;
1908 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1909 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1910 g_free (image_tag_id);
1912 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1914 ((gtk_text_iter_has_tag (&iter, image_tag))||
1915 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1916 data->images = g_list_append (data->images,
1917 g_object_ref (part));
1919 g_object_unref (part);
1920 tny_iterator_next (att_iter);
1922 g_object_unref (att_iter);
1924 data->priority_flags = priv->priority_flags;
1931 unref_gobject (GObject *obj, gpointer data)
1933 if (!G_IS_OBJECT(obj))
1935 g_object_unref (obj);
1939 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1942 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1950 g_free (data->from);
1951 g_free (data->subject);
1952 g_free (data->plain_body);
1953 g_free (data->html_body);
1954 g_free (data->account_name);
1955 g_free (data->references);
1956 g_free (data->in_reply_to);
1958 if (data->draft_msg != NULL) {
1959 g_object_unref (data->draft_msg);
1960 data->draft_msg = NULL;
1963 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1964 g_list_free (data->attachments);
1965 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1966 g_list_free (data->images);
1968 g_slice_free (MsgData, data);
1972 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1974 guint64 *parts_size)
1976 ModestMsgEditWindowPrivate *priv;
1978 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1980 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1982 /* TODO: add images */
1983 *parts_size += priv->images_size;
1984 *parts_count += priv->images_count;
1989 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1992 ModestMsgEditWindowPrivate *priv = NULL;
1993 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1995 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1997 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1999 return MODEST_MSG_EDIT_FORMAT_HTML;
2001 return MODEST_MSG_EDIT_FORMAT_TEXT;
2005 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
2006 ModestMsgEditFormat format)
2008 ModestMsgEditWindowPrivate *priv;
2009 ModestWindowPrivate *parent_priv;
2011 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2012 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2013 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2016 case MODEST_MSG_EDIT_FORMAT_HTML:
2017 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2018 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
2020 case MODEST_MSG_EDIT_FORMAT_TEXT:
2021 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2022 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
2025 g_return_if_reached ();
2029 ModestMsgEditFormatState *
2030 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2032 ModestMsgEditFormatState *format_state = NULL;
2033 ModestMsgEditWindowPrivate *priv;
2034 WPTextBufferFormat *buffer_format;
2036 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2038 buffer_format = g_new0 (WPTextBufferFormat, 1);
2039 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2041 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2043 format_state = g_new0 (ModestMsgEditFormatState, 1);
2044 format_state->bold = buffer_format->bold&0x1;
2045 format_state->italics = buffer_format->italic&0x1;
2046 format_state->bullet = buffer_format->bullet&0x1;
2047 format_state->color = buffer_format->color;
2048 format_state->font_size = buffer_format->font_size;
2049 format_state->font_family = wp_get_font_name (buffer_format->font);
2050 format_state->justification = buffer_format->justification;
2051 g_free (buffer_format);
2053 return format_state;
2058 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2059 const ModestMsgEditFormatState *format_state)
2061 ModestMsgEditWindowPrivate *priv;
2062 WPTextBufferFormat *buffer_format;
2063 WPTextBufferFormat *current_format;
2065 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2066 g_return_if_fail (format_state != NULL);
2068 buffer_format = g_new0 (WPTextBufferFormat, 1);
2069 current_format = g_new0 (WPTextBufferFormat, 1);
2071 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2072 gtk_widget_grab_focus (priv->msg_body);
2073 buffer_format->bold = (format_state->bold != FALSE);
2074 buffer_format->italic = (format_state->italics != FALSE);
2075 buffer_format->color = format_state->color;
2076 buffer_format->font_size = format_state->font_size;
2077 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2078 buffer_format->justification = format_state->justification;
2079 buffer_format->bullet = format_state->bullet;
2081 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2083 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2084 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2085 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2086 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2087 buffer_format->cs.font = (buffer_format->font != current_format->font);
2088 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2089 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2091 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2092 if (buffer_format->cs.bold) {
2093 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2094 GINT_TO_POINTER (buffer_format->bold&0x1));
2096 if (buffer_format->cs.italic) {
2097 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2098 GINT_TO_POINTER (buffer_format->italic&0x1));
2100 if (buffer_format->cs.color) {
2101 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2102 GINT_TO_POINTER (&(buffer_format->color)));
2104 if (buffer_format->cs.font_size) {
2105 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2106 GINT_TO_POINTER (buffer_format->font_size));
2108 if (buffer_format->cs.justification) {
2109 switch (buffer_format->justification) {
2110 case GTK_JUSTIFY_LEFT:
2111 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2112 GINT_TO_POINTER(TRUE));
2114 case GTK_JUSTIFY_CENTER:
2115 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2116 GINT_TO_POINTER(TRUE));
2118 case GTK_JUSTIFY_RIGHT:
2119 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2120 GINT_TO_POINTER(TRUE));
2127 if (buffer_format->cs.font) {
2128 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2129 GINT_TO_POINTER (buffer_format->font));
2131 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2132 if (buffer_format->cs.bullet) {
2133 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2134 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2136 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2138 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2140 g_free (buffer_format);
2141 g_free (current_format);
2143 /* Check dimming rules */
2144 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2145 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2149 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2151 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2153 ModestWindowPrivate *parent_priv;
2154 ModestMsgEditWindowPrivate *priv;
2156 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2157 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2159 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2160 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2161 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2162 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2164 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2165 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2166 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2169 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2171 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2172 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2174 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2175 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2177 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2178 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2181 switch (buffer_format->justification)
2183 case GTK_JUSTIFY_LEFT:
2184 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2186 case GTK_JUSTIFY_CENTER:
2187 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2189 case GTK_JUSTIFY_RIGHT:
2190 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2197 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2199 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2200 G_CALLBACK (modest_msg_edit_window_color_button_change),
2202 #ifdef MODEST_TOOLKIT_HILDON2
2203 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2205 gtk_color_button_set_color (GTK_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2207 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2208 G_CALLBACK (modest_msg_edit_window_color_button_change),
2211 if (priv->current_size_index != buffer_format->font_size) {
2215 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2216 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2220 priv->current_size_index = buffer_format->font_size;
2222 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2223 markup = g_strconcat ("<span font_family='Sans'>",
2224 size_text, "</span>", NULL);
2226 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2230 gtk_tree_path_free (path);
2233 if (priv->current_face_index != buffer_format->font) {
2237 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2238 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2242 priv->current_face_index = buffer_format->font;
2243 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2244 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2245 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2252 g_free (buffer_format);
2258 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2260 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2261 ModestMsgEditWindowPrivate *priv;
2262 GtkWidget *dialog = NULL;
2264 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2265 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2267 #ifdef MODEST_TOOLKIT_HILDON2
2268 dialog = hildon_color_chooser_new ();
2269 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2270 g_free (buffer_format);
2272 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2274 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2275 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2278 gtk_widget_destroy (dialog);
2280 dialog = gtk_color_selection_dialog_new (NULL);
2281 GtkWidget *selection;
2283 g_object_get (G_OBJECT (dialog), "color_selection", &selection, NULL);
2284 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2285 gtk_color_selection_set_previous_color (GTK_COLOR_SELECTION (selection), &(buffer_format->color));
2286 g_free (buffer_format);
2288 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2290 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION(selection), &col);
2291 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2294 gtk_widget_destroy (dialog);
2301 create_stream_for_uri (const gchar* uri)
2306 TnyStream *result = NULL;
2308 GnomeVFSHandle *handle = NULL;
2309 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2310 if (test == GNOME_VFS_OK) {
2311 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2312 /* Streams over OBEX (Bluetooth) are not seekable but
2313 * we expect them to be (we might need to read them
2314 * several times). So if this is a Bluetooth URI just
2315 * read the whole file into memory (this is not a fast
2316 * protocol so we can assume that these files are not
2317 * going to be very big) */
2318 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2319 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2320 TnyStream *memstream = tny_camel_mem_stream_new ();
2321 tny_stream_write_to_stream (vfssstream, memstream);
2322 g_object_unref (vfssstream);
2325 result = vfssstream;
2333 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2336 ModestMsgEditWindowPrivate *priv;
2337 GtkWidget *dialog = NULL;
2339 GSList *uris = NULL;
2340 GSList *uri_node = NULL;
2342 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2344 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2345 _("mcen_ia_select_inline_image_title"),
2346 (GtkWindow *) window,
2347 GTK_FILE_CHOOSER_ACTION_OPEN);
2348 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2350 #ifdef MODEST_TOOLKIT_HILDON2
2351 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2354 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2355 GTK_WINDOW (dialog), GTK_WINDOW (window));
2357 response = gtk_dialog_run (GTK_DIALOG (dialog));
2359 case GTK_RESPONSE_OK:
2361 gchar *current_folder;
2362 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2363 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2364 if (current_folder && current_folder != '\0') {
2366 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2367 current_folder, &err);
2369 g_debug ("Error storing latest used folder: %s", err->message);
2373 g_free (current_folder);
2379 gtk_widget_destroy (dialog);
2381 g_object_ref (window);
2382 /* The operation could take some time so allow the dialog to be closed */
2383 while (gtk_events_pending ())
2384 gtk_main_iteration ();
2386 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2388 GnomeVFSHandle *handle = NULL;
2389 GnomeVFSResult result;
2390 GtkTextIter position;
2391 GtkTextMark *insert_mark;
2393 uri = (const gchar *) uri_node->data;
2394 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2395 if (result == GNOME_VFS_OK) {
2397 GnomeVFSFileInfo *info;
2398 gchar *filename, *basename, *escaped_filename;
2399 TnyMimePart *mime_part;
2401 const gchar *mime_type = NULL;
2402 GnomeVFSURI *vfs_uri;
2403 guint64 stream_size;
2405 gnome_vfs_close (handle);
2406 vfs_uri = gnome_vfs_uri_new (uri);
2408 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2409 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2410 g_free (escaped_filename);
2411 gnome_vfs_uri_unref (vfs_uri);
2412 info = gnome_vfs_file_info_new ();
2414 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2415 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2417 mime_type = gnome_vfs_file_info_get_mime_type (info);
2419 mime_part = tny_platform_factory_new_mime_part
2420 (modest_runtime_get_platform_factory ());
2422 TnyStream *stream = create_stream_for_uri (uri);
2424 if (stream == NULL) {
2426 modest_platform_information_banner (NULL, NULL,
2427 _FM("sfil_ib_opening_not_allowed"));
2429 g_object_unref (mime_part);
2430 gnome_vfs_file_info_unref (info);
2434 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2436 content_id = g_strdup_printf ("%d", priv->next_cid);
2437 tny_mime_part_set_content_id (mime_part, content_id);
2438 g_free (content_id);
2441 basename = g_path_get_basename (filename);
2442 tny_mime_part_set_filename (mime_part, basename);
2445 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2447 if (pixbuf != NULL) {
2448 priv->images_size += stream_size;
2449 priv->images_count ++;
2450 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2451 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2452 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2453 tny_mime_part_get_content_id (mime_part), pixbuf);
2454 g_object_unref (pixbuf);
2456 tny_list_prepend (priv->images, (GObject *) mime_part);
2457 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2459 modest_platform_information_banner (NULL, NULL,
2460 _("mail_ib_file_operation_failed"));
2464 g_object_unref (mime_part);
2465 gnome_vfs_file_info_unref (info);
2469 g_object_unref (window);
2473 on_attach_file_response (GtkDialog *dialog,
2477 GSList *uris = NULL;
2479 GnomeVFSFileSize total_size, allowed_size;
2480 ModestMsgEditWindow *window;
2481 ModestMsgEditWindowPrivate *priv;
2486 case GTK_RESPONSE_OK:
2488 gchar *current_folder;
2490 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2491 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2492 if (current_folder && current_folder != '\0') {
2494 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2495 current_folder, &err);
2497 g_debug ("Error storing latest used folder: %s", err->message);
2501 g_free (current_folder);
2508 window = MODEST_MSG_EDIT_WINDOW (user_data);
2509 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2511 /* allowed size is the maximum size - what's already there */
2512 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2513 &att_num, &att_size);
2514 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2517 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2519 const gchar *uri = (const gchar *) uri_node->data;
2522 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2524 if (total_size > allowed_size) {
2525 g_debug ("%s: total size: %u",
2526 __FUNCTION__, (unsigned int)total_size);
2529 allowed_size -= total_size;
2531 g_slist_foreach (uris, (GFunc) g_free, NULL);
2532 g_slist_free (uris);
2534 gtk_widget_destroy (GTK_WIDGET (dialog));
2538 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2540 GtkWidget *dialog = NULL;
2541 ModestMsgEditWindowPrivate *priv;
2544 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2548 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2551 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2552 _("mcen_ia_select_attachment_title"),
2553 (GtkWindow *) window,
2554 GTK_FILE_CHOOSER_ACTION_OPEN);
2555 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2556 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2557 if (conf_folder && conf_folder[0] != '\0') {
2558 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2561 /* Set the default folder to documents folder */
2562 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2563 #ifdef MODEST_TOOLKIT_HILDON2
2566 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2567 ".documents", NULL);
2570 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2571 g_free (docs_folder);
2573 g_free (conf_folder);
2574 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2575 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2576 GTK_WINDOW (dialog), GTK_WINDOW (window));
2578 /* Connect to response & show */
2579 g_signal_connect (dialog, "response",
2580 G_CALLBACK (on_attach_file_response), window);
2581 gtk_widget_show (dialog);
2586 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2588 GnomeVFSFileSize allowed_size)
2591 GnomeVFSHandle *handle = NULL;
2592 ModestMsgEditWindowPrivate *priv;
2593 GnomeVFSResult result;
2594 GnomeVFSFileSize size = 0;
2595 g_return_val_if_fail (window, 0);
2596 g_return_val_if_fail (uri, 0);
2598 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2600 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2601 if (result == GNOME_VFS_OK) {
2602 TnyMimePart *mime_part;
2604 const gchar *mime_type = NULL;
2606 gchar *escaped_filename;
2609 GnomeVFSFileInfo *info;
2610 GnomeVFSURI *vfs_uri;
2612 gnome_vfs_close (handle);
2613 vfs_uri = gnome_vfs_uri_new (uri);
2616 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2617 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2618 g_free (escaped_filename);
2619 gnome_vfs_uri_unref (vfs_uri);
2621 info = gnome_vfs_file_info_new ();
2623 if (gnome_vfs_get_file_info (uri,
2625 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2627 mime_type = gnome_vfs_file_info_get_mime_type (info);
2628 mime_part = tny_platform_factory_new_mime_part
2629 (modest_runtime_get_platform_factory ());
2631 /* try to get the attachment's size; this may fail for weird
2632 * file systems, like obex, upnp... */
2633 if (allowed_size != 0 &&
2634 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2636 if (size > allowed_size) {
2637 modest_platform_information_banner (NULL, NULL,
2638 _("mail_ib_error_attachment_size"));
2643 g_debug ("%s: could not get attachment size", __FUNCTION__);
2645 stream = create_stream_for_uri (uri);
2647 if (stream == NULL) {
2649 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2651 g_object_unref (mime_part);
2653 gnome_vfs_file_info_unref (info);
2657 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2658 g_object_unref (stream);
2660 content_id = g_strdup_printf ("%d", priv->next_cid);
2661 tny_mime_part_set_content_id (mime_part, content_id);
2662 g_free (content_id);
2665 basename = g_path_get_basename (filename);
2666 tny_mime_part_set_filename (mime_part, basename);
2669 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2670 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2672 info->size == 0, info->size);
2673 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2674 gtk_widget_show_all (priv->attachments_caption);
2675 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2677 g_object_unref (mime_part);
2678 gnome_vfs_file_info_unref (info);
2685 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2688 ModestMsgEditWindowPrivate *priv;
2691 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2692 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2694 if (att_list == NULL) {
2695 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2696 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2697 g_object_unref (att_list);
2701 g_object_ref (att_list);
2704 if (tny_list_get_length (att_list) == 0) {
2705 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2707 gboolean dialog_response;
2708 gchar *message = NULL;
2709 gchar *filename = NULL;
2711 if (tny_list_get_length (att_list) == 1) {
2713 iter = tny_list_create_iterator (att_list);
2714 part = (TnyMimePart *) tny_iterator_get_current (iter);
2715 g_object_unref (iter);
2716 if (TNY_IS_MSG (part)) {
2717 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2719 filename = tny_header_dup_subject (header);
2720 g_object_unref (header);
2722 if (filename == NULL) {
2723 filename = g_strdup (_("mail_va_no_subject"));
2726 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2728 g_object_unref (part);
2730 filename = g_strdup ("");
2732 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2733 "emev_nc_delete_attachments",
2734 tny_list_get_length (att_list)), filename);
2737 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2741 if (dialog_response != GTK_RESPONSE_OK) {
2742 g_object_unref (att_list);
2746 for (iter = tny_list_create_iterator (att_list);
2747 !tny_iterator_is_done (iter);
2748 tny_iterator_next (iter)) {
2749 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2750 const gchar *att_id;
2751 tny_list_remove (priv->attachments, (GObject *) mime_part);
2753 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2755 if (tny_list_get_length (priv->attachments) == 0)
2756 gtk_widget_hide (priv->attachments_caption);
2757 att_id = tny_mime_part_get_content_id (mime_part);
2759 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2761 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2762 g_object_unref (mime_part);
2764 g_object_unref (iter);
2767 g_object_unref (att_list);
2769 /* if the last attachment has been removed, focus the Subject: field */
2770 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2771 gtk_widget_grab_focus (priv->subject_field);
2775 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2778 ModestMsgEditWindowPrivate *priv;
2781 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2783 gtk_color_button_get_color (GTK_COLOR_BUTTON(priv->font_color_button), &new_color);
2785 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2787 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2791 font_size_clicked (GtkToolButton *button,
2792 ModestMsgEditWindow *window)
2794 #ifdef MODEST_TOOLKIT_HILDON2
2795 ModestMsgEditWindowPrivate *priv;
2796 GtkWidget *selector, *dialog;
2798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2800 selector = hildon_touch_selector_new ();
2801 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2802 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2804 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2805 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2806 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2808 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2812 WPTextBufferFormat format;
2814 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2816 memset (&format, 0, sizeof (format));
2817 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2819 format.cs.font_size = TRUE;
2820 format.cs.text_position = TRUE;
2821 format.cs.font = TRUE;
2822 format.font_size = new_index;
2823 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2825 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2826 GINT_TO_POINTER (new_index)))
2827 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2829 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2830 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2831 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2832 size_text, "</span>", NULL);
2834 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2838 gtk_widget_destroy (dialog);
2840 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2845 font_face_clicked (GtkToolButton *button,
2846 ModestMsgEditWindow *window)
2848 #ifdef MODEST_TOOLKIT_HILDON2
2849 ModestMsgEditWindowPrivate *priv;
2850 GtkWidget *selector, *dialog;
2851 GtkCellRenderer *renderer;
2853 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2855 selector = hildon_touch_selector_new ();
2856 renderer = gtk_cell_renderer_text_new ();
2857 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2858 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2859 renderer, "family", 0, "text", 0, NULL);
2860 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2862 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2863 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2864 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2866 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2867 gint new_font_index;
2871 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2872 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2873 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2877 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2879 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2880 GINT_TO_POINTER(new_font_index)))
2881 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2883 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2884 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2886 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2890 gtk_tree_path_free (path);
2893 gtk_widget_destroy (dialog);
2895 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2900 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2903 ModestMsgEditWindowPrivate *priv = NULL;
2904 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2906 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2907 if (!priv->update_caption_visibility)
2910 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2912 gtk_widget_show (priv->cc_caption);
2914 gtk_widget_hide (priv->cc_caption);
2916 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2920 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2923 ModestMsgEditWindowPrivate *priv = NULL;
2924 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2926 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2927 if (!priv->update_caption_visibility)
2930 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2932 gtk_widget_show (priv->bcc_caption);
2934 gtk_widget_hide (priv->bcc_caption);
2936 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2940 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2941 ModestRecptEditor *editor)
2943 ModestMsgEditWindowPrivate *priv;
2945 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2946 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2948 /* we check for low-mem; in that case, show a warning, and don't allow
2949 * for the addressbook
2951 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2954 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2956 if (editor == NULL) {
2957 GtkWidget *view_focus, *parent;
2958 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2960 /* This code should be kept in sync with ModestRecptEditor. The
2961 textview inside the recpt editor is the one that really gets the
2962 focus. As it's inside a scrolled window, and this one inside the
2963 hbox recpt editor inherits from, we'll need to go up in the
2964 hierarchy to know if the text view is part of the recpt editor
2965 or if it's a different text entry */
2966 parent = gtk_widget_get_parent (view_focus);
2967 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2968 editor = MODEST_RECPT_EDITOR (parent);
2971 editor = MODEST_RECPT_EDITOR (priv->to_field);
2974 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2978 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2980 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2982 modest_msg_edit_window_open_addressbook (window, NULL);
2986 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2987 gboolean show_toolbar)
2989 ModestWindowPrivate *parent_priv;
2990 ModestMsgEditWindowPrivate *priv;
2992 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2993 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2994 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2996 /* We can not just use the code of
2997 modest_msg_edit_window_setup_toolbar because it has a
2998 mixture of both initialization and creation code. */
3000 gint current_format;
3001 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3002 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3003 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3004 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3006 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
3009 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3014 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
3015 TnyHeaderFlags priority_flags)
3017 ModestMsgEditWindowPrivate *priv;
3018 ModestWindowPrivate *parent_priv;
3020 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3022 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3023 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3025 if (priv->priority_flags != priority_flags) {
3026 GtkAction *priority_action = NULL;
3028 priv->priority_flags = priority_flags;
3030 switch (priority_flags) {
3031 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3032 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3033 MODEST_HEADER_ICON_HIGH,
3034 #ifdef MODEST_TOOLKIT_HILDON2
3035 HILDON_ICON_SIZE_SMALL
3037 GTK_ICON_SIZE_BUTTON
3040 gtk_widget_show (priv->priority_icon);
3041 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3042 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3044 case TNY_HEADER_FLAG_LOW_PRIORITY:
3045 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3046 MODEST_HEADER_ICON_LOW,
3047 #ifdef MODEST_TOOLKIT_HILDON2
3048 HILDON_ICON_SIZE_SMALL
3050 GTK_ICON_SIZE_BUTTON
3053 gtk_widget_show (priv->priority_icon);
3054 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3055 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3058 gtk_widget_hide (priv->priority_icon);
3059 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3060 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3063 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3064 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3066 gtk_widget_queue_resize (priv->subject_box);
3070 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3073 ModestMsgEditWindowPrivate *priv;
3074 ModestWindowPrivate *parent_priv;
3075 gint current_format;
3077 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3079 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3080 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3082 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3083 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3085 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3087 if (current_format != file_format) {
3088 switch (file_format) {
3089 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3090 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3091 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3092 if (parent_priv->toolbar)
3093 gtk_widget_show (parent_priv->toolbar);
3095 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3098 response = modest_platform_run_confirmation_dialog (NULL, _("emev_nc_formatting_lost"));
3099 if (response == GTK_RESPONSE_OK) {
3100 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3101 if (parent_priv->toolbar)
3102 gtk_widget_hide (parent_priv->toolbar);
3104 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3105 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3110 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3111 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3112 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3117 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3119 #ifdef MODEST_TOOLKIT_HILDON2
3121 ModestMsgEditWindowPrivate *priv;
3122 WPTextBufferFormat oldfmt, fmt;
3123 gint old_position = 0;
3127 GdkColor *color = NULL;
3128 gboolean bold, bold_set, italic, italic_set;
3129 gboolean underline, underline_set;
3130 gboolean strikethrough, strikethrough_set;
3131 gboolean position_set;
3132 gboolean font_size_set, font_set, color_set;
3135 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3136 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3138 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3139 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3140 GTK_WINDOW(dialog), GTK_WINDOW (window));
3142 /* First we get the currently selected font information */
3143 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3145 switch (oldfmt.text_position) {
3146 case TEXT_POSITION_NORMAL:
3149 case TEXT_POSITION_SUPERSCRIPT:
3157 g_object_set (G_OBJECT (dialog),
3158 "bold", oldfmt.bold != FALSE,
3159 "bold-set", !oldfmt.cs.bold,
3160 "underline", oldfmt.underline != FALSE,
3161 "underline-set", !oldfmt.cs.underline,
3162 "italic", oldfmt.italic != FALSE,
3163 "italic-set", !oldfmt.cs.italic,
3164 "strikethrough", oldfmt.strikethrough != FALSE,
3165 "strikethrough-set", !oldfmt.cs.strikethrough,
3166 "color", &oldfmt.color,
3167 "color-set", !oldfmt.cs.color,
3168 "size", wp_font_size[oldfmt.font_size],
3169 "size-set", !oldfmt.cs.font_size,
3170 "position", old_position,
3171 "position-set", !oldfmt.cs.text_position,
3172 "family", wp_get_font_name (oldfmt.font),
3173 "family-set", !oldfmt.cs.font,
3176 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3177 GTK_WINDOW (dialog), GTK_WINDOW (window));
3178 gtk_widget_show_all (dialog);
3179 priv->font_dialog = dialog;
3180 response = gtk_dialog_run (GTK_DIALOG (dialog));
3181 priv->font_dialog = NULL;
3182 if (response == GTK_RESPONSE_OK) {
3184 g_object_get( dialog,
3186 "bold-set", &bold_set,
3187 "underline", &underline,
3188 "underline-set", &underline_set,
3190 "italic-set", &italic_set,
3191 "strikethrough", &strikethrough,
3192 "strikethrough-set", &strikethrough_set,
3194 "color-set", &color_set,
3196 "size-set", &font_size_set,
3197 "family", &font_name,
3198 "family-set", &font_set,
3199 "position", &position,
3200 "position-set", &position_set,
3205 if (response == GTK_RESPONSE_OK) {
3206 memset(&fmt, 0, sizeof(fmt));
3212 fmt.italic = italic;
3213 fmt.cs.italic = TRUE;
3215 if (underline_set) {
3216 fmt.underline = underline;
3217 fmt.cs.underline = TRUE;
3219 if (strikethrough_set) {
3220 fmt.strikethrough = strikethrough;
3221 fmt.cs.strikethrough = TRUE;
3226 ? TEXT_POSITION_NORMAL
3227 : ( ( position == 1 )
3228 ? TEXT_POSITION_SUPERSCRIPT
3229 : TEXT_POSITION_SUBSCRIPT );
3230 fmt.cs.text_position = TRUE;
3231 fmt.font_size = oldfmt.font_size;
3235 fmt.cs.color = TRUE;
3238 fmt.font = wp_get_font_index(font_name,
3243 if (font_size_set) {
3244 fmt.cs.font_size = TRUE;
3245 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3247 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3248 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3250 gtk_widget_destroy (dialog);
3252 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3257 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3259 ModestMsgEditWindowPrivate *priv;
3260 ModestWindowPrivate *parent_priv;
3261 gboolean was_rich_text, is_rich_text;
3263 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3264 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3265 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3267 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3269 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3271 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3273 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3275 gtk_widget_show (parent_priv->toolbar);
3277 gtk_widget_hide (parent_priv->toolbar);
3280 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3281 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3285 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3287 ModestMsgEditWindowPrivate *priv;
3289 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3290 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3292 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3294 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3295 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3300 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3302 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3304 priv->can_undo = can_undo;
3308 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3310 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3312 priv->can_redo = can_redo;
3316 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3318 ModestMsgEditWindowPrivate *priv;
3319 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3320 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3322 return priv->can_undo;
3326 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3328 ModestMsgEditWindowPrivate *priv;
3329 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3330 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3332 return priv->can_redo;
3337 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3340 GtkTextIter match_start, match_end;
3342 if (image_id == NULL)
3345 gtk_text_buffer_get_start_iter (buffer, &iter);
3347 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3348 GSList *tags = gtk_text_iter_get_tags (&match_start);
3350 for (node = tags; node != NULL; node = g_slist_next (node)) {
3351 GtkTextTag *tag = (GtkTextTag *) node->data;
3352 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3353 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3354 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3356 offset = gtk_text_iter_get_offset (&match_start);
3357 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3358 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3362 gtk_text_iter_forward_char (&iter);
3367 message_is_empty (ModestMsgEditWindow *window)
3369 ModestMsgEditWindowPrivate *priv = NULL;
3371 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3372 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3374 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3375 * so we can ignore markup.
3377 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3380 count = gtk_text_buffer_get_char_count (buf);
3386 msg_body_focus (GtkWidget *focus,
3387 GdkEventFocus *event,
3391 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3392 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3393 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3398 recpt_field_changed (GtkTextBuffer *buffer,
3399 ModestMsgEditWindow *editor)
3401 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3402 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3406 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3408 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3409 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3413 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3416 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3417 GtkTextBuffer *buffer;
3419 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3420 gtk_text_buffer_set_modified (buffer, modified);
3421 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3422 gtk_text_buffer_set_modified (buffer, modified);
3423 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3424 gtk_text_buffer_set_modified (buffer, modified);
3425 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3429 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3431 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3432 const char *account_name;
3433 GtkTextBuffer *buffer;
3435 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3436 if (gtk_text_buffer_get_modified (buffer))
3438 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3439 if (gtk_text_buffer_get_modified (buffer))
3441 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3442 if (gtk_text_buffer_get_modified (buffer))
3444 if (gtk_text_buffer_get_modified (priv->text_buffer))
3447 account_name = modest_selector_get_active_id (priv->from_field);
3448 if (priv->original_mailbox) {
3449 if (!account_name || strcmp (account_name, priv->original_mailbox))
3451 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3462 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3464 ModestMsgEditWindowPrivate *priv = NULL;
3465 GSList *address_list = NULL;
3467 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3468 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3470 /* check if there's no recipient added */
3471 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3472 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3473 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3474 /* no recipient contents, then select contacts */
3475 modest_msg_edit_window_open_addressbook (window, NULL);
3480 g_object_ref (window);
3481 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3482 (add_to_addressbook) ? &address_list : NULL)) {
3483 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3484 g_object_unref (window);
3487 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3488 (add_to_addressbook) ? &address_list : NULL)) {
3489 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3490 g_object_unref (window);
3493 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3494 (add_to_addressbook) ? &address_list : NULL)) {
3495 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3496 g_object_unref (window);
3500 /* Add contacts to address book */
3501 if (add_to_addressbook && address_list)
3502 modest_address_book_add_address_list (address_list);
3504 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3505 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3506 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3507 g_object_unref (window);
3514 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3516 GSList *recipients = NULL;
3517 ModestMsgEditWindowPrivate *priv;
3518 gchar *joined, *after_remove, *to, *cc, *bcc;
3520 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3522 /* First of all check names */
3523 if (!modest_msg_edit_window_check_names (self, FALSE))
3526 if (!modest_msg_edit_window_has_pending_addresses (self))
3529 /* Don't add the from obviously */
3530 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3531 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3532 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3534 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3539 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3542 recipients = modest_text_utils_split_addresses_list (after_remove);
3543 g_free (after_remove);
3546 /* Offer the user to add recipients to the address book */
3547 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3548 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3553 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3554 ModestMsgEditWindow *window)
3556 modest_msg_edit_window_offer_attach_file (window);
3560 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3562 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3564 return priv->clipboard_text;
3568 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3570 ModestMsgEditWindow *window)
3572 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3573 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3576 /* It could happen that the window was already closed */
3577 if (!GTK_WIDGET_VISIBLE (window))
3580 g_object_ref (window);
3581 text = gtk_clipboard_wait_for_text (selection_clipboard);
3583 if (priv->clipboard_text != NULL) {
3584 g_free (priv->clipboard_text);
3586 priv->clipboard_text = text;
3588 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3590 g_object_unref (window);
3593 static gboolean clipboard_owner_change_idle (gpointer userdata)
3595 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3596 ModestMsgEditWindowPrivate *priv;
3598 gdk_threads_enter ();
3599 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3600 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3602 priv->clipboard_owner_idle = 0;
3603 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3604 gdk_threads_leave ();
3610 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3612 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3613 if (priv->clipboard_owner_idle == 0) {
3614 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3615 clipboard_owner_change_idle,
3616 g_object_ref (window),
3622 subject_field_move_cursor (GtkEntry *entry,
3623 GtkMovementStep step,
3628 /* It could happen that the window was already closed */
3629 if (!GTK_WIDGET_VISIBLE (window))
3632 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3636 update_window_title (ModestMsgEditWindow *window)
3638 ModestMsgEditWindowPrivate *priv = NULL;
3639 const gchar *subject;
3641 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3642 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3643 if (subject == NULL || subject[0] == '\0')
3644 subject = _("mail_va_new_email");
3646 modest_window_set_title (MODEST_WINDOW (window), subject);
3652 body_insert_text (GtkTextBuffer *buffer,
3653 GtkTextIter *location,
3656 ModestMsgEditWindow *window)
3658 GtkTextIter end_iter;
3665 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3667 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3669 offset = gtk_text_iter_get_offset (&end_iter);
3670 line = gtk_text_iter_get_line (&end_iter);
3674 while (text_offset < text + len) {
3675 if (*text_offset == '\n')
3677 if (text_lines + line >= MAX_BODY_LINES) {
3678 len = text_offset - text;
3684 utf8_len = g_utf8_strlen (text, len);
3686 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3687 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3688 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3693 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3695 /* Prevent endless recursion */
3696 result = g_strndup (text, utf8_end - text);
3697 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3698 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3699 (gpointer) result, (gpointer) (utf8_end - text),
3701 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3705 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3706 if (priv->max_chars_banner == NULL) {
3707 #ifdef MODEST_TOOLKIT_HILDON2
3708 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3709 _CS("ckdg_ib_maximum_characters_reached"));
3710 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3717 subject_field_changed (GtkEditable *editable,
3718 ModestMsgEditWindow *window)
3720 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3721 update_window_title (window);
3722 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3723 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3724 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3727 subject_field_insert_text (GtkEditable *editable,
3729 gint new_text_length,
3731 ModestMsgEditWindow *window)
3733 GString *result = g_string_new ("");
3735 gint result_len = 0;
3736 const gchar *entry_text = NULL;
3739 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3740 old_length = g_utf8_strlen (entry_text, -1);
3742 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3743 gunichar c = g_utf8_get_char_validated (current, 8);
3744 /* Invalid unichar, stop */
3750 result = g_string_append_unichar (result, c);
3754 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3755 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3758 /* Prevent endless recursion */
3759 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3760 g_signal_emit_by_name (editable, "insert-text",
3761 (gpointer) result->str, (gpointer) result->len,
3762 (gpointer) position, (gpointer) window);
3763 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3767 if (result_len + old_length > 1000) {
3768 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3769 _CS("ckdg_ib_maximum_characters_reached"));
3771 g_string_free (result, TRUE);
3775 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3778 ModestMsgEditWindowPrivate *priv = NULL;
3780 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3781 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3783 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3786 gtk_widget_show_all (priv->isearch_toolbar);
3787 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3789 gtk_widget_hide_all (priv->isearch_toolbar);
3790 gtk_widget_grab_focus (priv->msg_body);
3795 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3797 GtkTextIter *match_start,
3798 GtkTextIter *match_end)
3800 GtkTextIter end_iter;
3801 gchar *str_casefold;
3804 gchar *range_casefold;
3807 gboolean result = FALSE;
3814 gtk_text_iter_forward_to_end (&end_iter);
3816 str_casefold = g_utf8_casefold (str, -1);
3817 str_chars_n = strlen (str);
3819 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3820 range_casefold = g_utf8_casefold (range_text, -1);
3821 range_chars_n = strlen (range_casefold);
3823 if (range_chars_n < str_chars_n) {
3824 g_free (str_casefold);
3825 g_free (range_text);
3826 g_free (range_casefold);
3830 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3831 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3832 if (!g_utf8_collate (range_subtext, str_casefold)) {
3833 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3835 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3836 match_start, match_end, NULL)) {
3837 g_debug ("Matched string with collate, but not matched in model");
3839 g_free (found_text);
3841 g_free (range_subtext);
3845 g_free (str_casefold);
3846 g_free (range_text);
3847 g_free (range_casefold);
3854 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
3855 ModestMsgEditWindow *window)
3857 const gchar *current_search = NULL;
3858 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3860 GtkTextIter selection_start, selection_end;
3861 GtkTextIter match_start, match_end;
3862 gboolean continue_search = FALSE;
3864 if (message_is_empty (window)) {
3865 g_free (priv->last_search);
3866 priv->last_search = NULL;
3867 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3871 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
3872 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3873 g_free (priv->last_search);
3874 priv->last_search = NULL;
3875 /* Information banner about empty search */
3876 modest_platform_system_banner (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3880 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3881 continue_search = TRUE;
3883 g_free (priv->last_search);
3884 priv->last_search = g_strdup (current_search);
3887 if (continue_search) {
3888 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3889 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3890 &match_start, &match_end);
3892 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3894 GtkTextIter buffer_start;
3895 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3896 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3897 &match_start, &match_end);
3899 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3902 /* Mark as selected the string found in search */
3904 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3905 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3906 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3908 g_free (priv->last_search);
3909 priv->last_search = NULL;
3914 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3916 ModestMsgEditWindowPrivate *priv;
3918 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3923 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3926 ModestMsgEditWindowPrivate *priv;
3928 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3933 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
3934 ModestMsgEditWindow *window)
3936 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
3940 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3943 ModestMsgEditWindowPrivate *priv;
3944 TnyHeader *header = NULL;
3946 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3947 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3949 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3951 if (priv->draft_msg != NULL) {
3952 g_object_unref (priv->draft_msg);
3955 if (draft != NULL) {
3956 g_object_ref (draft);
3957 header = tny_msg_get_header (draft);
3958 if (priv->msg_uid) {
3959 g_free (priv->msg_uid);
3960 priv->msg_uid = NULL;
3962 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3965 priv->draft_msg = draft;
3969 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3970 GtkTextIter *start, GtkTextIter *end,
3973 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3974 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3977 if (tag == NULL) return;
3978 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3979 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3980 replace_with_images (window, priv->images);
3985 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3988 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3990 g_return_if_fail (TNY_IS_MIME_PART (part));
3991 tny_list_prepend (priv->attachments, (GObject *) part);
3992 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3993 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3994 gtk_widget_show_all (priv->attachments_caption);
3995 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3999 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
4001 ModestMsgEditWindowPrivate *priv;
4003 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
4004 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4006 return priv->msg_uid;
4010 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
4011 ModestMsgEditWindowWidgetType widget_type)
4013 ModestMsgEditWindowPrivate *priv;
4015 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
4016 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
4018 switch (widget_type) {
4019 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
4020 return priv->msg_body;
4022 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
4023 return priv->to_field;
4025 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
4026 return priv->cc_field;
4028 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4029 return priv->bcc_field;
4031 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4032 return priv->subject_field;
4034 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4035 return priv->attachments_view;
4043 remove_tags (WPTextBuffer *buffer)
4045 GtkTextIter start, end;
4047 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4048 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4050 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4054 on_account_removed (TnyAccountStore *account_store,
4055 TnyAccount *account,
4058 /* Do nothing if it's a store account, because we use the
4059 transport to send the messages */
4060 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4061 const gchar *parent_acc = NULL;
4062 const gchar *our_acc = NULL;
4064 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4065 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4066 /* Close this window if I'm showing a message of the removed account */
4067 if (strcmp (parent_acc, our_acc) == 0)
4068 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4073 update_signature (ModestMsgEditWindow *self,
4074 const gchar *old_account,
4075 const gchar *new_account)
4077 ModestMsgEditWindowPrivate *priv;
4078 gboolean has_old_signature, has_new_signature;
4080 ModestAccountMgr *mgr;
4083 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4085 gtk_text_buffer_begin_user_action (priv->text_buffer);
4087 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4088 mgr = modest_runtime_get_account_mgr ();
4092 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4093 if (has_old_signature) {
4094 GtkTextIter match_start, match_end;
4096 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4097 seems that the search has some problems
4098 with the blank space at the end */
4099 if (gtk_text_iter_forward_search (&iter, "--",
4100 GTK_TEXT_SEARCH_TEXT_ONLY,
4101 &match_start, NULL, NULL)) {
4102 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4103 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4105 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4106 &match_start, &match_end, NULL)) {
4110 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4115 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4116 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4117 if (has_new_signature) {
4119 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4120 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4122 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4123 g_free (full_signature);
4126 gtk_text_buffer_end_user_action (priv->text_buffer);
4129 static void update_branding (ModestMsgEditWindow *self,
4130 const gchar *new_account)
4132 ModestMsgEditWindowPrivate *priv;
4133 ModestAccountMgr *mgr;
4134 const GdkPixbuf *new_icon = NULL;
4135 gchar *new_label = NULL;
4136 gboolean show = FALSE;
4138 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4140 mgr = modest_runtime_get_account_mgr ();
4142 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4144 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4145 gtk_widget_show (priv->brand_icon);
4148 gtk_widget_hide (priv->brand_icon);
4151 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4152 gtk_widget_show (priv->brand_label);
4156 gtk_widget_hide (priv->brand_label);
4160 gtk_widget_show (priv->brand_container);
4162 gtk_widget_hide (priv->brand_container);
4166 from_field_changed (GtkWidget *button,
4167 ModestMsgEditWindow *self)
4169 ModestMsgEditWindowPrivate *priv;
4170 gchar *old_account, *new_account;
4172 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4174 old_account = priv->last_from_account;
4175 new_account = modest_selector_get_active_id (priv->from_field);
4178 g_warning ("%s, could not get the new account", __FUNCTION__);
4182 /* If the From is the same do nothing */
4183 if (old_account && new_account && !strcmp (old_account, new_account))
4186 priv->last_from_account = new_account;
4188 update_signature (self, old_account, new_account);
4189 update_branding (self, new_account);
4193 typedef struct _MessageSettingsHelper {
4194 ModestMsgEditWindow *window;
4195 GSList *priority_group;
4196 GSList *format_group;
4197 GtkToggleButton *current_priority;
4198 GtkToggleButton *current_format;
4199 } MessageSettingsHelper;
4202 on_priority_toggle (GtkToggleButton *button,
4203 MessageSettingsHelper *helper)
4206 ModestMsgEditWindowPrivate *priv;
4208 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4209 if (gtk_toggle_button_get_active (button)) {
4211 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4212 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4213 if ((node_button != button) &&
4214 gtk_toggle_button_get_active (node_button)) {
4215 gtk_toggle_button_set_active (node_button, FALSE);
4218 helper->current_priority = button;
4220 gboolean found = FALSE;
4221 /* If no one is active, activate it again */
4222 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4223 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4224 if (gtk_toggle_button_get_active (node_button)) {
4230 gtk_toggle_button_set_active (button, TRUE);
4236 on_format_toggle (GtkToggleButton *button,
4237 MessageSettingsHelper *helper)
4240 ModestMsgEditWindowPrivate *priv;
4242 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4243 if (gtk_toggle_button_get_active (button)) {
4245 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4246 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4247 if ((node_button != button) &&
4248 gtk_toggle_button_get_active (node_button)) {
4249 gtk_toggle_button_set_active (node_button, FALSE);
4252 helper->current_format = button;
4254 gboolean found = FALSE;
4255 /* If no one is active, activate it again */
4256 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4257 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4258 if (gtk_toggle_button_get_active (node_button)) {
4264 gtk_toggle_button_set_active (button, TRUE);
4271 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4273 #ifdef MODEST_TOOLKIT_HILDON2
4277 GtkWidget *priority_hbox;
4278 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4279 GtkWidget *captioned;
4280 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4281 GtkWidget *format_hbox;
4282 GtkWidget *html_toggle, *text_toggle;
4283 ModestMsgEditWindowPrivate *priv;
4284 MessageSettingsHelper helper = {0,};
4286 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4287 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4288 helper.window = window;
4289 helper.priority_group = NULL;
4290 helper.format_group = NULL;
4292 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4293 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4295 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4296 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4297 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4298 vbox = gtk_vbox_new (FALSE, 0);
4299 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4300 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4301 gtk_container_add (GTK_CONTAINER (align), vbox);
4302 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4303 gtk_widget_show (align);
4304 gtk_widget_show (vbox);
4306 /* Priority toggles */
4307 priority_hbox = gtk_hbox_new (TRUE, 0);
4308 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4309 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4310 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4311 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4312 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4313 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4314 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4315 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4316 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4317 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4318 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4319 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4320 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4321 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4322 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4323 gtk_widget_show_all (priority_hbox);
4324 captioned = modest_toolkit_utils_create_captioned (title_sizegroup, value_sizegroup,
4325 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4326 gtk_widget_show (captioned);
4327 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4329 /* format toggles */
4330 format_hbox = gtk_hbox_new (TRUE, 0);
4331 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4332 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4333 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4334 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4335 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4336 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4337 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4338 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4339 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4340 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4341 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4342 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4343 gtk_widget_show_all (format_hbox);
4344 gtk_widget_show (format_hbox);
4345 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4348 g_object_unref (title_sizegroup);
4349 g_object_unref (value_sizegroup);
4351 /* Set current values */
4352 switch (priv->priority_flags) {
4353 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4354 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4355 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4357 case TNY_HEADER_FLAG_LOW_PRIORITY:
4358 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4359 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4362 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4363 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4367 switch (modest_msg_edit_window_get_format (window)) {
4368 case MODEST_MSG_EDIT_FORMAT_TEXT:
4369 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4370 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4372 case MODEST_MSG_EDIT_FORMAT_HTML:
4374 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4375 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4379 /* Signal connects */
4380 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4381 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4382 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4383 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4384 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4386 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4387 GTK_WINDOW (dialog), GTK_WINDOW (window));
4389 /* Save settings if the user clicked on done */
4390 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4391 TnyHeaderFlags flags;
4392 ModestMsgEditFormat old_format, new_format;
4394 /* Set priority flags */
4395 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4396 if (priv->priority_flags != flags)
4397 modest_msg_edit_window_set_priority_flags (window, flags);
4399 /* Set edit format */
4400 old_format = modest_msg_edit_window_get_format (window);
4401 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4402 if (old_format != new_format) {
4403 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4404 modest_msg_edit_window_set_file_format (window, file_format);
4408 gtk_widget_destroy (dialog);
4409 g_slist_free (helper.priority_group);
4414 on_message_settings (GtkAction *action,
4415 ModestMsgEditWindow *window)
4417 modest_msg_edit_window_show_msg_settings_dialog (window);
4421 on_cc_button_toggled (GtkWidget *button,
4422 ModestMsgEditWindow *window)
4424 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4426 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4427 modest_togglable_get_active (button));
4431 on_bcc_button_toggled (GtkWidget *button,
4432 ModestMsgEditWindow *window)
4434 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4436 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4437 modest_togglable_get_active (button));
4441 setup_menu (ModestMsgEditWindow *self)
4443 ModestMsgEditWindowPrivate *priv = NULL;
4445 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4447 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4449 /* Settings menu buttons */
4450 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4451 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4453 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4454 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4455 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4456 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4457 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4458 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4460 #ifdef MODEST_TOOLKIT_HILDON2
4461 priv->cc_button = hildon_check_button_new (0);
4462 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4463 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4465 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4466 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4467 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4469 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4470 _("mcen_me_editor_showbcc"));
4471 modest_togglable_set_active (priv->bcc_button,
4473 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4475 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4476 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4479 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4480 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4481 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4482 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4483 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4485 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4486 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4487 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4488 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4489 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4491 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4492 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4497 emit_open_addressbook (GtkButton *button,
4498 ModestRecptEditor *editor)
4500 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4504 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4505 const gchar *label, GtkWidget *control)
4507 GtkWidget *abook_button;
4510 GtkWidget *label_widget;
4512 box = gtk_hbox_new (FALSE, 0);
4514 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4515 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4517 #ifdef MODEST_TOOLKIT_HILDON2
4518 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4520 abook_button = gtk_button_new ();
4522 label_widget = gtk_label_new (label);
4523 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4524 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4526 gtk_container_add (GTK_CONTAINER (align), abook_button);
4527 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4528 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4529 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4530 if (title_size_group)
4531 gtk_size_group_add_widget (title_size_group, label_widget);
4532 if (value_size_group)
4533 gtk_size_group_add_widget (value_size_group, control);
4535 g_signal_connect (G_OBJECT (abook_button), "clicked",
4536 G_CALLBACK (emit_open_addressbook), control);
4542 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4544 ModestMsgEditWindowPrivate *priv = NULL;
4546 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4548 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4549 priv->max_chars_banner = NULL;
4553 has_pending_addresses (ModestRecptEditor *recpt_editor)
4555 const gchar *recipients = NULL;
4556 GSList *start_indexes = NULL, *end_indexes = NULL;
4557 GSList *current_start, *current_end;
4558 GtkTextBuffer *buffer;
4559 gint offset_delta = 0;
4561 gboolean has_recipients_to_add = FALSE;
4563 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4564 last_length = g_utf8_strlen (recipients, -1);
4565 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4570 current_start = start_indexes;
4571 current_end = end_indexes;
4572 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4574 while (current_start && !has_recipients_to_add) {
4576 gchar *start_ptr, *end_ptr;
4577 gint start_pos, end_pos;
4579 start_pos = (*((gint*) current_start->data)) + offset_delta;
4580 end_pos = (*((gint*) current_end->data)) + offset_delta;
4582 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4583 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4585 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4587 if (modest_text_utils_validate_recipient (address, NULL)) {
4588 if (!modest_address_book_has_address (address)) {
4589 has_recipients_to_add = TRUE;
4592 current_start = g_slist_next (current_start);
4593 current_end = g_slist_next (current_end);
4595 return has_recipients_to_add;
4599 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4601 ModestMsgEditWindowPrivate *priv = NULL;
4603 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4605 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4607 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4608 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4609 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))