1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38 #include <tny-camel-mem-stream.h>
39 #include <modest-account-protocol.h>
43 #include <modest-account-mgr.h>
44 #include <modest-account-mgr-helpers.h>
46 #include <widgets/modest-msg-edit-window.h>
47 #include <modest-selector-picker.h>
48 #include <widgets/modest-recpt-editor.h>
49 #include <widgets/modest-attachments-view.h>
51 #include <modest-runtime.h>
53 #include "modest-platform.h"
54 #include "modest-icon-names.h"
55 #include "modest-widget-memory.h"
56 #include "modest-window-priv.h"
57 #include "modest-mail-operation.h"
58 #include "modest-tny-platform-factory.h"
59 #include "modest-tny-msg.h"
60 #include "modest-tny-folder.h"
61 #include "modest-tny-account.h"
62 #include "modest-address-book.h"
63 #include "modest-text-utils.h"
64 #include <tny-simple-list.h>
65 #include <modest-wp-text-view.h>
66 #include <wptextbuffer.h>
67 #include <modest-scrollable.h>
68 #include <modest-isearch-toolbar.h>
69 #include <hildon/hildon-touch-selector.h>
70 #include <hildon/hildon-picker-dialog.h>
71 #include "modest-msg-edit-window-ui-dimming.h"
73 #include "modest-hildon-includes.h"
74 #include "widgets/modest-msg-edit-window-ui.h"
75 #include <libgnomevfs/gnome-vfs-mime.h>
76 #include <modest-utils.h>
77 #include "modest-maemo-utils.h"
78 #include <modest-ui-constants.h>
80 #ifdef MODEST_USE_CALENDAR_WIDGETS
81 #include <calendar-ui-widgets.h>
84 #define DEFAULT_FONT_SIZE 3
85 #define DEFAULT_FONT 2
86 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
87 #define DEFAULT_MAIN_VBOX_SPACING 0
88 #define SUBJECT_MAX_LENGTH 1000
89 #define IMAGE_MAX_WIDTH 560
90 #define DEFAULT_FONT_SCALE 1.5
91 #define ATTACHMENT_BUTTON_WIDTH 118
92 #define MAX_FROM_VALUE 36
93 #define MAX_BODY_LENGTH 128*1024
94 #define MAX_BODY_LINES 2048
96 static gboolean is_wp_text_buffer_started = FALSE;
98 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
99 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
100 static void modest_msg_edit_window_finalize (GObject *obj);
102 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
103 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
104 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
106 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
107 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
108 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
109 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
110 GtkTextIter *start, GtkTextIter *end,
112 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
113 static void body_insert_text (GtkTextBuffer *buffer,
114 GtkTextIter *location,
117 ModestMsgEditWindow *window);
118 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
119 static void subject_field_insert_text (GtkEditable *editable,
121 gint new_text_length,
123 ModestMsgEditWindow *window);
124 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
126 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
128 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
129 ModestRecptEditor *editor);
130 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
131 ModestMsgEditWindow *window);
133 /* ModestWindow methods implementation */
134 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
135 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
136 gboolean show_toolbar);
137 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
139 ModestMsgEditWindow *window);
140 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
141 static void subject_field_move_cursor (GtkEntry *entry,
142 GtkMovementStep step,
146 static void update_window_title (ModestMsgEditWindow *window);
149 static void modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
150 ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
152 ModestMsgEditWindow *window);
153 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
155 GtkTextIter *match_start,
156 GtkTextIter *match_end);
158 static void remove_tags (WPTextBuffer *buffer);
160 static void on_account_removed (TnyAccountStore *account_store,
164 static void init_window (ModestMsgEditWindow *obj);
166 gboolean scroll_drag_timeout (gpointer userdata);
167 static void correct_scroll (ModestMsgEditWindow *w);
168 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
169 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
170 ModestMsgEditWindow *userdata);
171 static void text_buffer_mark_set (GtkTextBuffer *buffer,
174 ModestMsgEditWindow *userdata);
175 static void on_message_settings (GtkAction *action,
176 ModestMsgEditWindow *window);
177 static void setup_menu (ModestMsgEditWindow *self);
179 static void from_field_changed (GtkWidget *button,
180 ModestMsgEditWindow *self);
181 static void font_size_clicked (GtkToolButton *button,
182 ModestMsgEditWindow *window);
183 static void font_face_clicked (GtkToolButton *button,
184 ModestMsgEditWindow *window);
185 static void update_signature (ModestMsgEditWindow *self,
186 const gchar *old_account,
187 const gchar *new_account);
188 static void update_branding (ModestMsgEditWindow *self,
189 const gchar *new_account);
190 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
191 const gchar *label, GtkWidget *control);
192 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
193 static void DEBUG_BUFFER (WPTextBuffer *buffer)
197 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
199 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
200 while (!gtk_text_iter_is_end (&iter)) {
201 GString *output = g_string_new ("");
202 GSList *toggled_tags;
205 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
206 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
207 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
208 GtkTextTag *tag = (GtkTextTag *) node->data;
210 g_object_get (G_OBJECT (tag), "name", &name, NULL);
211 output = g_string_append (output, name);
212 g_string_append (output, " ");
214 output = g_string_append (output, "] OPENED [ ");
215 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
216 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
217 GtkTextTag *tag = (GtkTextTag *) node->data;
219 g_object_get (G_OBJECT (tag), "name", &name, NULL);
220 output = g_string_append (output, name);
221 g_string_append (output, " ");
223 output = g_string_append (output, "]\n");
224 g_debug ("%s", output->str);
225 g_string_free (output, TRUE);
226 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
228 g_debug ("END BUFFER");
232 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
233 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
237 /* static gboolean */
238 /* on_key_pressed (GtkWidget *self, */
239 /* GdkEventKey *event, */
240 /* gpointer user_data); */
242 /* list my signals */
249 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
250 struct _ModestMsgEditWindowPrivate {
252 GtkWidget *header_box;
254 ModestPairList *from_field_protos;
255 GtkWidget *from_field;
256 gchar *last_from_account;
257 gchar *original_account_name;
262 gchar *original_mailbox;
266 GtkWidget *bcc_field;
267 GtkWidget *subject_field;
268 GtkWidget *attachments_view;
269 GtkWidget *priority_icon;
270 GtkWidget *subject_box;
271 GtkWidget *send_button;
273 GtkWidget *cc_caption;
274 GtkWidget *bcc_caption;
275 gboolean update_caption_visibility;
276 GtkWidget *attachments_caption;
278 GtkTextBuffer *text_buffer;
280 GtkWidget *font_size_toolitem;
281 GtkWidget *font_face_toolitem;
282 GtkWidget *font_color_button;
283 GtkWidget *font_color_toolitem;
284 GSList *font_items_group;
285 GtkTreeModel *faces_model;
286 gint current_face_index;
287 GtkWidget *font_tool_button_label;
288 GtkTreeModel *sizes_model;
289 gint current_size_index;
290 GtkWidget *size_tool_button_label;
292 GtkWidget *isearch_toolbar;
295 GtkWidget *font_dialog;
297 GtkWidget *scrollable;
298 guint correct_scroll_idle;
299 guint scroll_drag_timeout_id;
303 TnyList *attachments;
308 TnyHeaderFlags priority_flags;
310 gboolean can_undo, can_redo;
311 gulong clipboard_change_handler_id;
312 gulong default_clipboard_change_handler_id;
313 gulong account_removed_handler_id;
314 guint clipboard_owner_idle;
315 gchar *clipboard_text;
324 GtkWidget *cc_button;
325 GtkWidget *bcc_button;
327 GtkWidget *max_chars_banner;
329 GtkWidget *brand_icon;
330 GtkWidget *brand_label;
331 GtkWidget *brand_container;
334 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
335 MODEST_TYPE_MSG_EDIT_WINDOW, \
336 ModestMsgEditWindowPrivate))
338 static GtkWindowClass *parent_class = NULL;
340 /* uncomment the following if you have defined any signals */
341 /* static guint signals[LAST_SIGNAL] = {0}; */
344 modest_msg_edit_window_get_type (void)
346 static GType my_type = 0;
348 static const GTypeInfo my_info = {
349 sizeof(ModestMsgEditWindowClass),
350 NULL, /* base init */
351 NULL, /* base finalize */
352 (GClassInitFunc) modest_msg_edit_window_class_init,
353 NULL, /* class finalize */
354 NULL, /* class data */
355 sizeof(ModestMsgEditWindow),
357 (GInstanceInitFunc) modest_msg_edit_window_init,
360 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
361 "ModestMsgEditWindow",
369 save_state (ModestWindow *self)
371 modest_widget_memory_save (modest_runtime_get_conf(),
372 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
377 restore_settings (ModestMsgEditWindow *self)
379 ModestConf *conf = NULL;
381 conf = modest_runtime_get_conf ();
383 /* Dim at start clipboard actions */
384 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
389 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
391 GObjectClass *gobject_class;
392 ModestWindowClass *modest_window_class;
393 gobject_class = (GObjectClass*) klass;
394 modest_window_class = (ModestWindowClass*) klass;
396 parent_class = g_type_class_peek_parent (klass);
397 gobject_class->finalize = modest_msg_edit_window_finalize;
399 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
400 modest_window_class->save_state_func = save_state;
401 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
403 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
407 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
409 ModestMsgEditWindowPrivate *priv;
410 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
412 priv->msg_body = NULL;
413 priv->from_field = NULL;
414 priv->to_field = NULL;
415 priv->cc_field = NULL;
416 priv->bcc_field = NULL;
417 priv->subject_field = NULL;
418 priv->attachments = TNY_LIST (tny_simple_list_new ());
419 priv->images = TNY_LIST (tny_simple_list_new ());
420 priv->images_size = 0;
421 priv->images_count = 0;
424 priv->cc_caption = NULL;
425 priv->bcc_caption = NULL;
426 priv->update_caption_visibility = FALSE;
428 priv->priority_flags = 0;
430 priv->isearch_toolbar = NULL;
431 priv->last_search = NULL;
433 priv->draft_msg = NULL;
434 priv->outbox_msg = NULL;
435 priv->msg_uid = NULL;
437 priv->can_undo = FALSE;
438 priv->can_redo = FALSE;
439 priv->clipboard_change_handler_id = 0;
440 priv->default_clipboard_change_handler_id = 0;
441 priv->account_removed_handler_id = 0;
442 priv->clipboard_owner_idle = 0;
443 priv->clipboard_text = NULL;
446 priv->scroll_drag_timeout_id = 0;
447 priv->correct_scroll_idle = 0;
448 priv->last_upper = 0.0;
450 priv->font_dialog = NULL;
451 priv->app_menu = NULL;
453 priv->references = NULL;
454 priv->in_reply_to = NULL;
455 priv->max_chars_banner = NULL;
457 if (!is_wp_text_buffer_started) {
458 is_wp_text_buffer_started = TRUE;
459 wp_text_buffer_library_init ();
464 hildon_program_add_window (hildon_program_get_instance(),
469 multimailbox_get_default_mailbox (const gchar *account_name)
471 gchar *transport_account;
472 gchar *result = NULL;
474 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
476 TNY_ACCOUNT_TYPE_TRANSPORT);
477 if (transport_account) {
479 ModestProtocolRegistry *registry;
481 registry = modest_runtime_get_protocol_registry ();
483 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
484 MODEST_ACCOUNT_PROTO, TRUE);
486 ModestProtocol *protocol =
487 modest_protocol_registry_get_protocol_by_name (registry,
488 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
490 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
491 ModestPairList *pair_list;
493 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
496 ModestPair *pair = (ModestPair *) pair_list->data;
497 result = g_strdup ((const gchar *) pair->first);
498 modest_pair_list_free (pair_list);
509 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
511 static ModestPairList*
512 get_transports (void)
514 GSList *transports = NULL;
516 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
517 GSList *accounts = modest_account_mgr_account_names (account_mgr,
518 TRUE /* only enabled accounts. */);
520 GSList *cursor = accounts;
522 gchar *account_name = cursor->data;
525 gchar *transport_account;
526 gboolean multi_mailbox = FALSE;
527 ModestProtocol *protocol = NULL;
529 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
531 transport_account = modest_account_mgr_get_server_account_name
532 (modest_runtime_get_account_mgr (),
534 TNY_ACCOUNT_TYPE_TRANSPORT);
535 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
536 ModestPairList *pair_list;
537 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
540 transports = g_slist_concat (transports, pair_list);
541 multi_mailbox = TRUE;
546 if (!multi_mailbox) {
547 gchar *from_string = NULL;
549 from_string = modest_account_mgr_get_from_string (account_mgr,
551 if (from_string && account_name) {
552 gchar *name = account_name;
553 ModestPair *pair = modest_pair_new ((gpointer) name,
554 (gpointer) from_string , TRUE);
555 transports = g_slist_prepend (transports, pair);
560 cursor = cursor->next;
562 g_slist_free (accounts); /* only free the accounts, not the elements,
563 * because they are used in the pairlist */
567 static void window_focus (GtkWindow *window,
571 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
575 scroll_drag_timeout (gpointer userdata)
577 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
578 ModestMsgEditWindowPrivate *priv;
580 /* It could happen that the window was already closed */
581 if (!GTK_WIDGET_VISIBLE (win))
584 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
586 correct_scroll_without_drag_check (win, TRUE);
588 priv->scroll_drag_timeout_id = 0;
594 correct_scroll_without_drag_check_idle (gpointer userdata)
596 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
597 ModestMsgEditWindowPrivate *priv;
599 GdkRectangle rectangle;
600 gint offset_min, offset_max;
604 /* It could happen that the window was already closed */
605 if (!GTK_WIDGET_VISIBLE (w))
608 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
610 insert = gtk_text_buffer_get_insert (priv->text_buffer);
611 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
613 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
614 offset_min = priv->msg_body->allocation.y + rectangle.y;
615 offset_max = offset_min + rectangle.height;
617 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
618 offset_min = MAX (offset_min - 48, 0);
619 offset_max = MIN (offset_max + 48, vadj->upper);
621 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
623 priv->correct_scroll_idle = 0;
628 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
630 ModestMsgEditWindowPrivate *priv;
632 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
634 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
637 if (priv->correct_scroll_idle > 0) {
641 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
642 (GSourceFunc) correct_scroll_without_drag_check_idle,
648 correct_scroll (ModestMsgEditWindow *w)
650 ModestMsgEditWindowPrivate *priv;
652 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
653 if (gtk_grab_get_current () == priv->msg_body) {
654 if (priv->scroll_drag_timeout_id == 0) {
655 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
657 (GSourceFunc) scroll_drag_timeout,
664 correct_scroll_without_drag_check (w, TRUE);
668 text_buffer_end_user_action (GtkTextBuffer *buffer,
669 ModestMsgEditWindow *userdata)
672 correct_scroll (userdata);
676 text_buffer_mark_set (GtkTextBuffer *buffer,
679 ModestMsgEditWindow *userdata)
681 gtk_text_buffer_begin_user_action (buffer);
682 gtk_text_buffer_end_user_action (buffer);
686 cut_clipboard_check (GtkTextView *text_view,
689 GtkTextBuffer *buffer;
691 buffer = gtk_text_view_get_buffer (text_view);
692 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
693 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
698 copy_clipboard_check (GtkTextView *text_view,
701 GtkTextBuffer *buffer;
703 buffer = gtk_text_view_get_buffer (text_view);
704 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
705 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
710 attachment_deleted (ModestAttachmentsView *attachments_view,
713 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
718 body_size_request (GtkWidget *body,
722 /* Make sure the body always get at least 70 pixels */
723 if (req->height < 70)
728 connect_signals (ModestMsgEditWindow *obj)
730 ModestMsgEditWindowPrivate *priv;
732 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
734 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
735 G_CALLBACK (text_buffer_refresh_attributes), obj);
736 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
737 G_CALLBACK (text_buffer_can_undo), obj);
738 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
739 G_CALLBACK (text_buffer_can_redo), obj);
740 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
741 G_CALLBACK (body_changed), obj);
742 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
743 G_CALLBACK (body_insert_text), obj);
744 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
745 G_CALLBACK (body_changed), obj);
746 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
747 G_CALLBACK (text_buffer_end_user_action), obj);
748 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
749 G_CALLBACK (text_buffer_mark_set), obj);
750 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
751 G_CALLBACK (text_buffer_apply_tag), obj);
752 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
753 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
754 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
755 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
756 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
757 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
759 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
760 G_CALLBACK (modest_ui_actions_on_send), obj);
762 if (GTK_IS_COMBO_BOX (priv->from_field)) {
763 g_signal_connect (G_OBJECT (priv->from_field), "changed",
764 G_CALLBACK (from_field_changed), obj);
766 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
767 G_CALLBACK (from_field_changed), obj);
770 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
771 G_CALLBACK (msg_body_focus), obj);
772 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
773 G_CALLBACK (msg_body_focus), obj);
774 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
775 G_CALLBACK (body_size_request), obj);
776 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
777 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
778 "changed", G_CALLBACK (recpt_field_changed), obj);
779 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
780 "changed", G_CALLBACK (recpt_field_changed), obj);
781 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
782 "changed", G_CALLBACK (recpt_field_changed), obj);
783 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
784 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
785 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
787 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
788 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
789 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
790 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_close), obj);
792 priv->clipboard_change_handler_id =
793 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
794 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
795 priv->default_clipboard_change_handler_id =
796 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
797 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
799 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
800 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
801 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
805 init_wp_text_view_style ()
807 static gboolean initialized = FALSE;
810 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
816 init_window (ModestMsgEditWindow *obj)
818 GtkWidget *to_caption, *subject_caption;
819 GtkWidget *main_vbox;
820 ModestMsgEditWindowPrivate *priv;
821 GtkActionGroup *action_group;
822 ModestWindowPrivate *parent_priv;
823 GdkPixbuf *window_icon = NULL;
824 GError *error = NULL;
826 GtkSizeGroup *title_size_group;
827 GtkSizeGroup *value_size_group;
828 GtkWidget *window_box;
829 GtkWidget *window_align;
830 #if (GTK_MINOR_VERSION >= 10)
831 GdkAtom deserialize_type;
833 GtkWidget *from_send_hbox;
834 GtkWidget *send_icon;
835 GtkWidget *attachments_label;
836 GtkWidget *branding_box;
837 GtkWidget *from_caption;
839 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
840 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
842 parent_priv->ui_manager = gtk_ui_manager_new();
843 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
844 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
846 /* Add common actions */
847 gtk_action_group_add_actions (action_group,
848 modest_msg_edit_action_entries,
849 G_N_ELEMENTS (modest_msg_edit_action_entries),
851 gtk_action_group_add_actions (action_group,
852 hildon2_msg_edit_action_entries,
853 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
855 gtk_action_group_add_toggle_actions (action_group,
856 modest_msg_edit_toggle_action_entries,
857 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
859 gtk_action_group_add_radio_actions (action_group,
860 modest_msg_edit_alignment_radio_action_entries,
861 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
863 G_CALLBACK (modest_ui_actions_on_change_justify),
865 gtk_action_group_add_radio_actions (action_group,
866 modest_msg_edit_priority_action_entries,
867 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
869 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
871 gtk_action_group_add_radio_actions (action_group,
872 modest_msg_edit_file_format_action_entries,
873 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
874 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
875 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
877 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
878 g_object_unref (action_group);
880 /* Load the UI definition */
881 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
884 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
885 g_clear_error (&error);
888 /* Add accelerators */
889 gtk_window_add_accel_group (GTK_WINDOW (obj),
890 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
892 parent_priv->menubar = NULL;
894 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
895 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
897 /* Note: This ModestPairList* must exist for as long as the picker
898 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
899 * so it can't know how to manage its memory. */
900 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
902 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
903 if (GTK_IS_COMBO_BOX (priv->from_field)) {
904 from_caption = modest_maemo_utils_create_captioned (title_size_group, NULL,
905 _("mail_va_from"), FALSE,
907 gtk_widget_show (from_caption);
909 modest_maemo_utils_set_hbutton_layout (title_size_group, NULL,
910 _("mail_va_from"), priv->from_field);
911 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
912 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
913 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
914 from_caption = priv->from_field;
917 priv->to_field = modest_recpt_editor_new ();
918 priv->cc_field = modest_recpt_editor_new ();
919 priv->bcc_field = modest_recpt_editor_new ();
920 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
921 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
922 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
923 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
924 priv->priority_icon = gtk_image_new ();
925 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
926 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
927 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
928 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
929 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
930 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
931 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
932 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
933 priv->attachments_view = modest_attachments_view_new (NULL);
934 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
935 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
937 priv->header_box = gtk_vbox_new (FALSE, 0);
939 to_caption = _create_addressbook_box
940 (title_size_group, value_size_group,
941 _("mail_va_to"), priv->to_field);
942 priv->cc_caption = _create_addressbook_box
943 (title_size_group, value_size_group,
944 _("mail_va_cc"), priv->cc_field);
945 priv->bcc_caption = _create_addressbook_box
946 (title_size_group, value_size_group,
947 _("mail_va_hotfix1"), priv->bcc_field);
948 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
949 _("mail_va_subject"), FALSE, priv->subject_box);
950 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (NULL, NULL,
951 _("mail_va_attachment"),
953 priv->attachments_view,
954 HILDON_SIZE_AUTO_WIDTH |
955 HILDON_SIZE_AUTO_HEIGHT);
956 attachments_label = modest_maemo_utils_captioned_get_label_widget (priv->attachments_caption);
957 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
960 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
961 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
962 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
963 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
965 g_object_unref (title_size_group);
966 g_object_unref (value_size_group);
968 priv->brand_icon = gtk_image_new ();
969 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
970 priv->brand_label = gtk_label_new (NULL);
971 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
972 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
973 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
974 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
976 from_send_hbox = gtk_hbox_new (FALSE, 0);
977 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
978 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
980 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
981 gtk_widget_show (branding_box);
982 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
983 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
985 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
986 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
987 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
988 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
991 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
992 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
993 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
994 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
995 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
996 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
997 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
998 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1000 init_wp_text_view_style ();
1002 priv->msg_body = modest_wp_text_view_new ();
1005 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1006 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1007 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1008 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1009 #if (GTK_MINOR_VERSION >= 10)
1010 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1011 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1013 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1014 deserialize_type, TRUE);
1016 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1018 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1020 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1022 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1024 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1026 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1028 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1029 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1030 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1032 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1033 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1034 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1036 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1037 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1039 window_box = gtk_vbox_new (FALSE, 0);
1040 gtk_container_add (GTK_CONTAINER(obj), window_box);
1042 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1044 /* Set window icon */
1045 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1047 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1048 g_object_unref (window_icon);
1053 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1055 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1057 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1058 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1059 priv->clipboard_change_handler_id))
1060 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1061 priv->clipboard_change_handler_id);
1062 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1063 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1064 priv->default_clipboard_change_handler_id))
1065 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1066 priv->default_clipboard_change_handler_id);
1068 if (priv->account_removed_handler_id &&
1069 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1070 priv->account_removed_handler_id))
1071 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1072 priv->account_removed_handler_id);
1076 modest_msg_edit_window_finalize (GObject *obj)
1078 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1080 if (priv->max_chars_banner) {
1081 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1082 priv->max_chars_banner = FALSE;
1085 /* Sanity check: shouldn't be needed, the window mgr should
1086 call this function before */
1087 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1089 if (priv->font_dialog != NULL) {
1090 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1093 if (priv->clipboard_text != NULL) {
1094 g_free (priv->clipboard_text);
1095 priv->clipboard_text = NULL;
1098 if (priv->draft_msg != NULL) {
1099 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1100 if (TNY_IS_HEADER (header)) {
1101 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1102 modest_window_mgr_unregister_header (mgr, header);
1104 g_object_unref (priv->draft_msg);
1105 priv->draft_msg = NULL;
1107 if (priv->outbox_msg != NULL) {
1108 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1109 if (TNY_IS_HEADER (header)) {
1110 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1111 modest_window_mgr_unregister_header (mgr, header);
1113 g_object_unref (priv->outbox_msg);
1114 priv->outbox_msg = NULL;
1116 if (priv->correct_scroll_idle > 0) {
1117 g_source_remove (priv->correct_scroll_idle);
1118 priv->correct_scroll_idle = 0;
1120 if (priv->scroll_drag_timeout_id > 0) {
1121 g_source_remove (priv->scroll_drag_timeout_id);
1122 priv->scroll_drag_timeout_id = 0;
1124 if (priv->clipboard_owner_idle > 0) {
1125 g_source_remove (priv->clipboard_owner_idle);
1126 priv->clipboard_owner_idle = 0;
1128 if (priv->original_account_name)
1129 g_free (priv->original_account_name);
1130 if (priv->original_mailbox)
1131 g_free (priv->original_mailbox);
1132 g_free (priv->msg_uid);
1133 g_free (priv->last_search);
1134 g_free (priv->references);
1135 g_free (priv->in_reply_to);
1136 g_object_unref (priv->attachments);
1137 g_object_unref (priv->images);
1139 /* This had to stay alive for as long as the picker that used it: */
1140 modest_pair_list_free (priv->from_field_protos);
1142 G_OBJECT_CLASS(parent_class)->finalize (obj);
1146 pixbuf_size_prepared (GdkPixbufLoader *loader,
1149 ModestMsgEditWindow *self)
1151 gint new_height, new_width;
1154 new_height = height;
1158 if (width > IMAGE_MAX_WIDTH) {
1159 new_height = height * IMAGE_MAX_WIDTH / width;
1160 new_width = IMAGE_MAX_WIDTH;
1163 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1167 pixbuf_from_stream (TnyStream *stream,
1168 const gchar *mime_type,
1169 guint64 *stream_size,
1170 ModestMsgEditWindow *self)
1172 GdkPixbufLoader *loader;
1175 GError *error = NULL;
1179 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1181 if (loader == NULL) {
1186 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1188 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1190 tny_stream_reset (TNY_STREAM (stream));
1191 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1192 unsigned char read_buffer[128];
1194 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1196 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1199 /* Allow some UI responsiveness */
1200 while (gtk_events_pending ())
1201 gtk_main_iteration ();
1203 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1205 gdk_pixbuf_loader_close (loader, &error);
1208 g_error_free (error);
1209 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1211 g_object_ref (pixbuf);
1212 g_object_unref (loader);
1217 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1218 GdkPixbuf *new_pixbuf;
1220 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1221 gdk_pixbuf_get_width (pixbuf);
1222 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1223 g_object_unref (pixbuf);
1224 pixbuf = new_pixbuf;
1228 *stream_size = size;
1234 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1236 ModestMsgEditWindowPrivate *priv;
1239 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1241 g_object_ref (self);
1242 for (iter = tny_list_create_iterator (attachments);
1243 !tny_iterator_is_done (iter);
1244 tny_iterator_next (iter)) {
1245 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1246 const gchar *cid = tny_mime_part_get_content_id (part);
1247 const gchar *mime_type = tny_mime_part_get_content_type (part);
1248 if ((cid != NULL)&&(mime_type != NULL)) {
1249 guint64 stream_size;
1250 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1251 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1254 g_object_unref (stream);
1256 if (pixbuf != NULL) {
1257 priv->images_count ++;
1258 priv->images_size += stream_size;
1259 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1260 g_object_unref (pixbuf);
1263 g_object_unref (part);
1265 g_object_unref (iter);
1266 g_object_unref (self);
1270 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1272 TnyMimePart *parent = NULL;
1273 const gchar *content_type = NULL;
1274 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1276 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1278 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1279 parent = g_object_ref (msg);
1280 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1281 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1284 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1285 iter = tny_list_create_iterator (parts);
1286 while (!tny_iterator_is_done (iter)) {
1288 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1289 content_type = tny_mime_part_get_content_type (part);
1290 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1294 g_object_unref (part);
1296 tny_iterator_next (iter);
1298 g_object_unref (iter);
1299 g_object_unref (parts);
1302 if (parent != NULL) {
1303 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1306 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1307 iter = tny_list_create_iterator (parts);
1308 while (!tny_iterator_is_done (iter)) {
1310 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1311 content_type = tny_mime_part_get_content_type (part);
1312 if (content_type && g_str_has_prefix (content_type, "image/")) {
1313 tny_list_prepend (priv->images, (GObject *) part);
1315 g_object_unref (part);
1316 tny_iterator_next (iter);
1318 g_object_unref (iter);
1319 g_object_unref (parts);
1320 g_object_unref (parent);
1325 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1328 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1330 for (iter = tny_list_create_iterator (attachments) ;
1331 !tny_iterator_is_done (iter);
1332 tny_iterator_next (iter)) {
1333 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1334 const gchar *cid = tny_mime_part_get_content_id (part);
1336 char *invalid = NULL;
1337 gint int_cid = strtol (cid, &invalid, 10);
1338 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1339 priv->next_cid = int_cid + 1;
1342 g_object_unref (part);
1344 g_object_unref (iter);
1348 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1351 gchar *to, *cc, *bcc, *subject;
1353 ModestMsgEditWindowPrivate *priv;
1354 ModestWindowPrivate *parent_priv;
1356 TnyHeaderFlags priority_flags;
1357 TnyFolder *msg_folder;
1358 gboolean is_html = FALSE;
1359 gboolean field_view_set;
1361 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1362 g_return_if_fail (TNY_IS_MSG (msg));
1364 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1365 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1367 header = tny_msg_get_header (msg);
1368 to = tny_header_dup_to (header);
1369 cc = tny_header_dup_cc (header);
1370 bcc = tny_header_dup_bcc (header);
1371 subject = tny_header_dup_subject (header);
1373 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1374 priority_flags = tny_header_get_priority (header);
1377 gchar *quoted_names = modest_text_utils_quote_names (to);
1378 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1379 g_free (quoted_names);
1382 field_view_set = TRUE;
1384 gchar *quoted_names = modest_text_utils_quote_names (cc);
1385 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1386 g_free (quoted_names);
1387 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1388 gtk_widget_show (priv->cc_caption);
1389 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1390 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1391 gtk_widget_hide (priv->cc_caption);
1392 field_view_set = FALSE;
1394 modest_togglable_set_active (priv->cc_button, field_view_set);
1396 field_view_set = TRUE;
1398 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1399 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1400 g_free (quoted_names);
1401 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1402 gtk_widget_show (priv->bcc_caption);
1403 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1404 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1405 gtk_widget_hide (priv->bcc_caption);
1406 field_view_set = FALSE;
1408 modest_togglable_set_active (priv->bcc_button, field_view_set);
1412 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1413 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1416 update_window_title (self);
1418 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1419 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1421 if ((body == NULL)||(body[0] == '\0')) {
1423 body = modest_text_utils_convert_to_html ("");
1426 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1427 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1430 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1433 /* Add attachments to the view */
1434 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1435 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1436 if (tny_list_get_length (priv->attachments) == 0) {
1437 gtk_widget_hide (priv->attachments_caption);
1439 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1440 gtk_widget_show_all (priv->attachments_caption);
1442 get_related_images (self, msg);
1443 update_next_cid (self, priv->attachments);
1444 update_next_cid (self, priv->images);
1445 replace_with_images (self, priv->images);
1447 if (preserve_is_rich && !is_html) {
1448 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1449 /* Get the default format required from configuration */
1450 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1451 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1454 /* Set the default focus depending on having already a To: field or not */
1455 if ((!to)||(*to == '\0')) {
1456 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1458 gtk_widget_grab_focus (priv->msg_body);
1461 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1463 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1464 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1466 modest_msg_edit_window_set_modified (self, FALSE);
1468 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1469 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1470 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1471 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1473 if (priv->msg_uid) {
1474 g_free (priv->msg_uid);
1475 priv->msg_uid = NULL;
1478 /* we should set a reference to the incoming message if it is a draft */
1479 msg_folder = tny_msg_get_folder (msg);
1481 if (modest_tny_folder_is_local_folder (msg_folder)) {
1482 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1483 if (type == TNY_FOLDER_TYPE_INVALID)
1484 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1486 if (type == TNY_FOLDER_TYPE_DRAFTS)
1487 priv->draft_msg = g_object_ref(msg);
1488 if (type == TNY_FOLDER_TYPE_OUTBOX)
1489 priv->outbox_msg = g_object_ref(msg);
1490 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1492 g_object_unref (msg_folder);
1501 #ifdef MODEST_USE_CALENDAR_WIDGETS
1503 color_button_clicked (GtkButton *button)
1505 /* Show ColorPicker dialog */
1506 PipCalendarColor color = pip_color_picker_select_color(PipTextColorRed, PipColorPickerText);
1508 /* Check if some color is selected rather than dialog is dismissed */
1509 if (color != PipCalendarColorInvalid) {
1510 GdkColor *gdk_color = (GdkColor *) pip_calendar_color_get_gdkcolor(color);
1512 hildon_color_button_set_color ((HildonColorButton *) button, gdk_color);
1518 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1520 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1521 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1522 GtkWidget *placeholder;
1523 GtkWidget *tool_item;
1528 GtkWidget *sizes_menu;
1529 GtkWidget *fonts_menu;
1535 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1536 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1537 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1538 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1540 /* Font color placeholder */
1541 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1542 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1545 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1546 priv->font_color_button = hildon_color_button_new ();
1547 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1548 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1549 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1550 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1551 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1552 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1553 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1554 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1556 G_CALLBACK (modest_msg_edit_window_color_button_change),
1559 /* Yes I know this is a horrible hack, but it works for the
1560 moment while we don't create a ModestColorButton */
1561 #ifdef MODEST_USE_CALENDAR_WIDGETS
1562 GtkButtonClass *button_class = GTK_BUTTON_CLASS (HILDON_COLOR_BUTTON_GET_CLASS (priv->font_color_button));
1563 button_class->clicked = color_button_clicked;
1566 /* Font size and face placeholder */
1567 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1568 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1570 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1571 priv->size_tool_button_label = gtk_label_new (NULL);
1572 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1573 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1574 size_text, "</span>", NULL);
1575 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1576 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1578 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1579 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1580 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1581 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1582 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1583 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1584 gtk_widget_set_sensitive (arrow, FALSE);
1585 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1586 sizes_menu = gtk_menu_new ();
1587 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1588 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1591 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1592 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1594 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1598 if (wp_font_size[size_index] == 12)
1599 priv->current_size_index = size_index;
1603 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1604 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1605 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1606 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1607 priv->font_size_toolitem = tool_item;
1610 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1611 priv->font_tool_button_label = gtk_label_new (NULL);
1612 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1613 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1614 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1616 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1617 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1618 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1619 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1620 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1621 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1622 gtk_widget_set_sensitive (arrow, FALSE);
1623 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1624 fonts_menu = gtk_menu_new ();
1625 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1626 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1629 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1631 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1632 0, wp_get_font_name (font_index),
1635 if (font_index == DEFAULT_FONT)
1636 priv->current_face_index = font_index;
1638 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1639 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1640 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1641 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1642 priv->font_face_toolitem = tool_item;
1644 /* Set expand and homogeneous for remaining items */
1645 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1646 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1647 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1648 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1649 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1650 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1652 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1653 will not show the tool items added to the placeholders) */
1654 gtk_widget_show_all (parent_priv->toolbar);
1656 /* Set the no show all *after* showing all items. We do not
1657 want the toolbar to be shown with a show all because it
1658 could go agains the gconf setting regarding showing or not
1659 the toolbar of the editor window */
1660 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1666 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1669 ModestWindowPrivate *parent_priv;
1670 ModestMsgEditWindowPrivate *priv;
1671 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1672 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1673 ModestWindowMgr *mgr = NULL;
1675 g_return_val_if_fail (msg, NULL);
1676 g_return_val_if_fail (account_name, NULL);
1678 mgr = modest_runtime_get_window_mgr ();
1680 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1682 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1683 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1685 /* Menubar. Update the state of some toggles */
1686 priv->from_field_protos = get_transports ();
1687 priv->original_mailbox = NULL;
1688 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1689 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1690 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1691 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1692 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1693 priv->original_mailbox = g_strdup (mailbox);
1694 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1695 /* We set the first mailbox as the active mailbox */
1696 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1697 if (priv->original_mailbox != NULL)
1698 modest_selector_set_active_id (priv->from_field,
1699 (gpointer) priv->original_mailbox);
1701 modest_selector_set_active_id (priv->from_field,
1702 (gpointer) account_name);
1704 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1706 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1707 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1708 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1709 #ifdef HILDON_TOOLKIT_HILDON2
1710 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1712 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1713 hildon_touch_selector_get_current_text
1714 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1717 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1718 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1721 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1723 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1725 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1726 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1728 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1730 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1731 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1732 /* Add common dimming rules */
1733 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1734 modest_msg_edit_window_toolbar_dimming_entries,
1735 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1736 MODEST_WINDOW (obj));
1737 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1738 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1739 MODEST_WINDOW (obj));
1740 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1741 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1742 MODEST_WINDOW (obj));
1743 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1744 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1745 MODEST_WINDOW (obj));
1746 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1747 G_CALLBACK (modest_ui_dimming_rules_on_send),
1748 MODEST_WINDOW (obj));
1749 /* Insert dimming rules group for this window */
1750 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1751 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1753 /* Setup app menu */
1754 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1756 /* Checks the dimming rules */
1757 g_object_unref (toolbar_rules_group);
1758 g_object_unref (clipboard_rules_group);
1759 gtk_widget_hide (priv->priority_icon);
1760 gtk_widget_queue_resize (priv->subject_box);
1761 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1763 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1765 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1766 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1767 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1768 priv->update_caption_visibility = TRUE;
1770 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1772 /* Track account-removed signal, this window should be closed
1773 in the case we're creating a mail associated to the account
1775 priv->account_removed_handler_id =
1776 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1778 G_CALLBACK(on_account_removed),
1781 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1783 return (ModestWindow*) obj;
1787 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1789 GString **string_buffer = (GString **) user_data;
1791 *string_buffer = g_string_append (*string_buffer, buffer);
1797 * @result: A new string which should be freed with g_free().
1800 get_formatted_data (ModestMsgEditWindow *edit_window)
1802 ModestMsgEditWindowPrivate *priv;
1803 GString *string_buffer = g_string_new ("");
1805 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1807 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1809 modest_text_utils_hyperlinkify (string_buffer);
1811 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1813 return g_string_free (string_buffer, FALSE);
1818 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1821 const gchar *account_name;
1822 ModestMsgEditWindowPrivate *priv;
1823 TnyIterator *att_iter;
1824 const gchar *picker_active_id;
1826 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1828 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1830 picker_active_id = modest_selector_get_active_id (priv->from_field);
1831 g_return_val_if_fail (picker_active_id, NULL);
1832 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1834 /* don't free these (except from) */
1835 data = g_slice_new0 (MsgData);
1836 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1837 data->account_name = g_strdup (account_name);
1838 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1839 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1840 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1841 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1842 data->references = g_strdup (priv->references);
1843 data->in_reply_to = g_strdup (priv->in_reply_to);
1844 if (priv->draft_msg) {
1845 data->draft_msg = g_object_ref (priv->draft_msg);
1846 } else if (priv->outbox_msg) {
1847 data->draft_msg = g_object_ref (priv->outbox_msg);
1849 data->draft_msg = NULL;
1852 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1854 gtk_text_buffer_get_bounds (buf, &b, &e);
1855 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1857 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1858 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1860 data->html_body = NULL;
1862 /* deep-copy the data */
1863 att_iter = tny_list_create_iterator (priv->attachments);
1864 data->attachments = NULL;
1865 while (!tny_iterator_is_done (att_iter)) {
1866 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1867 if (!(TNY_IS_MIME_PART(part))) {
1868 g_warning ("strange data in attachment list");
1869 g_object_unref (part);
1870 tny_iterator_next (att_iter);
1873 data->attachments = g_list_append (data->attachments,
1875 tny_iterator_next (att_iter);
1877 g_object_unref (att_iter);
1879 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1880 att_iter = tny_list_create_iterator (priv->images);
1881 data->images = NULL;
1882 while (!tny_iterator_is_done (att_iter)) {
1883 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1885 if (!(TNY_IS_MIME_PART(part))) {
1886 g_warning ("strange data in attachment list");
1887 g_object_unref (part);
1888 tny_iterator_next (att_iter);
1891 cid = tny_mime_part_get_content_id (part);
1893 gchar *image_tag_id;
1894 GtkTextTag *image_tag;
1896 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1897 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1898 g_free (image_tag_id);
1900 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1902 ((gtk_text_iter_has_tag (&iter, image_tag))||
1903 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1904 data->images = g_list_append (data->images,
1905 g_object_ref (part));
1907 g_object_unref (part);
1908 tny_iterator_next (att_iter);
1910 g_object_unref (att_iter);
1912 data->priority_flags = priv->priority_flags;
1919 unref_gobject (GObject *obj, gpointer data)
1921 if (!G_IS_OBJECT(obj))
1923 g_object_unref (obj);
1927 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1930 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1938 g_free (data->from);
1939 g_free (data->subject);
1940 g_free (data->plain_body);
1941 g_free (data->html_body);
1942 g_free (data->account_name);
1943 g_free (data->references);
1944 g_free (data->in_reply_to);
1946 if (data->draft_msg != NULL) {
1947 g_object_unref (data->draft_msg);
1948 data->draft_msg = NULL;
1951 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1952 g_list_free (data->attachments);
1953 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1954 g_list_free (data->images);
1956 g_slice_free (MsgData, data);
1960 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1962 guint64 *parts_size)
1964 ModestMsgEditWindowPrivate *priv;
1966 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1968 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1970 /* TODO: add images */
1971 *parts_size += priv->images_size;
1972 *parts_count += priv->images_count;
1977 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1980 ModestMsgEditWindowPrivate *priv = NULL;
1981 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1983 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1985 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1987 return MODEST_MSG_EDIT_FORMAT_HTML;
1989 return MODEST_MSG_EDIT_FORMAT_TEXT;
1993 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1994 ModestMsgEditFormat format)
1996 ModestMsgEditWindowPrivate *priv;
1997 ModestWindowPrivate *parent_priv;
1999 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2000 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2001 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2004 case MODEST_MSG_EDIT_FORMAT_HTML:
2005 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2006 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
2008 case MODEST_MSG_EDIT_FORMAT_TEXT:
2009 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2010 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
2013 g_return_if_reached ();
2017 ModestMsgEditFormatState *
2018 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2020 ModestMsgEditFormatState *format_state = NULL;
2021 ModestMsgEditWindowPrivate *priv;
2022 WPTextBufferFormat *buffer_format;
2024 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2026 buffer_format = g_new0 (WPTextBufferFormat, 1);
2027 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2029 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2031 format_state = g_new0 (ModestMsgEditFormatState, 1);
2032 format_state->bold = buffer_format->bold&0x1;
2033 format_state->italics = buffer_format->italic&0x1;
2034 format_state->bullet = buffer_format->bullet&0x1;
2035 format_state->color = buffer_format->color;
2036 format_state->font_size = buffer_format->font_size;
2037 format_state->font_family = wp_get_font_name (buffer_format->font);
2038 format_state->justification = buffer_format->justification;
2039 g_free (buffer_format);
2041 return format_state;
2046 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2047 const ModestMsgEditFormatState *format_state)
2049 ModestMsgEditWindowPrivate *priv;
2050 WPTextBufferFormat *buffer_format;
2051 WPTextBufferFormat *current_format;
2053 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2054 g_return_if_fail (format_state != NULL);
2056 buffer_format = g_new0 (WPTextBufferFormat, 1);
2057 current_format = g_new0 (WPTextBufferFormat, 1);
2059 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2060 gtk_widget_grab_focus (priv->msg_body);
2061 buffer_format->bold = (format_state->bold != FALSE);
2062 buffer_format->italic = (format_state->italics != FALSE);
2063 buffer_format->color = format_state->color;
2064 buffer_format->font_size = format_state->font_size;
2065 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2066 buffer_format->justification = format_state->justification;
2067 buffer_format->bullet = format_state->bullet;
2069 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2071 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2072 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2073 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2074 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2075 buffer_format->cs.font = (buffer_format->font != current_format->font);
2076 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2077 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2079 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2080 if (buffer_format->cs.bold) {
2081 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2082 GINT_TO_POINTER (buffer_format->bold&0x1));
2084 if (buffer_format->cs.italic) {
2085 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2086 GINT_TO_POINTER (buffer_format->italic&0x1));
2088 if (buffer_format->cs.color) {
2089 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2090 GINT_TO_POINTER (&(buffer_format->color)));
2092 if (buffer_format->cs.font_size) {
2093 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2094 GINT_TO_POINTER (buffer_format->font_size));
2096 if (buffer_format->cs.justification) {
2097 switch (buffer_format->justification) {
2098 case GTK_JUSTIFY_LEFT:
2099 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2100 GINT_TO_POINTER(TRUE));
2102 case GTK_JUSTIFY_CENTER:
2103 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2104 GINT_TO_POINTER(TRUE));
2106 case GTK_JUSTIFY_RIGHT:
2107 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2108 GINT_TO_POINTER(TRUE));
2115 if (buffer_format->cs.font) {
2116 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2117 GINT_TO_POINTER (buffer_format->font));
2119 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2120 if (buffer_format->cs.bullet) {
2121 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2122 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2124 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2126 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2128 g_free (buffer_format);
2129 g_free (current_format);
2131 /* Check dimming rules */
2132 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2133 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2137 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2139 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2141 ModestWindowPrivate *parent_priv;
2142 ModestMsgEditWindowPrivate *priv;
2144 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2145 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2147 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2148 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2149 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2150 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2152 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2153 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2154 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2157 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2159 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2160 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2162 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2163 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2165 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2166 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2169 switch (buffer_format->justification)
2171 case GTK_JUSTIFY_LEFT:
2172 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2174 case GTK_JUSTIFY_CENTER:
2175 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2177 case GTK_JUSTIFY_RIGHT:
2178 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2185 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2187 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2188 G_CALLBACK (modest_msg_edit_window_color_button_change),
2190 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2191 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2192 G_CALLBACK (modest_msg_edit_window_color_button_change),
2195 if (priv->current_size_index != buffer_format->font_size) {
2199 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2200 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2204 priv->current_size_index = buffer_format->font_size;
2206 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2207 markup = g_strconcat ("<span font_family='Sans'>",
2208 size_text, "</span>", NULL);
2210 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2214 gtk_tree_path_free (path);
2217 if (priv->current_face_index != buffer_format->font) {
2221 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2222 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2226 priv->current_face_index = buffer_format->font;
2227 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2228 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2229 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2236 g_free (buffer_format);
2242 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2244 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2245 ModestMsgEditWindowPrivate *priv;
2246 GtkWidget *dialog = NULL;
2248 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2249 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2251 dialog = hildon_color_chooser_new ();
2252 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2253 g_free (buffer_format);
2255 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2257 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2258 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2261 gtk_widget_destroy (dialog);
2266 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2268 ModestMsgEditWindowPrivate *priv;
2269 GtkWidget *dialog = NULL;
2270 GdkColor *old_color = NULL;
2272 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2273 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2275 dialog = hildon_color_chooser_new ();
2276 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2278 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2280 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2281 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2283 gtk_widget_destroy (dialog);
2288 create_stream_for_uri (const gchar* uri)
2293 TnyStream *result = NULL;
2295 GnomeVFSHandle *handle = NULL;
2296 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2297 if (test == GNOME_VFS_OK) {
2298 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2299 /* Streams over OBEX (Bluetooth) are not seekable but
2300 * we expect them to be (we might need to read them
2301 * several times). So if this is a Bluetooth URI just
2302 * read the whole file into memory (this is not a fast
2303 * protocol so we can assume that these files are not
2304 * going to be very big) */
2305 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2306 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2307 TnyStream *memstream = tny_camel_mem_stream_new ();
2308 tny_stream_write_to_stream (vfssstream, memstream);
2309 g_object_unref (vfssstream);
2312 result = vfssstream;
2320 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2323 ModestMsgEditWindowPrivate *priv;
2324 GtkWidget *dialog = NULL;
2326 GSList *uris = NULL;
2327 GSList *uri_node = NULL;
2329 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2331 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2332 _("mcen_ia_select_inline_image_title"),
2333 (GtkWindow *) window,
2334 GTK_FILE_CHOOSER_ACTION_OPEN);
2335 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2337 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2339 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2340 GTK_WINDOW (dialog), GTK_WINDOW (window));
2342 response = gtk_dialog_run (GTK_DIALOG (dialog));
2344 case GTK_RESPONSE_OK:
2346 gchar *current_folder;
2347 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2348 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2349 if (current_folder && current_folder != '\0') {
2351 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2352 current_folder, &err);
2354 g_debug ("Error storing latest used folder: %s", err->message);
2358 g_free (current_folder);
2364 gtk_widget_destroy (dialog);
2366 g_object_ref (window);
2367 /* The operation could take some time so allow the dialog to be closed */
2368 while (gtk_events_pending ())
2369 gtk_main_iteration ();
2371 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2373 GnomeVFSHandle *handle = NULL;
2374 GnomeVFSResult result;
2375 GtkTextIter position;
2376 GtkTextMark *insert_mark;
2378 uri = (const gchar *) uri_node->data;
2379 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2380 if (result == GNOME_VFS_OK) {
2382 GnomeVFSFileInfo *info;
2383 gchar *filename, *basename, *escaped_filename;
2384 TnyMimePart *mime_part;
2386 const gchar *mime_type = NULL;
2387 GnomeVFSURI *vfs_uri;
2388 guint64 stream_size;
2390 gnome_vfs_close (handle);
2391 vfs_uri = gnome_vfs_uri_new (uri);
2393 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2394 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2395 g_free (escaped_filename);
2396 gnome_vfs_uri_unref (vfs_uri);
2397 info = gnome_vfs_file_info_new ();
2399 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2400 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2402 mime_type = gnome_vfs_file_info_get_mime_type (info);
2404 mime_part = tny_platform_factory_new_mime_part
2405 (modest_runtime_get_platform_factory ());
2407 TnyStream *stream = create_stream_for_uri (uri);
2409 if (stream == NULL) {
2411 modest_platform_information_banner (NULL, NULL,
2412 _FM("sfil_ib_opening_not_allowed"));
2414 g_object_unref (mime_part);
2415 gnome_vfs_file_info_unref (info);
2419 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2421 content_id = g_strdup_printf ("%d", priv->next_cid);
2422 tny_mime_part_set_content_id (mime_part, content_id);
2423 g_free (content_id);
2426 basename = g_path_get_basename (filename);
2427 tny_mime_part_set_filename (mime_part, basename);
2430 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2432 if (pixbuf != NULL) {
2433 priv->images_size += stream_size;
2434 priv->images_count ++;
2435 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2436 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2437 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2438 tny_mime_part_get_content_id (mime_part), pixbuf);
2439 g_object_unref (pixbuf);
2441 tny_list_prepend (priv->images, (GObject *) mime_part);
2442 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2444 modest_platform_information_banner (NULL, NULL,
2445 _("mail_ib_file_operation_failed"));
2449 g_object_unref (mime_part);
2450 gnome_vfs_file_info_unref (info);
2454 g_object_unref (window);
2458 on_attach_file_response (GtkDialog *dialog,
2462 GSList *uris = NULL;
2464 GnomeVFSFileSize total_size, allowed_size;
2465 ModestMsgEditWindow *window;
2466 ModestMsgEditWindowPrivate *priv;
2471 case GTK_RESPONSE_OK:
2473 gchar *current_folder;
2475 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2476 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2477 if (current_folder && current_folder != '\0') {
2479 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2480 current_folder, &err);
2482 g_debug ("Error storing latest used folder: %s", err->message);
2486 g_free (current_folder);
2493 window = MODEST_MSG_EDIT_WINDOW (user_data);
2494 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2496 /* allowed size is the maximum size - what's already there */
2497 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2498 &att_num, &att_size);
2499 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2502 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2504 const gchar *uri = (const gchar *) uri_node->data;
2507 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2509 if (total_size > allowed_size) {
2510 g_debug ("%s: total size: %u",
2511 __FUNCTION__, (unsigned int)total_size);
2514 allowed_size -= total_size;
2516 g_slist_foreach (uris, (GFunc) g_free, NULL);
2517 g_slist_free (uris);
2519 gtk_widget_destroy (GTK_WIDGET (dialog));
2523 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2525 GtkWidget *dialog = NULL;
2526 ModestMsgEditWindowPrivate *priv;
2529 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2531 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2533 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2536 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2537 _("mcen_ia_select_attachment_title"),
2538 (GtkWindow *) window,
2539 GTK_FILE_CHOOSER_ACTION_OPEN);
2540 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2541 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2542 if (conf_folder && conf_folder[0] != '\0') {
2543 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2546 /* Set the default folder to documents folder */
2547 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2550 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2551 ".documents", NULL);
2553 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2554 g_free (docs_folder);
2556 g_free (conf_folder);
2557 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2558 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2559 GTK_WINDOW (dialog), GTK_WINDOW (window));
2561 /* Connect to response & show */
2562 g_signal_connect (dialog, "response",
2563 G_CALLBACK (on_attach_file_response), window);
2564 gtk_widget_show (dialog);
2569 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2571 GnomeVFSFileSize allowed_size)
2574 GnomeVFSHandle *handle = NULL;
2575 ModestMsgEditWindowPrivate *priv;
2576 GnomeVFSResult result;
2577 GnomeVFSFileSize size = 0;
2578 g_return_val_if_fail (window, 0);
2579 g_return_val_if_fail (uri, 0);
2581 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2583 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2584 if (result == GNOME_VFS_OK) {
2585 TnyMimePart *mime_part;
2587 const gchar *mime_type = NULL;
2589 gchar *escaped_filename;
2592 GnomeVFSFileInfo *info;
2593 GnomeVFSURI *vfs_uri;
2595 gnome_vfs_close (handle);
2596 vfs_uri = gnome_vfs_uri_new (uri);
2599 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2600 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2601 g_free (escaped_filename);
2602 gnome_vfs_uri_unref (vfs_uri);
2604 info = gnome_vfs_file_info_new ();
2606 if (gnome_vfs_get_file_info (uri,
2608 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2610 mime_type = gnome_vfs_file_info_get_mime_type (info);
2611 mime_part = tny_platform_factory_new_mime_part
2612 (modest_runtime_get_platform_factory ());
2614 /* try to get the attachment's size; this may fail for weird
2615 * file systems, like obex, upnp... */
2616 if (allowed_size != 0 &&
2617 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2619 if (size > allowed_size) {
2620 modest_platform_information_banner (NULL, NULL,
2621 _("mail_ib_error_attachment_size"));
2626 g_debug ("%s: could not get attachment size", __FUNCTION__);
2628 stream = create_stream_for_uri (uri);
2630 if (stream == NULL) {
2632 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2634 g_object_unref (mime_part);
2636 gnome_vfs_file_info_unref (info);
2640 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2641 g_object_unref (stream);
2643 content_id = g_strdup_printf ("%d", priv->next_cid);
2644 tny_mime_part_set_content_id (mime_part, content_id);
2645 g_free (content_id);
2648 basename = g_path_get_basename (filename);
2649 tny_mime_part_set_filename (mime_part, basename);
2652 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2653 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2655 info->size == 0, info->size);
2656 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2657 gtk_widget_show_all (priv->attachments_caption);
2658 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2660 g_object_unref (mime_part);
2661 gnome_vfs_file_info_unref (info);
2668 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2671 ModestMsgEditWindowPrivate *priv;
2674 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2675 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2677 if (att_list == NULL) {
2678 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2679 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2680 g_object_unref (att_list);
2684 g_object_ref (att_list);
2687 if (tny_list_get_length (att_list) == 0) {
2688 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2690 gboolean dialog_response;
2691 gchar *message = NULL;
2692 gchar *filename = NULL;
2694 if (tny_list_get_length (att_list) == 1) {
2696 iter = tny_list_create_iterator (att_list);
2697 part = (TnyMimePart *) tny_iterator_get_current (iter);
2698 g_object_unref (iter);
2699 if (TNY_IS_MSG (part)) {
2700 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2702 filename = tny_header_dup_subject (header);
2703 g_object_unref (header);
2705 if (filename == NULL) {
2706 filename = g_strdup (_("mail_va_no_subject"));
2709 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2711 g_object_unref (part);
2713 filename = g_strdup ("");
2715 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2716 "emev_nc_delete_attachments",
2717 tny_list_get_length (att_list)), filename);
2720 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2724 if (dialog_response != GTK_RESPONSE_OK) {
2725 g_object_unref (att_list);
2729 for (iter = tny_list_create_iterator (att_list);
2730 !tny_iterator_is_done (iter);
2731 tny_iterator_next (iter)) {
2732 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2733 const gchar *att_id;
2734 tny_list_remove (priv->attachments, (GObject *) mime_part);
2736 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2738 if (tny_list_get_length (priv->attachments) == 0)
2739 gtk_widget_hide (priv->attachments_caption);
2740 att_id = tny_mime_part_get_content_id (mime_part);
2742 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2744 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2745 g_object_unref (mime_part);
2747 g_object_unref (iter);
2750 g_object_unref (att_list);
2752 /* if the last attachment has been removed, focus the Subject: field */
2753 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2754 gtk_widget_grab_focus (priv->subject_field);
2758 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2761 ModestMsgEditWindowPrivate *priv;
2764 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2766 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2768 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2770 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2774 font_size_clicked (GtkToolButton *button,
2775 ModestMsgEditWindow *window)
2777 ModestMsgEditWindowPrivate *priv;
2778 GtkWidget *selector, *dialog;
2780 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2782 selector = hildon_touch_selector_new ();
2783 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2784 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2786 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2787 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2788 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2790 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2794 WPTextBufferFormat format;
2796 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2798 memset (&format, 0, sizeof (format));
2799 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2801 format.cs.font_size = TRUE;
2802 format.cs.text_position = TRUE;
2803 format.cs.font = TRUE;
2804 format.font_size = new_index;
2805 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2807 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2808 GINT_TO_POINTER (new_index)))
2809 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2811 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2812 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2813 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2814 size_text, "</span>", NULL);
2816 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2820 gtk_widget_destroy (dialog);
2822 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2827 font_face_clicked (GtkToolButton *button,
2828 ModestMsgEditWindow *window)
2830 ModestMsgEditWindowPrivate *priv;
2831 GtkWidget *selector, *dialog;
2832 GtkCellRenderer *renderer;
2834 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2836 selector = hildon_touch_selector_new ();
2837 renderer = gtk_cell_renderer_text_new ();
2838 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2839 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2840 renderer, "family", 0, "text", 0, NULL);
2841 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2843 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2844 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2845 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2847 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2848 gint new_font_index;
2852 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2853 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2854 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2858 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2860 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2861 GINT_TO_POINTER(new_font_index)))
2862 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2864 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2865 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2867 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2871 gtk_tree_path_free (path);
2874 gtk_widget_destroy (dialog);
2876 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2881 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2884 ModestMsgEditWindowPrivate *priv = NULL;
2885 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2887 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2888 if (!priv->update_caption_visibility)
2891 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2893 gtk_widget_show (priv->cc_caption);
2895 gtk_widget_hide (priv->cc_caption);
2897 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2901 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2904 ModestMsgEditWindowPrivate *priv = NULL;
2905 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2907 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2908 if (!priv->update_caption_visibility)
2911 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2913 gtk_widget_show (priv->bcc_caption);
2915 gtk_widget_hide (priv->bcc_caption);
2917 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2921 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2922 ModestRecptEditor *editor)
2924 ModestMsgEditWindowPrivate *priv;
2926 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2927 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2929 /* we check for low-mem; in that case, show a warning, and don't allow
2930 * for the addressbook
2932 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2935 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2937 if (editor == NULL) {
2938 GtkWidget *view_focus, *parent;
2939 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2941 /* This code should be kept in sync with ModestRecptEditor. The
2942 textview inside the recpt editor is the one that really gets the
2943 focus. As it's inside a scrolled window, and this one inside the
2944 hbox recpt editor inherits from, we'll need to go up in the
2945 hierarchy to know if the text view is part of the recpt editor
2946 or if it's a different text entry */
2947 parent = gtk_widget_get_parent (view_focus);
2948 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2949 editor = MODEST_RECPT_EDITOR (parent);
2952 editor = MODEST_RECPT_EDITOR (priv->to_field);
2955 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2959 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2961 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2963 modest_msg_edit_window_open_addressbook (window, NULL);
2967 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2968 gboolean show_toolbar)
2970 ModestWindowPrivate *parent_priv;
2971 ModestMsgEditWindowPrivate *priv;
2973 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2974 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2975 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2977 /* We can not just use the code of
2978 modest_msg_edit_window_setup_toolbar because it has a
2979 mixture of both initialization and creation code. */
2981 gint current_format;
2982 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2983 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2984 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2985 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2987 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2990 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2995 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2996 TnyHeaderFlags priority_flags)
2998 ModestMsgEditWindowPrivate *priv;
2999 ModestWindowPrivate *parent_priv;
3001 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3003 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3004 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3006 if (priv->priority_flags != priority_flags) {
3007 GtkAction *priority_action = NULL;
3009 priv->priority_flags = priority_flags;
3011 switch (priority_flags) {
3012 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3013 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3014 MODEST_HEADER_ICON_HIGH,
3015 HILDON_ICON_SIZE_SMALL);
3016 gtk_widget_show (priv->priority_icon);
3017 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3018 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3020 case TNY_HEADER_FLAG_LOW_PRIORITY:
3021 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3022 MODEST_HEADER_ICON_LOW,
3023 HILDON_ICON_SIZE_SMALL);
3024 gtk_widget_show (priv->priority_icon);
3025 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3026 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3029 gtk_widget_hide (priv->priority_icon);
3030 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3031 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3034 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3035 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3037 gtk_widget_queue_resize (priv->subject_box);
3041 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3044 ModestMsgEditWindowPrivate *priv;
3045 ModestWindowPrivate *parent_priv;
3046 gint current_format;
3048 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3050 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3051 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3053 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3054 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3056 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3058 if (current_format != file_format) {
3059 switch (file_format) {
3060 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3061 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3062 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3063 if (parent_priv->toolbar)
3064 gtk_widget_show (parent_priv->toolbar);
3066 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3070 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3071 response = gtk_dialog_run (GTK_DIALOG (dialog));
3072 gtk_widget_destroy (dialog);
3073 if (response == GTK_RESPONSE_OK) {
3074 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3075 if (parent_priv->toolbar)
3076 gtk_widget_hide (parent_priv->toolbar);
3078 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3079 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3084 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3085 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3086 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3091 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3094 ModestMsgEditWindowPrivate *priv;
3095 WPTextBufferFormat oldfmt, fmt;
3096 gint old_position = 0;
3100 GdkColor *color = NULL;
3101 gboolean bold, bold_set, italic, italic_set;
3102 gboolean underline, underline_set;
3103 gboolean strikethrough, strikethrough_set;
3104 gboolean position_set;
3105 gboolean font_size_set, font_set, color_set;
3108 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3109 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3111 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3112 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3113 GTK_WINDOW(dialog), GTK_WINDOW (window));
3115 /* First we get the currently selected font information */
3116 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3118 switch (oldfmt.text_position) {
3119 case TEXT_POSITION_NORMAL:
3122 case TEXT_POSITION_SUPERSCRIPT:
3130 g_object_set (G_OBJECT (dialog),
3131 "bold", oldfmt.bold != FALSE,
3132 "bold-set", !oldfmt.cs.bold,
3133 "underline", oldfmt.underline != FALSE,
3134 "underline-set", !oldfmt.cs.underline,
3135 "italic", oldfmt.italic != FALSE,
3136 "italic-set", !oldfmt.cs.italic,
3137 "strikethrough", oldfmt.strikethrough != FALSE,
3138 "strikethrough-set", !oldfmt.cs.strikethrough,
3139 "color", &oldfmt.color,
3140 "color-set", !oldfmt.cs.color,
3141 "size", wp_font_size[oldfmt.font_size],
3142 "size-set", !oldfmt.cs.font_size,
3143 "position", old_position,
3144 "position-set", !oldfmt.cs.text_position,
3145 "family", wp_get_font_name (oldfmt.font),
3146 "family-set", !oldfmt.cs.font,
3149 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3150 GTK_WINDOW (dialog), GTK_WINDOW (window));
3151 gtk_widget_show_all (dialog);
3152 priv->font_dialog = dialog;
3153 response = gtk_dialog_run (GTK_DIALOG (dialog));
3154 priv->font_dialog = NULL;
3155 if (response == GTK_RESPONSE_OK) {
3157 g_object_get( dialog,
3159 "bold-set", &bold_set,
3160 "underline", &underline,
3161 "underline-set", &underline_set,
3163 "italic-set", &italic_set,
3164 "strikethrough", &strikethrough,
3165 "strikethrough-set", &strikethrough_set,
3167 "color-set", &color_set,
3169 "size-set", &font_size_set,
3170 "family", &font_name,
3171 "family-set", &font_set,
3172 "position", &position,
3173 "position-set", &position_set,
3178 if (response == GTK_RESPONSE_OK) {
3179 memset(&fmt, 0, sizeof(fmt));
3185 fmt.italic = italic;
3186 fmt.cs.italic = TRUE;
3188 if (underline_set) {
3189 fmt.underline = underline;
3190 fmt.cs.underline = TRUE;
3192 if (strikethrough_set) {
3193 fmt.strikethrough = strikethrough;
3194 fmt.cs.strikethrough = TRUE;
3199 ? TEXT_POSITION_NORMAL
3200 : ( ( position == 1 )
3201 ? TEXT_POSITION_SUPERSCRIPT
3202 : TEXT_POSITION_SUBSCRIPT );
3203 fmt.cs.text_position = TRUE;
3204 fmt.font_size = oldfmt.font_size;
3208 fmt.cs.color = TRUE;
3211 fmt.font = wp_get_font_index(font_name,
3216 if (font_size_set) {
3217 fmt.cs.font_size = TRUE;
3218 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3220 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3221 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3223 gtk_widget_destroy (dialog);
3225 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3229 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3231 ModestMsgEditWindowPrivate *priv;
3232 ModestWindowPrivate *parent_priv;
3233 gboolean was_rich_text, is_rich_text;
3235 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3236 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3237 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3239 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3241 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3243 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3245 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3247 gtk_widget_show (parent_priv->toolbar);
3249 gtk_widget_hide (parent_priv->toolbar);
3252 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3253 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3257 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3259 ModestMsgEditWindowPrivate *priv;
3261 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3262 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3264 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3266 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3267 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3272 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3274 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3276 priv->can_undo = can_undo;
3280 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3282 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3284 priv->can_redo = can_redo;
3288 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3290 ModestMsgEditWindowPrivate *priv;
3291 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3292 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3294 return priv->can_undo;
3298 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3300 ModestMsgEditWindowPrivate *priv;
3301 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3302 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3304 return priv->can_redo;
3309 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3312 GtkTextIter match_start, match_end;
3314 if (image_id == NULL)
3317 gtk_text_buffer_get_start_iter (buffer, &iter);
3319 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3320 GSList *tags = gtk_text_iter_get_tags (&match_start);
3322 for (node = tags; node != NULL; node = g_slist_next (node)) {
3323 GtkTextTag *tag = (GtkTextTag *) node->data;
3324 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3325 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3326 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3328 offset = gtk_text_iter_get_offset (&match_start);
3329 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3330 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3334 gtk_text_iter_forward_char (&iter);
3339 message_is_empty (ModestMsgEditWindow *window)
3341 ModestMsgEditWindowPrivate *priv = NULL;
3343 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3344 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3346 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3347 * so we can ignore markup.
3349 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3352 count = gtk_text_buffer_get_char_count (buf);
3358 msg_body_focus (GtkWidget *focus,
3359 GdkEventFocus *event,
3363 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3364 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3365 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3370 recpt_field_changed (GtkTextBuffer *buffer,
3371 ModestMsgEditWindow *editor)
3373 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3374 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3378 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3380 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3381 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3385 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3388 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3389 GtkTextBuffer *buffer;
3391 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3392 gtk_text_buffer_set_modified (buffer, modified);
3393 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3394 gtk_text_buffer_set_modified (buffer, modified);
3395 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3396 gtk_text_buffer_set_modified (buffer, modified);
3397 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3401 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3403 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3404 const char *account_name;
3405 GtkTextBuffer *buffer;
3407 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3408 if (gtk_text_buffer_get_modified (buffer))
3410 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3411 if (gtk_text_buffer_get_modified (buffer))
3413 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3414 if (gtk_text_buffer_get_modified (buffer))
3416 if (gtk_text_buffer_get_modified (priv->text_buffer))
3419 account_name = modest_selector_get_active_id (priv->from_field);
3420 if (priv->original_mailbox) {
3421 if (!account_name || strcmp (account_name, priv->original_mailbox))
3423 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3434 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3436 ModestMsgEditWindowPrivate *priv = NULL;
3437 GSList *address_list = NULL;
3439 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3440 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3442 /* check if there's no recipient added */
3443 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3444 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3445 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3446 /* no recipient contents, then select contacts */
3447 modest_msg_edit_window_open_addressbook (window, NULL);
3452 g_object_ref (window);
3453 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3454 (add_to_addressbook) ? &address_list : NULL)) {
3455 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3456 g_object_unref (window);
3459 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3460 (add_to_addressbook) ? &address_list : NULL)) {
3461 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3462 g_object_unref (window);
3465 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3466 (add_to_addressbook) ? &address_list : NULL)) {
3467 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3468 g_object_unref (window);
3472 /* Add contacts to address book */
3473 if (add_to_addressbook && address_list)
3474 modest_address_book_add_address_list (address_list);
3476 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3477 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3478 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3479 g_object_unref (window);
3486 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3488 GSList *recipients = NULL;
3489 ModestMsgEditWindowPrivate *priv;
3490 gchar *joined, *after_remove, *to, *cc, *bcc;
3492 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3494 /* First of all check names */
3495 if (!modest_msg_edit_window_check_names (self, FALSE))
3498 if (!modest_msg_edit_window_has_pending_addresses (self))
3501 /* Don't add the from obviously */
3502 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3503 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3504 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3506 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3511 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3514 recipients = modest_text_utils_split_addresses_list (after_remove);
3515 g_free (after_remove);
3518 /* Offer the user to add recipients to the address book */
3519 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3520 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3525 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3526 ModestMsgEditWindow *window)
3528 modest_msg_edit_window_offer_attach_file (window);
3532 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3534 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3536 return priv->clipboard_text;
3540 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3542 ModestMsgEditWindow *window)
3544 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3545 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3548 /* It could happen that the window was already closed */
3549 if (!GTK_WIDGET_VISIBLE (window))
3552 g_object_ref (window);
3553 text = gtk_clipboard_wait_for_text (selection_clipboard);
3555 if (priv->clipboard_text != NULL) {
3556 g_free (priv->clipboard_text);
3558 priv->clipboard_text = text;
3560 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3562 g_object_unref (window);
3565 static gboolean clipboard_owner_change_idle (gpointer userdata)
3567 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3568 ModestMsgEditWindowPrivate *priv;
3570 gdk_threads_enter ();
3571 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3572 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3574 priv->clipboard_owner_idle = 0;
3575 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3576 gdk_threads_leave ();
3582 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3584 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3585 if (priv->clipboard_owner_idle == 0) {
3586 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3587 clipboard_owner_change_idle,
3588 g_object_ref (window),
3594 subject_field_move_cursor (GtkEntry *entry,
3595 GtkMovementStep step,
3600 /* It could happen that the window was already closed */
3601 if (!GTK_WIDGET_VISIBLE (window))
3604 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3608 update_window_title (ModestMsgEditWindow *window)
3610 ModestMsgEditWindowPrivate *priv = NULL;
3611 const gchar *subject;
3613 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3614 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3615 if (subject == NULL || subject[0] == '\0')
3616 subject = _("mail_va_new_email");
3618 modest_window_set_title (MODEST_WINDOW (window), subject);
3624 body_insert_text (GtkTextBuffer *buffer,
3625 GtkTextIter *location,
3628 ModestMsgEditWindow *window)
3630 GtkTextIter end_iter;
3637 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3639 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3641 offset = gtk_text_iter_get_offset (&end_iter);
3642 line = gtk_text_iter_get_line (&end_iter);
3646 while (text_offset < text + len) {
3647 if (*text_offset == '\n')
3649 if (text_lines + line >= MAX_BODY_LINES) {
3650 len = text_offset - text;
3656 utf8_len = g_utf8_strlen (text, len);
3658 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3659 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3660 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3665 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3667 /* Prevent endless recursion */
3668 result = g_strndup (text, utf8_end - text);
3669 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3670 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3671 (gpointer) result, (gpointer) (utf8_end - text),
3673 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3677 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3678 if (priv->max_chars_banner == NULL) {
3679 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3680 _CS("ckdg_ib_maximum_characters_reached"));
3681 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3687 subject_field_changed (GtkEditable *editable,
3688 ModestMsgEditWindow *window)
3690 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3691 update_window_title (window);
3692 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3693 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3694 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3697 subject_field_insert_text (GtkEditable *editable,
3699 gint new_text_length,
3701 ModestMsgEditWindow *window)
3703 GString *result = g_string_new ("");
3705 gint result_len = 0;
3706 const gchar *entry_text = NULL;
3709 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3710 old_length = g_utf8_strlen (entry_text, -1);
3712 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3713 gunichar c = g_utf8_get_char_validated (current, 8);
3714 /* Invalid unichar, stop */
3720 result = g_string_append_unichar (result, c);
3724 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3725 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3728 /* Prevent endless recursion */
3729 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3730 g_signal_emit_by_name (editable, "insert-text",
3731 (gpointer) result->str, (gpointer) result->len,
3732 (gpointer) position, (gpointer) window);
3733 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3737 if (result_len + old_length > 1000) {
3738 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3739 _CS("ckdg_ib_maximum_characters_reached"));
3741 g_string_free (result, TRUE);
3745 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3748 ModestMsgEditWindowPrivate *priv = NULL;
3750 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3751 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3753 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3756 gtk_widget_show_all (priv->isearch_toolbar);
3757 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3759 gtk_widget_hide_all (priv->isearch_toolbar);
3760 gtk_widget_grab_focus (priv->msg_body);
3765 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3767 GtkTextIter *match_start,
3768 GtkTextIter *match_end)
3770 GtkTextIter end_iter;
3771 gchar *str_casefold;
3774 gchar *range_casefold;
3777 gboolean result = FALSE;
3784 gtk_text_iter_forward_to_end (&end_iter);
3786 str_casefold = g_utf8_casefold (str, -1);
3787 str_chars_n = strlen (str);
3789 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3790 range_casefold = g_utf8_casefold (range_text, -1);
3791 range_chars_n = strlen (range_casefold);
3793 if (range_chars_n < str_chars_n) {
3794 g_free (str_casefold);
3795 g_free (range_text);
3796 g_free (range_casefold);
3800 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3801 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3802 if (!g_utf8_collate (range_subtext, str_casefold)) {
3803 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3805 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3806 match_start, match_end, NULL)) {
3807 g_debug ("Matched string with collate, but not matched in model");
3809 g_free (found_text);
3811 g_free (range_subtext);
3815 g_free (str_casefold);
3816 g_free (range_text);
3817 g_free (range_casefold);
3824 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
3825 ModestMsgEditWindow *window)
3827 const gchar *current_search = NULL;
3828 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3830 GtkTextIter selection_start, selection_end;
3831 GtkTextIter match_start, match_end;
3832 gboolean continue_search = FALSE;
3834 if (message_is_empty (window)) {
3835 g_free (priv->last_search);
3836 priv->last_search = NULL;
3837 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3841 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
3842 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3843 g_free (priv->last_search);
3844 priv->last_search = NULL;
3845 /* Information banner about empty search */
3846 modest_platform_system_banner (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3850 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3851 continue_search = TRUE;
3853 g_free (priv->last_search);
3854 priv->last_search = g_strdup (current_search);
3857 if (continue_search) {
3858 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3859 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3860 &match_start, &match_end);
3862 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3864 GtkTextIter buffer_start;
3865 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3866 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3867 &match_start, &match_end);
3869 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3872 /* Mark as selected the string found in search */
3874 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3875 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3876 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3878 g_free (priv->last_search);
3879 priv->last_search = NULL;
3884 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3886 ModestMsgEditWindowPrivate *priv;
3888 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3893 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3896 ModestMsgEditWindowPrivate *priv;
3898 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3903 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
3904 ModestMsgEditWindow *window)
3906 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
3910 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3913 ModestMsgEditWindowPrivate *priv;
3914 TnyHeader *header = NULL;
3916 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3917 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3919 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3921 if (priv->draft_msg != NULL) {
3922 g_object_unref (priv->draft_msg);
3925 if (draft != NULL) {
3926 g_object_ref (draft);
3927 header = tny_msg_get_header (draft);
3928 if (priv->msg_uid) {
3929 g_free (priv->msg_uid);
3930 priv->msg_uid = NULL;
3932 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3935 priv->draft_msg = draft;
3939 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3940 GtkTextIter *start, GtkTextIter *end,
3943 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3944 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3947 if (tag == NULL) return;
3948 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3949 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3950 replace_with_images (window, priv->images);
3955 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3958 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3960 g_return_if_fail (TNY_IS_MIME_PART (part));
3961 tny_list_prepend (priv->attachments, (GObject *) part);
3962 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3963 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3964 gtk_widget_show_all (priv->attachments_caption);
3965 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3969 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3971 ModestMsgEditWindowPrivate *priv;
3973 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3974 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3976 return priv->msg_uid;
3980 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3981 ModestMsgEditWindowWidgetType widget_type)
3983 ModestMsgEditWindowPrivate *priv;
3985 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3986 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3988 switch (widget_type) {
3989 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3990 return priv->msg_body;
3992 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3993 return priv->to_field;
3995 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3996 return priv->cc_field;
3998 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3999 return priv->bcc_field;
4001 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4002 return priv->subject_field;
4004 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4005 return priv->attachments_view;
4013 remove_tags (WPTextBuffer *buffer)
4015 GtkTextIter start, end;
4017 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4018 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4020 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4024 on_account_removed (TnyAccountStore *account_store,
4025 TnyAccount *account,
4028 /* Do nothing if it's a store account, because we use the
4029 transport to send the messages */
4030 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4031 const gchar *parent_acc = NULL;
4032 const gchar *our_acc = NULL;
4034 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4035 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4036 /* Close this window if I'm showing a message of the removed account */
4037 if (strcmp (parent_acc, our_acc) == 0)
4038 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4043 update_signature (ModestMsgEditWindow *self,
4044 const gchar *old_account,
4045 const gchar *new_account)
4047 ModestMsgEditWindowPrivate *priv;
4048 gboolean has_old_signature, has_new_signature;
4050 ModestAccountMgr *mgr;
4053 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4055 gtk_text_buffer_begin_user_action (priv->text_buffer);
4057 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4058 mgr = modest_runtime_get_account_mgr ();
4062 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4063 if (has_old_signature) {
4064 GtkTextIter match_start, match_end;
4066 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4067 seems that the search has some problems
4068 with the blank space at the end */
4069 if (gtk_text_iter_forward_search (&iter, "--",
4070 GTK_TEXT_SEARCH_TEXT_ONLY,
4071 &match_start, NULL, NULL)) {
4072 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4073 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4075 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4076 &match_start, &match_end, NULL)) {
4080 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4085 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4086 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4087 if (has_new_signature) {
4089 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4090 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4092 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4093 g_free (full_signature);
4096 gtk_text_buffer_end_user_action (priv->text_buffer);
4099 static void update_branding (ModestMsgEditWindow *self,
4100 const gchar *new_account)
4102 ModestMsgEditWindowPrivate *priv;
4103 ModestAccountMgr *mgr;
4104 const GdkPixbuf *new_icon = NULL;
4105 gchar *new_label = NULL;
4106 gboolean show = FALSE;
4108 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4110 mgr = modest_runtime_get_account_mgr ();
4112 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4114 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4115 gtk_widget_show (priv->brand_icon);
4118 gtk_widget_hide (priv->brand_icon);
4121 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4122 gtk_widget_show (priv->brand_label);
4126 gtk_widget_hide (priv->brand_label);
4130 gtk_widget_show (priv->brand_container);
4132 gtk_widget_hide (priv->brand_container);
4136 from_field_changed (GtkWidget *button,
4137 ModestMsgEditWindow *self)
4139 ModestMsgEditWindowPrivate *priv;
4140 gchar *old_account, *new_account;
4142 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4144 old_account = priv->last_from_account;
4145 new_account = modest_selector_get_active_id (priv->from_field);
4148 g_warning ("%s, could not get the new account", __FUNCTION__);
4152 /* If the From is the same do nothing */
4153 if (old_account && new_account && !strcmp (old_account, new_account))
4156 priv->last_from_account = new_account;
4158 update_signature (self, old_account, new_account);
4159 update_branding (self, new_account);
4163 typedef struct _MessageSettingsHelper {
4164 ModestMsgEditWindow *window;
4165 GSList *priority_group;
4166 GSList *format_group;
4167 GtkToggleButton *current_priority;
4168 GtkToggleButton *current_format;
4169 } MessageSettingsHelper;
4172 on_priority_toggle (GtkToggleButton *button,
4173 MessageSettingsHelper *helper)
4176 ModestMsgEditWindowPrivate *priv;
4178 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4179 if (gtk_toggle_button_get_active (button)) {
4181 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4182 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4183 if ((node_button != button) &&
4184 gtk_toggle_button_get_active (node_button)) {
4185 gtk_toggle_button_set_active (node_button, FALSE);
4188 helper->current_priority = button;
4190 gboolean found = FALSE;
4191 /* If no one is active, activate it again */
4192 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4193 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4194 if (gtk_toggle_button_get_active (node_button)) {
4200 gtk_toggle_button_set_active (button, TRUE);
4206 on_format_toggle (GtkToggleButton *button,
4207 MessageSettingsHelper *helper)
4210 ModestMsgEditWindowPrivate *priv;
4212 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4213 if (gtk_toggle_button_get_active (button)) {
4215 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4216 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4217 if ((node_button != button) &&
4218 gtk_toggle_button_get_active (node_button)) {
4219 gtk_toggle_button_set_active (node_button, FALSE);
4222 helper->current_format = button;
4224 gboolean found = FALSE;
4225 /* If no one is active, activate it again */
4226 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4227 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4228 if (gtk_toggle_button_get_active (node_button)) {
4234 gtk_toggle_button_set_active (button, TRUE);
4241 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4246 GtkWidget *priority_hbox;
4247 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4248 GtkWidget *captioned;
4249 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4250 GtkWidget *format_hbox;
4251 GtkWidget *html_toggle, *text_toggle;
4252 ModestMsgEditWindowPrivate *priv;
4253 MessageSettingsHelper helper = {0,};
4255 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4256 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4257 helper.window = window;
4258 helper.priority_group = NULL;
4259 helper.format_group = NULL;
4261 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4262 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4264 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4265 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4266 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4267 vbox = gtk_vbox_new (FALSE, 0);
4268 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4269 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4270 gtk_container_add (GTK_CONTAINER (align), vbox);
4271 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4272 gtk_widget_show (align);
4273 gtk_widget_show (vbox);
4275 /* Priority toggles */
4276 priority_hbox = gtk_hbox_new (TRUE, 0);
4277 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4278 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4279 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4280 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4281 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4282 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4283 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4284 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4285 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4286 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4287 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4288 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4289 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4290 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4291 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4292 gtk_widget_show_all (priority_hbox);
4293 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4294 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4295 gtk_widget_show (captioned);
4296 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4298 /* format toggles */
4299 format_hbox = gtk_hbox_new (TRUE, 0);
4300 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4301 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4302 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4303 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4304 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4305 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4306 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4307 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4308 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4309 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4310 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4311 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4312 gtk_widget_show_all (format_hbox);
4313 gtk_widget_show (format_hbox);
4314 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4317 g_object_unref (title_sizegroup);
4318 g_object_unref (value_sizegroup);
4320 /* Set current values */
4321 switch (priv->priority_flags) {
4322 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4323 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4324 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4326 case TNY_HEADER_FLAG_LOW_PRIORITY:
4327 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4328 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4331 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4332 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4336 switch (modest_msg_edit_window_get_format (window)) {
4337 case MODEST_MSG_EDIT_FORMAT_TEXT:
4338 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4339 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4341 case MODEST_MSG_EDIT_FORMAT_HTML:
4343 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4344 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4348 /* Signal connects */
4349 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4350 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4351 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4352 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4353 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4355 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4356 GTK_WINDOW (dialog), GTK_WINDOW (window));
4358 /* Save settings if the user clicked on done */
4359 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4360 TnyHeaderFlags flags;
4361 ModestMsgEditFormat old_format, new_format;
4363 /* Set priority flags */
4364 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4365 if (priv->priority_flags != flags)
4366 modest_msg_edit_window_set_priority_flags (window, flags);
4368 /* Set edit format */
4369 old_format = modest_msg_edit_window_get_format (window);
4370 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4371 if (old_format != new_format) {
4372 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4373 modest_msg_edit_window_set_file_format (window, file_format);
4377 gtk_widget_destroy (dialog);
4378 g_slist_free (helper.priority_group);
4382 on_message_settings (GtkAction *action,
4383 ModestMsgEditWindow *window)
4385 modest_msg_edit_window_show_msg_settings_dialog (window);
4389 on_cc_button_toggled (GtkWidget *button,
4390 ModestMsgEditWindow *window)
4392 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4394 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4395 modest_togglable_get_active (button));
4399 on_bcc_button_toggled (GtkWidget *button,
4400 ModestMsgEditWindow *window)
4402 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4404 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4405 modest_togglable_get_active (button));
4409 setup_menu (ModestMsgEditWindow *self)
4411 ModestMsgEditWindowPrivate *priv = NULL;
4413 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4415 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4417 /* Settings menu buttons */
4418 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4419 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4421 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4422 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4423 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4424 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4425 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4426 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4428 priv->cc_button = hildon_check_button_new (0);
4429 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4430 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4432 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4433 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4434 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4436 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4437 _("mcen_me_editor_showbcc"));
4438 modest_togglable_set_active (priv->bcc_button,
4440 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4442 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4443 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4445 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4446 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4447 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4448 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4449 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4451 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4452 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4453 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4454 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4455 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4457 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4458 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4463 emit_open_addressbook (GtkButton *button,
4464 ModestRecptEditor *editor)
4466 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4470 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4471 const gchar *label, GtkWidget *control)
4473 GtkWidget *abook_button;
4476 GtkWidget *label_widget;
4478 box = gtk_hbox_new (FALSE, 0);
4480 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4481 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4483 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4484 label_widget = gtk_label_new (label);
4485 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4486 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4488 gtk_container_add (GTK_CONTAINER (align), abook_button);
4489 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4490 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4491 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4492 if (title_size_group)
4493 gtk_size_group_add_widget (title_size_group, label_widget);
4494 if (value_size_group)
4495 gtk_size_group_add_widget (value_size_group, control);
4497 g_signal_connect (G_OBJECT (abook_button), "clicked",
4498 G_CALLBACK (emit_open_addressbook), control);
4504 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4506 ModestMsgEditWindowPrivate *priv = NULL;
4508 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4510 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4511 priv->max_chars_banner = NULL;
4515 has_pending_addresses (ModestRecptEditor *recpt_editor)
4517 const gchar *recipients = NULL;
4518 GSList *start_indexes = NULL, *end_indexes = NULL;
4519 GSList *current_start, *current_end;
4520 GtkTextBuffer *buffer;
4521 gint offset_delta = 0;
4523 gboolean has_recipients_to_add = FALSE;
4525 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4526 last_length = g_utf8_strlen (recipients, -1);
4527 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4532 current_start = start_indexes;
4533 current_end = end_indexes;
4534 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4536 while (current_start && !has_recipients_to_add) {
4538 gchar *start_ptr, *end_ptr;
4539 gint start_pos, end_pos;
4541 start_pos = (*((gint*) current_start->data)) + offset_delta;
4542 end_pos = (*((gint*) current_end->data)) + offset_delta;
4544 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4545 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4547 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4549 if (modest_text_utils_validate_recipient (address, NULL)) {
4550 if (!modest_address_book_has_address (address)) {
4551 has_recipients_to_add = TRUE;
4554 current_start = g_slist_next (current_start);
4555 current_end = g_slist_next (current_end);
4557 return has_recipients_to_add;
4561 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4563 ModestMsgEditWindowPrivate *priv = NULL;
4565 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4567 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4569 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4570 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4571 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))