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>
79 #include "modest-color-button.h"
81 #ifdef MODEST_USE_CALENDAR_WIDGETS
82 #include <calendar-ui-widgets.h>
85 #define DEFAULT_FONT_SIZE 3
86 #define DEFAULT_FONT 2
87 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
88 #define DEFAULT_MAIN_VBOX_SPACING 0
89 #define SUBJECT_MAX_LENGTH 1000
90 #define IMAGE_MAX_WIDTH 560
91 #define DEFAULT_FONT_SCALE 1.5
92 #define ATTACHMENT_BUTTON_WIDTH 118
93 #define MAX_FROM_VALUE 36
94 #define MAX_BODY_LENGTH 128*1024
95 #define MAX_BODY_LINES 2048
97 static gboolean is_wp_text_buffer_started = FALSE;
99 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
100 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
101 static void modest_msg_edit_window_finalize (GObject *obj);
103 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
104 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
105 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
107 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
108 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
109 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
110 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
111 GtkTextIter *start, GtkTextIter *end,
113 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
114 static void body_insert_text (GtkTextBuffer *buffer,
115 GtkTextIter *location,
118 ModestMsgEditWindow *window);
119 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
120 static void subject_field_insert_text (GtkEditable *editable,
122 gint new_text_length,
124 ModestMsgEditWindow *window);
125 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
127 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
129 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
130 ModestRecptEditor *editor);
131 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
132 ModestMsgEditWindow *window);
134 /* ModestWindow methods implementation */
135 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
136 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
137 gboolean show_toolbar);
138 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
140 ModestMsgEditWindow *window);
141 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
142 static void subject_field_move_cursor (GtkEntry *entry,
143 GtkMovementStep step,
147 static void update_window_title (ModestMsgEditWindow *window);
150 static void modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
151 ModestMsgEditWindow *window);
152 static void modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
153 ModestMsgEditWindow *window);
154 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
156 GtkTextIter *match_start,
157 GtkTextIter *match_end);
159 static void remove_tags (WPTextBuffer *buffer);
161 static void on_account_removed (TnyAccountStore *account_store,
165 static void init_window (ModestMsgEditWindow *obj);
167 gboolean scroll_drag_timeout (gpointer userdata);
168 static void correct_scroll (ModestMsgEditWindow *w);
169 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
170 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
171 ModestMsgEditWindow *userdata);
172 static void text_buffer_mark_set (GtkTextBuffer *buffer,
175 ModestMsgEditWindow *userdata);
176 static void on_message_settings (GtkAction *action,
177 ModestMsgEditWindow *window);
178 static void setup_menu (ModestMsgEditWindow *self);
180 static void from_field_changed (GtkWidget *button,
181 ModestMsgEditWindow *self);
182 static void font_size_clicked (GtkToolButton *button,
183 ModestMsgEditWindow *window);
184 static void font_face_clicked (GtkToolButton *button,
185 ModestMsgEditWindow *window);
186 static void update_signature (ModestMsgEditWindow *self,
187 const gchar *old_account,
188 const gchar *new_account);
189 static void update_branding (ModestMsgEditWindow *self,
190 const gchar *new_account);
191 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
192 const gchar *label, GtkWidget *control);
193 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
194 static void DEBUG_BUFFER (WPTextBuffer *buffer)
198 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
200 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
201 while (!gtk_text_iter_is_end (&iter)) {
202 GString *output = g_string_new ("");
203 GSList *toggled_tags;
206 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
207 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
208 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
209 GtkTextTag *tag = (GtkTextTag *) node->data;
211 g_object_get (G_OBJECT (tag), "name", &name, NULL);
212 output = g_string_append (output, name);
213 g_string_append (output, " ");
215 output = g_string_append (output, "] OPENED [ ");
216 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
217 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
218 GtkTextTag *tag = (GtkTextTag *) node->data;
220 g_object_get (G_OBJECT (tag), "name", &name, NULL);
221 output = g_string_append (output, name);
222 g_string_append (output, " ");
224 output = g_string_append (output, "]\n");
225 g_debug ("%s", output->str);
226 g_string_free (output, TRUE);
227 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
229 g_debug ("END BUFFER");
233 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
234 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
238 /* static gboolean */
239 /* on_key_pressed (GtkWidget *self, */
240 /* GdkEventKey *event, */
241 /* gpointer user_data); */
243 /* list my signals */
250 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
251 struct _ModestMsgEditWindowPrivate {
253 GtkWidget *header_box;
255 ModestPairList *from_field_protos;
256 GtkWidget *from_field;
257 gchar *last_from_account;
258 gchar *original_account_name;
263 gchar *original_mailbox;
267 GtkWidget *bcc_field;
268 GtkWidget *subject_field;
269 GtkWidget *attachments_view;
270 GtkWidget *priority_icon;
271 GtkWidget *subject_box;
272 GtkWidget *send_button;
274 GtkWidget *cc_caption;
275 GtkWidget *bcc_caption;
276 gboolean update_caption_visibility;
277 GtkWidget *attachments_caption;
279 GtkTextBuffer *text_buffer;
281 GtkWidget *font_size_toolitem;
282 GtkWidget *font_face_toolitem;
283 GtkWidget *font_color_button;
284 GtkWidget *font_color_toolitem;
285 GSList *font_items_group;
286 GtkTreeModel *faces_model;
287 gint current_face_index;
288 GtkWidget *font_tool_button_label;
289 GtkTreeModel *sizes_model;
290 gint current_size_index;
291 GtkWidget *size_tool_button_label;
293 GtkWidget *isearch_toolbar;
296 GtkWidget *font_dialog;
298 GtkWidget *scrollable;
299 guint correct_scroll_idle;
300 guint scroll_drag_timeout_id;
304 TnyList *attachments;
309 TnyHeaderFlags priority_flags;
311 gboolean can_undo, can_redo;
312 gulong clipboard_change_handler_id;
313 gulong default_clipboard_change_handler_id;
314 gulong account_removed_handler_id;
315 guint clipboard_owner_idle;
316 gchar *clipboard_text;
325 GtkWidget *cc_button;
326 GtkWidget *bcc_button;
328 GtkWidget *max_chars_banner;
330 GtkWidget *brand_icon;
331 GtkWidget *brand_label;
332 GtkWidget *brand_container;
335 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
336 MODEST_TYPE_MSG_EDIT_WINDOW, \
337 ModestMsgEditWindowPrivate))
339 static GtkWindowClass *parent_class = NULL;
341 /* uncomment the following if you have defined any signals */
342 /* static guint signals[LAST_SIGNAL] = {0}; */
345 modest_msg_edit_window_get_type (void)
347 static GType my_type = 0;
349 static const GTypeInfo my_info = {
350 sizeof(ModestMsgEditWindowClass),
351 NULL, /* base init */
352 NULL, /* base finalize */
353 (GClassInitFunc) modest_msg_edit_window_class_init,
354 NULL, /* class finalize */
355 NULL, /* class data */
356 sizeof(ModestMsgEditWindow),
358 (GInstanceInitFunc) modest_msg_edit_window_init,
361 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
362 "ModestMsgEditWindow",
370 save_state (ModestWindow *self)
372 modest_widget_memory_save (modest_runtime_get_conf(),
373 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
378 restore_settings (ModestMsgEditWindow *self)
380 ModestConf *conf = NULL;
382 conf = modest_runtime_get_conf ();
384 /* Dim at start clipboard actions */
385 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
390 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
392 GObjectClass *gobject_class;
393 ModestWindowClass *modest_window_class;
394 gobject_class = (GObjectClass*) klass;
395 modest_window_class = (ModestWindowClass*) klass;
397 parent_class = g_type_class_peek_parent (klass);
398 gobject_class->finalize = modest_msg_edit_window_finalize;
400 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
401 modest_window_class->save_state_func = save_state;
402 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
404 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
408 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
410 ModestMsgEditWindowPrivate *priv;
411 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
413 priv->msg_body = NULL;
414 priv->from_field = NULL;
415 priv->to_field = NULL;
416 priv->cc_field = NULL;
417 priv->bcc_field = NULL;
418 priv->subject_field = NULL;
419 priv->attachments = TNY_LIST (tny_simple_list_new ());
420 priv->images = TNY_LIST (tny_simple_list_new ());
421 priv->images_size = 0;
422 priv->images_count = 0;
425 priv->cc_caption = NULL;
426 priv->bcc_caption = NULL;
427 priv->update_caption_visibility = FALSE;
429 priv->priority_flags = 0;
431 priv->isearch_toolbar = NULL;
432 priv->last_search = NULL;
434 priv->draft_msg = NULL;
435 priv->outbox_msg = NULL;
436 priv->msg_uid = NULL;
438 priv->can_undo = FALSE;
439 priv->can_redo = FALSE;
440 priv->clipboard_change_handler_id = 0;
441 priv->default_clipboard_change_handler_id = 0;
442 priv->account_removed_handler_id = 0;
443 priv->clipboard_owner_idle = 0;
444 priv->clipboard_text = NULL;
447 priv->scroll_drag_timeout_id = 0;
448 priv->correct_scroll_idle = 0;
449 priv->last_upper = 0.0;
451 priv->font_dialog = NULL;
452 priv->app_menu = NULL;
454 priv->references = NULL;
455 priv->in_reply_to = NULL;
456 priv->max_chars_banner = NULL;
458 if (!is_wp_text_buffer_started) {
459 is_wp_text_buffer_started = TRUE;
460 wp_text_buffer_library_init ();
465 hildon_program_add_window (hildon_program_get_instance(),
470 multimailbox_get_default_mailbox (const gchar *account_name)
472 gchar *transport_account;
473 gchar *result = NULL;
475 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
477 TNY_ACCOUNT_TYPE_TRANSPORT);
478 if (transport_account) {
480 ModestProtocolRegistry *registry;
482 registry = modest_runtime_get_protocol_registry ();
484 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
485 MODEST_ACCOUNT_PROTO, TRUE);
487 ModestProtocol *protocol =
488 modest_protocol_registry_get_protocol_by_name (registry,
489 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
491 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
492 ModestPairList *pair_list;
494 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
497 ModestPair *pair = (ModestPair *) pair_list->data;
498 result = g_strdup ((const gchar *) pair->first);
499 modest_pair_list_free (pair_list);
510 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
512 static ModestPairList*
513 get_transports (void)
515 GSList *transports = NULL;
517 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
518 GSList *accounts = modest_account_mgr_account_names (account_mgr,
519 TRUE /* only enabled accounts. */);
521 GSList *cursor = accounts;
523 gchar *account_name = cursor->data;
526 gchar *transport_account;
527 gboolean multi_mailbox = FALSE;
528 ModestProtocol *protocol = NULL;
530 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
532 transport_account = modest_account_mgr_get_server_account_name
533 (modest_runtime_get_account_mgr (),
535 TNY_ACCOUNT_TYPE_TRANSPORT);
536 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
537 ModestPairList *pair_list;
538 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
541 transports = g_slist_concat (transports, pair_list);
542 multi_mailbox = TRUE;
547 if (!multi_mailbox) {
548 gchar *from_string = NULL;
550 from_string = modest_account_mgr_get_from_string (account_mgr,
552 if (from_string && account_name) {
553 gchar *name = account_name;
554 ModestPair *pair = modest_pair_new ((gpointer) name,
555 (gpointer) from_string , TRUE);
556 transports = g_slist_prepend (transports, pair);
561 cursor = cursor->next;
563 g_slist_free (accounts); /* only free the accounts, not the elements,
564 * because they are used in the pairlist */
568 static void window_focus (GtkWindow *window,
572 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
576 scroll_drag_timeout (gpointer userdata)
578 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
579 ModestMsgEditWindowPrivate *priv;
581 /* It could happen that the window was already closed */
582 if (!GTK_WIDGET_VISIBLE (win))
585 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
587 correct_scroll_without_drag_check (win, TRUE);
589 priv->scroll_drag_timeout_id = 0;
595 correct_scroll_without_drag_check_idle (gpointer userdata)
597 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
598 ModestMsgEditWindowPrivate *priv;
600 GdkRectangle rectangle;
601 gint offset_min, offset_max;
605 /* It could happen that the window was already closed */
606 if (!GTK_WIDGET_VISIBLE (w))
609 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
611 insert = gtk_text_buffer_get_insert (priv->text_buffer);
612 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
614 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
615 offset_min = priv->msg_body->allocation.y + rectangle.y;
616 offset_max = offset_min + rectangle.height;
618 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
619 offset_min = MAX (offset_min - 48, 0);
620 offset_max = MIN (offset_max + 48, vadj->upper);
622 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
624 priv->correct_scroll_idle = 0;
629 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
631 ModestMsgEditWindowPrivate *priv;
633 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
635 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
638 if (priv->correct_scroll_idle > 0) {
642 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
643 (GSourceFunc) correct_scroll_without_drag_check_idle,
649 correct_scroll (ModestMsgEditWindow *w)
651 ModestMsgEditWindowPrivate *priv;
653 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
654 if (gtk_grab_get_current () == priv->msg_body) {
655 if (priv->scroll_drag_timeout_id == 0) {
656 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
658 (GSourceFunc) scroll_drag_timeout,
665 correct_scroll_without_drag_check (w, TRUE);
669 text_buffer_end_user_action (GtkTextBuffer *buffer,
670 ModestMsgEditWindow *userdata)
673 correct_scroll (userdata);
677 text_buffer_mark_set (GtkTextBuffer *buffer,
680 ModestMsgEditWindow *userdata)
682 gtk_text_buffer_begin_user_action (buffer);
683 gtk_text_buffer_end_user_action (buffer);
687 cut_clipboard_check (GtkTextView *text_view,
690 GtkTextBuffer *buffer;
692 buffer = gtk_text_view_get_buffer (text_view);
693 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
694 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
699 copy_clipboard_check (GtkTextView *text_view,
702 GtkTextBuffer *buffer;
704 buffer = gtk_text_view_get_buffer (text_view);
705 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
706 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
711 attachment_deleted (ModestAttachmentsView *attachments_view,
714 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
719 body_size_request (GtkWidget *body,
723 /* Make sure the body always get at least 70 pixels */
724 if (req->height < 70)
729 connect_signals (ModestMsgEditWindow *obj)
731 ModestMsgEditWindowPrivate *priv;
733 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
735 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
736 G_CALLBACK (text_buffer_refresh_attributes), obj);
737 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
738 G_CALLBACK (text_buffer_can_undo), obj);
739 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
740 G_CALLBACK (text_buffer_can_redo), obj);
741 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
742 G_CALLBACK (body_changed), obj);
743 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
744 G_CALLBACK (body_insert_text), obj);
745 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
746 G_CALLBACK (body_changed), obj);
747 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
748 G_CALLBACK (text_buffer_end_user_action), obj);
749 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
750 G_CALLBACK (text_buffer_mark_set), obj);
751 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
752 G_CALLBACK (text_buffer_apply_tag), obj);
753 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
754 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
755 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
756 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
757 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
758 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
760 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
761 G_CALLBACK (modest_ui_actions_on_send), obj);
763 if (GTK_IS_COMBO_BOX (priv->from_field)) {
764 g_signal_connect (G_OBJECT (priv->from_field), "changed",
765 G_CALLBACK (from_field_changed), obj);
767 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
768 G_CALLBACK (from_field_changed), obj);
771 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
772 G_CALLBACK (msg_body_focus), obj);
773 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
774 G_CALLBACK (msg_body_focus), obj);
775 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
776 G_CALLBACK (body_size_request), obj);
777 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
778 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
779 "changed", G_CALLBACK (recpt_field_changed), obj);
780 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
781 "changed", G_CALLBACK (recpt_field_changed), obj);
782 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
783 "changed", G_CALLBACK (recpt_field_changed), obj);
784 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
785 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
786 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
788 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
789 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
790 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
791 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_close), obj);
793 priv->clipboard_change_handler_id =
794 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
795 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
796 priv->default_clipboard_change_handler_id =
797 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
798 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
800 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
801 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
802 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
806 init_wp_text_view_style ()
808 static gboolean initialized = FALSE;
811 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
817 init_window (ModestMsgEditWindow *obj)
819 GtkWidget *to_caption, *subject_caption;
820 GtkWidget *main_vbox;
821 ModestMsgEditWindowPrivate *priv;
822 GtkActionGroup *action_group;
823 ModestWindowPrivate *parent_priv;
824 GdkPixbuf *window_icon = NULL;
825 GError *error = NULL;
827 GtkSizeGroup *title_size_group;
828 GtkSizeGroup *value_size_group;
829 GtkWidget *window_box;
830 GtkWidget *window_align;
831 #if (GTK_MINOR_VERSION >= 10)
832 GdkAtom deserialize_type;
834 GtkWidget *from_send_hbox;
835 GtkWidget *send_icon;
836 GtkWidget *attachments_label;
837 GtkWidget *branding_box;
838 GtkWidget *from_caption;
840 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
841 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
843 parent_priv->ui_manager = gtk_ui_manager_new();
844 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
845 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
847 /* Add common actions */
848 gtk_action_group_add_actions (action_group,
849 modest_msg_edit_action_entries,
850 G_N_ELEMENTS (modest_msg_edit_action_entries),
852 gtk_action_group_add_actions (action_group,
853 hildon2_msg_edit_action_entries,
854 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
856 gtk_action_group_add_toggle_actions (action_group,
857 modest_msg_edit_toggle_action_entries,
858 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
860 gtk_action_group_add_radio_actions (action_group,
861 modest_msg_edit_alignment_radio_action_entries,
862 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
864 G_CALLBACK (modest_ui_actions_on_change_justify),
866 gtk_action_group_add_radio_actions (action_group,
867 modest_msg_edit_priority_action_entries,
868 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
870 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
872 gtk_action_group_add_radio_actions (action_group,
873 modest_msg_edit_file_format_action_entries,
874 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
875 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
876 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
878 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
879 g_object_unref (action_group);
881 /* Load the UI definition */
882 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
885 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
886 g_clear_error (&error);
889 /* Add accelerators */
890 gtk_window_add_accel_group (GTK_WINDOW (obj),
891 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
893 parent_priv->menubar = NULL;
895 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
896 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
898 /* Note: This ModestPairList* must exist for as long as the picker
899 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
900 * so it can't know how to manage its memory. */
901 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
903 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
904 if (GTK_IS_COMBO_BOX (priv->from_field)) {
905 from_caption = modest_toolkit_utils_create_captioned (title_size_group, NULL,
906 _("mail_va_from"), FALSE,
908 gtk_widget_show (from_caption);
910 modest_toolkit_utils_set_hbutton_layout (title_size_group, NULL,
911 _("mail_va_from"), priv->from_field);
912 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
913 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
914 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
915 from_caption = priv->from_field;
918 priv->to_field = modest_recpt_editor_new ();
919 priv->cc_field = modest_recpt_editor_new ();
920 priv->bcc_field = modest_recpt_editor_new ();
921 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
922 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
923 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
924 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
925 priv->priority_icon = gtk_image_new ();
926 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
927 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
928 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
929 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
930 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
931 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
932 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
933 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
934 priv->attachments_view = modest_attachments_view_new (NULL);
935 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
936 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
938 priv->header_box = gtk_vbox_new (FALSE, 0);
940 to_caption = _create_addressbook_box
941 (title_size_group, value_size_group,
942 _("mail_va_to"), priv->to_field);
943 priv->cc_caption = _create_addressbook_box
944 (title_size_group, value_size_group,
945 _("mail_va_cc"), priv->cc_field);
946 priv->bcc_caption = _create_addressbook_box
947 (title_size_group, value_size_group,
948 _("mail_va_hotfix1"), priv->bcc_field);
949 subject_caption = modest_toolkit_utils_create_captioned (title_size_group, value_size_group,
950 _("mail_va_subject"), FALSE, priv->subject_box);
951 priv->attachments_caption = modest_toolkit_utils_create_captioned_with_size_type (NULL, NULL,
952 _("mail_va_attachment"),
954 priv->attachments_view,
955 HILDON_SIZE_AUTO_WIDTH |
956 HILDON_SIZE_AUTO_HEIGHT);
957 attachments_label = modest_toolkit_utils_captioned_get_label_widget (priv->attachments_caption);
958 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
961 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
962 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
963 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
964 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
966 g_object_unref (title_size_group);
967 g_object_unref (value_size_group);
969 priv->brand_icon = gtk_image_new ();
970 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
971 priv->brand_label = gtk_label_new (NULL);
972 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
973 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
974 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
975 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
977 from_send_hbox = gtk_hbox_new (FALSE, 0);
978 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
979 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
981 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
982 gtk_widget_show (branding_box);
983 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
984 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
986 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
987 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
988 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
989 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
992 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
993 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
994 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
995 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
996 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
997 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
998 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
999 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1001 init_wp_text_view_style ();
1003 priv->msg_body = modest_wp_text_view_new ();
1006 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1007 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1008 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1009 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1010 #if (GTK_MINOR_VERSION >= 10)
1011 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1012 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1014 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1015 deserialize_type, TRUE);
1017 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1019 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1021 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1023 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1025 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1027 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1029 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1030 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1031 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1033 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1034 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1035 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1037 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1038 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1040 window_box = gtk_vbox_new (FALSE, 0);
1041 gtk_container_add (GTK_CONTAINER(obj), window_box);
1043 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1045 /* Set window icon */
1046 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1048 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1049 g_object_unref (window_icon);
1054 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1056 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1058 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1059 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1060 priv->clipboard_change_handler_id))
1061 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1062 priv->clipboard_change_handler_id);
1063 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1064 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1065 priv->default_clipboard_change_handler_id))
1066 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1067 priv->default_clipboard_change_handler_id);
1069 if (priv->account_removed_handler_id &&
1070 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1071 priv->account_removed_handler_id))
1072 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1073 priv->account_removed_handler_id);
1077 modest_msg_edit_window_finalize (GObject *obj)
1079 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1081 if (priv->max_chars_banner) {
1082 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1083 priv->max_chars_banner = FALSE;
1086 /* Sanity check: shouldn't be needed, the window mgr should
1087 call this function before */
1088 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1090 if (priv->font_dialog != NULL) {
1091 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1094 if (priv->clipboard_text != NULL) {
1095 g_free (priv->clipboard_text);
1096 priv->clipboard_text = NULL;
1099 if (priv->draft_msg != NULL) {
1100 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1101 if (TNY_IS_HEADER (header)) {
1102 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1103 modest_window_mgr_unregister_header (mgr, header);
1105 g_object_unref (priv->draft_msg);
1106 priv->draft_msg = NULL;
1108 if (priv->outbox_msg != NULL) {
1109 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1110 if (TNY_IS_HEADER (header)) {
1111 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1112 modest_window_mgr_unregister_header (mgr, header);
1114 g_object_unref (priv->outbox_msg);
1115 priv->outbox_msg = NULL;
1117 if (priv->correct_scroll_idle > 0) {
1118 g_source_remove (priv->correct_scroll_idle);
1119 priv->correct_scroll_idle = 0;
1121 if (priv->scroll_drag_timeout_id > 0) {
1122 g_source_remove (priv->scroll_drag_timeout_id);
1123 priv->scroll_drag_timeout_id = 0;
1125 if (priv->clipboard_owner_idle > 0) {
1126 g_source_remove (priv->clipboard_owner_idle);
1127 priv->clipboard_owner_idle = 0;
1129 if (priv->original_account_name)
1130 g_free (priv->original_account_name);
1131 if (priv->original_mailbox)
1132 g_free (priv->original_mailbox);
1133 g_free (priv->msg_uid);
1134 g_free (priv->last_search);
1135 g_free (priv->references);
1136 g_free (priv->in_reply_to);
1137 g_object_unref (priv->attachments);
1138 g_object_unref (priv->images);
1140 /* This had to stay alive for as long as the picker that used it: */
1141 modest_pair_list_free (priv->from_field_protos);
1143 G_OBJECT_CLASS(parent_class)->finalize (obj);
1147 pixbuf_size_prepared (GdkPixbufLoader *loader,
1150 ModestMsgEditWindow *self)
1152 gint new_height, new_width;
1155 new_height = height;
1159 if (width > IMAGE_MAX_WIDTH) {
1160 new_height = height * IMAGE_MAX_WIDTH / width;
1161 new_width = IMAGE_MAX_WIDTH;
1164 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1168 pixbuf_from_stream (TnyStream *stream,
1169 const gchar *mime_type,
1170 guint64 *stream_size,
1171 ModestMsgEditWindow *self)
1173 GdkPixbufLoader *loader;
1176 GError *error = NULL;
1180 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1182 if (loader == NULL) {
1187 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1189 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1191 tny_stream_reset (TNY_STREAM (stream));
1192 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1193 unsigned char read_buffer[128];
1195 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1197 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1200 /* Allow some UI responsiveness */
1201 while (gtk_events_pending ())
1202 gtk_main_iteration ();
1204 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1206 gdk_pixbuf_loader_close (loader, &error);
1209 g_error_free (error);
1210 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1212 g_object_ref (pixbuf);
1213 g_object_unref (loader);
1218 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1219 GdkPixbuf *new_pixbuf;
1221 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1222 gdk_pixbuf_get_width (pixbuf);
1223 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1224 g_object_unref (pixbuf);
1225 pixbuf = new_pixbuf;
1229 *stream_size = size;
1235 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1237 ModestMsgEditWindowPrivate *priv;
1240 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1242 g_object_ref (self);
1243 for (iter = tny_list_create_iterator (attachments);
1244 !tny_iterator_is_done (iter);
1245 tny_iterator_next (iter)) {
1246 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1247 const gchar *cid = tny_mime_part_get_content_id (part);
1248 const gchar *mime_type = tny_mime_part_get_content_type (part);
1249 if ((cid != NULL)&&(mime_type != NULL)) {
1250 guint64 stream_size;
1251 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1252 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1255 g_object_unref (stream);
1257 if (pixbuf != NULL) {
1258 priv->images_count ++;
1259 priv->images_size += stream_size;
1260 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1261 g_object_unref (pixbuf);
1264 g_object_unref (part);
1266 g_object_unref (iter);
1267 g_object_unref (self);
1271 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1273 TnyMimePart *parent = NULL;
1274 const gchar *content_type = NULL;
1275 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1277 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1279 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1280 parent = g_object_ref (msg);
1281 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1282 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1285 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1286 iter = tny_list_create_iterator (parts);
1287 while (!tny_iterator_is_done (iter)) {
1289 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1290 content_type = tny_mime_part_get_content_type (part);
1291 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1295 g_object_unref (part);
1297 tny_iterator_next (iter);
1299 g_object_unref (iter);
1300 g_object_unref (parts);
1303 if (parent != NULL) {
1304 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1307 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1308 iter = tny_list_create_iterator (parts);
1309 while (!tny_iterator_is_done (iter)) {
1311 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1312 content_type = tny_mime_part_get_content_type (part);
1313 if (content_type && g_str_has_prefix (content_type, "image/")) {
1314 tny_list_prepend (priv->images, (GObject *) part);
1316 g_object_unref (part);
1317 tny_iterator_next (iter);
1319 g_object_unref (iter);
1320 g_object_unref (parts);
1321 g_object_unref (parent);
1326 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1329 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1331 for (iter = tny_list_create_iterator (attachments) ;
1332 !tny_iterator_is_done (iter);
1333 tny_iterator_next (iter)) {
1334 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1335 const gchar *cid = tny_mime_part_get_content_id (part);
1337 char *invalid = NULL;
1338 gint int_cid = strtol (cid, &invalid, 10);
1339 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1340 priv->next_cid = int_cid + 1;
1343 g_object_unref (part);
1345 g_object_unref (iter);
1349 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1352 gchar *to, *cc, *bcc, *subject;
1354 ModestMsgEditWindowPrivate *priv;
1355 ModestWindowPrivate *parent_priv;
1357 TnyHeaderFlags priority_flags;
1358 TnyFolder *msg_folder;
1359 gboolean is_html = FALSE;
1360 gboolean field_view_set;
1362 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1363 g_return_if_fail (TNY_IS_MSG (msg));
1365 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1366 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1368 header = tny_msg_get_header (msg);
1369 to = tny_header_dup_to (header);
1370 cc = tny_header_dup_cc (header);
1371 bcc = tny_header_dup_bcc (header);
1372 subject = tny_header_dup_subject (header);
1374 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1375 priority_flags = tny_header_get_priority (header);
1378 gchar *quoted_names = modest_text_utils_quote_names (to);
1379 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1380 g_free (quoted_names);
1383 field_view_set = TRUE;
1385 gchar *quoted_names = modest_text_utils_quote_names (cc);
1386 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1387 g_free (quoted_names);
1388 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1389 gtk_widget_show (priv->cc_caption);
1390 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1391 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1392 gtk_widget_hide (priv->cc_caption);
1393 field_view_set = FALSE;
1395 modest_togglable_set_active (priv->cc_button, field_view_set);
1397 field_view_set = TRUE;
1399 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1400 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1401 g_free (quoted_names);
1402 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1403 gtk_widget_show (priv->bcc_caption);
1404 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1405 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1406 gtk_widget_hide (priv->bcc_caption);
1407 field_view_set = FALSE;
1409 modest_togglable_set_active (priv->bcc_button, field_view_set);
1413 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1414 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1417 update_window_title (self);
1419 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1420 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1422 if ((body == NULL)||(body[0] == '\0')) {
1424 body = modest_text_utils_convert_to_html ("");
1427 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1428 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1431 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1434 /* Add attachments to the view */
1435 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1436 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1437 if (tny_list_get_length (priv->attachments) == 0) {
1438 gtk_widget_hide (priv->attachments_caption);
1440 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1441 gtk_widget_show_all (priv->attachments_caption);
1443 get_related_images (self, msg);
1444 update_next_cid (self, priv->attachments);
1445 update_next_cid (self, priv->images);
1446 replace_with_images (self, priv->images);
1448 if (preserve_is_rich && !is_html) {
1449 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1450 /* Get the default format required from configuration */
1451 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1452 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1455 /* Set the default focus depending on having already a To: field or not */
1456 if ((!to)||(*to == '\0')) {
1457 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1459 gtk_widget_grab_focus (priv->msg_body);
1462 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1464 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1465 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1467 modest_msg_edit_window_set_modified (self, FALSE);
1469 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1470 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1471 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1472 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1474 if (priv->msg_uid) {
1475 g_free (priv->msg_uid);
1476 priv->msg_uid = NULL;
1479 /* we should set a reference to the incoming message if it is a draft */
1480 msg_folder = tny_msg_get_folder (msg);
1482 if (modest_tny_folder_is_local_folder (msg_folder)) {
1483 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1484 if (type == TNY_FOLDER_TYPE_INVALID)
1485 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1487 if (type == TNY_FOLDER_TYPE_DRAFTS)
1488 priv->draft_msg = g_object_ref(msg);
1489 if (type == TNY_FOLDER_TYPE_OUTBOX)
1490 priv->outbox_msg = g_object_ref(msg);
1491 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1493 g_object_unref (msg_folder);
1503 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1505 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1506 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1507 GtkWidget *placeholder;
1508 GtkWidget *tool_item;
1513 GtkWidget *sizes_menu;
1514 GtkWidget *fonts_menu;
1520 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1521 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1522 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1523 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1525 /* Font color placeholder */
1526 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1527 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1530 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1531 priv->font_color_button = modest_color_button_new ();
1532 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1533 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1534 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1535 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1536 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1537 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1538 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1539 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1541 G_CALLBACK (modest_msg_edit_window_color_button_change),
1544 /* Font size and face placeholder */
1545 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1546 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1548 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1549 priv->size_tool_button_label = gtk_label_new (NULL);
1550 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1551 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1552 size_text, "</span>", NULL);
1553 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1554 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1556 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1557 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1558 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1559 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1560 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1561 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1562 gtk_widget_set_sensitive (arrow, FALSE);
1563 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1564 sizes_menu = gtk_menu_new ();
1565 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1566 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1569 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1570 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1572 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1576 if (wp_font_size[size_index] == 12)
1577 priv->current_size_index = size_index;
1581 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1582 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1583 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1584 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1585 priv->font_size_toolitem = tool_item;
1588 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1589 priv->font_tool_button_label = gtk_label_new (NULL);
1590 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1591 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1592 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1594 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1595 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1596 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1597 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1598 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1599 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1600 gtk_widget_set_sensitive (arrow, FALSE);
1601 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1602 fonts_menu = gtk_menu_new ();
1603 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1604 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1607 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1609 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1610 0, wp_get_font_name (font_index),
1613 if (font_index == DEFAULT_FONT)
1614 priv->current_face_index = font_index;
1616 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1617 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1618 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1619 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1620 priv->font_face_toolitem = tool_item;
1622 /* Set expand and homogeneous for remaining items */
1623 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1624 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1625 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1626 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1627 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1628 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1630 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1631 will not show the tool items added to the placeholders) */
1632 gtk_widget_show_all (parent_priv->toolbar);
1634 /* Set the no show all *after* showing all items. We do not
1635 want the toolbar to be shown with a show all because it
1636 could go agains the gconf setting regarding showing or not
1637 the toolbar of the editor window */
1638 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1644 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1647 ModestWindowPrivate *parent_priv;
1648 ModestMsgEditWindowPrivate *priv;
1649 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1650 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1651 ModestWindowMgr *mgr = NULL;
1653 g_return_val_if_fail (msg, NULL);
1654 g_return_val_if_fail (account_name, NULL);
1656 mgr = modest_runtime_get_window_mgr ();
1658 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1660 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1661 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1663 /* Menubar. Update the state of some toggles */
1664 priv->from_field_protos = get_transports ();
1665 priv->original_mailbox = NULL;
1666 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1667 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1668 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1669 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1670 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1671 priv->original_mailbox = g_strdup (mailbox);
1672 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1673 /* We set the first mailbox as the active mailbox */
1674 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1675 if (priv->original_mailbox != NULL)
1676 modest_selector_set_active_id (priv->from_field,
1677 (gpointer) priv->original_mailbox);
1679 modest_selector_set_active_id (priv->from_field,
1680 (gpointer) account_name);
1682 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1684 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1685 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1686 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1687 #ifdef HILDON_TOOLKIT_HILDON2
1688 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1690 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1691 hildon_touch_selector_get_current_text
1692 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1695 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1696 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1699 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1701 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1703 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1704 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1706 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1708 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1709 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1710 /* Add common dimming rules */
1711 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1712 modest_msg_edit_window_toolbar_dimming_entries,
1713 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1714 MODEST_WINDOW (obj));
1715 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1716 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1717 MODEST_WINDOW (obj));
1718 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1719 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1720 MODEST_WINDOW (obj));
1721 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1722 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1723 MODEST_WINDOW (obj));
1724 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1725 G_CALLBACK (modest_ui_dimming_rules_on_send),
1726 MODEST_WINDOW (obj));
1727 /* Insert dimming rules group for this window */
1728 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1729 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1731 /* Setup app menu */
1732 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1734 /* Checks the dimming rules */
1735 g_object_unref (toolbar_rules_group);
1736 g_object_unref (clipboard_rules_group);
1737 gtk_widget_hide (priv->priority_icon);
1738 gtk_widget_queue_resize (priv->subject_box);
1739 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1741 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1743 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1744 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1745 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1746 priv->update_caption_visibility = TRUE;
1748 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1750 /* Track account-removed signal, this window should be closed
1751 in the case we're creating a mail associated to the account
1753 priv->account_removed_handler_id =
1754 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1756 G_CALLBACK(on_account_removed),
1759 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1761 return (ModestWindow*) obj;
1765 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1767 GString **string_buffer = (GString **) user_data;
1769 *string_buffer = g_string_append (*string_buffer, buffer);
1775 * @result: A new string which should be freed with g_free().
1778 get_formatted_data (ModestMsgEditWindow *edit_window)
1780 ModestMsgEditWindowPrivate *priv;
1781 GString *string_buffer = g_string_new ("");
1783 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1785 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1787 modest_text_utils_hyperlinkify (string_buffer);
1789 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1791 return g_string_free (string_buffer, FALSE);
1796 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1799 const gchar *account_name;
1800 ModestMsgEditWindowPrivate *priv;
1801 TnyIterator *att_iter;
1802 const gchar *picker_active_id;
1804 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1806 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1808 picker_active_id = modest_selector_get_active_id (priv->from_field);
1809 g_return_val_if_fail (picker_active_id, NULL);
1810 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1812 /* don't free these (except from) */
1813 data = g_slice_new0 (MsgData);
1814 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1815 data->account_name = g_strdup (account_name);
1816 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1817 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1818 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1819 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1820 data->references = g_strdup (priv->references);
1821 data->in_reply_to = g_strdup (priv->in_reply_to);
1822 if (priv->draft_msg) {
1823 data->draft_msg = g_object_ref (priv->draft_msg);
1824 } else if (priv->outbox_msg) {
1825 data->draft_msg = g_object_ref (priv->outbox_msg);
1827 data->draft_msg = NULL;
1830 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1832 gtk_text_buffer_get_bounds (buf, &b, &e);
1833 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1835 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1836 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1838 data->html_body = NULL;
1840 /* deep-copy the data */
1841 att_iter = tny_list_create_iterator (priv->attachments);
1842 data->attachments = NULL;
1843 while (!tny_iterator_is_done (att_iter)) {
1844 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1845 if (!(TNY_IS_MIME_PART(part))) {
1846 g_warning ("strange data in attachment list");
1847 g_object_unref (part);
1848 tny_iterator_next (att_iter);
1851 data->attachments = g_list_append (data->attachments,
1853 tny_iterator_next (att_iter);
1855 g_object_unref (att_iter);
1857 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1858 att_iter = tny_list_create_iterator (priv->images);
1859 data->images = NULL;
1860 while (!tny_iterator_is_done (att_iter)) {
1861 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1863 if (!(TNY_IS_MIME_PART(part))) {
1864 g_warning ("strange data in attachment list");
1865 g_object_unref (part);
1866 tny_iterator_next (att_iter);
1869 cid = tny_mime_part_get_content_id (part);
1871 gchar *image_tag_id;
1872 GtkTextTag *image_tag;
1874 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1875 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1876 g_free (image_tag_id);
1878 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1880 ((gtk_text_iter_has_tag (&iter, image_tag))||
1881 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1882 data->images = g_list_append (data->images,
1883 g_object_ref (part));
1885 g_object_unref (part);
1886 tny_iterator_next (att_iter);
1888 g_object_unref (att_iter);
1890 data->priority_flags = priv->priority_flags;
1897 unref_gobject (GObject *obj, gpointer data)
1899 if (!G_IS_OBJECT(obj))
1901 g_object_unref (obj);
1905 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1908 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1916 g_free (data->from);
1917 g_free (data->subject);
1918 g_free (data->plain_body);
1919 g_free (data->html_body);
1920 g_free (data->account_name);
1921 g_free (data->references);
1922 g_free (data->in_reply_to);
1924 if (data->draft_msg != NULL) {
1925 g_object_unref (data->draft_msg);
1926 data->draft_msg = NULL;
1929 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1930 g_list_free (data->attachments);
1931 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1932 g_list_free (data->images);
1934 g_slice_free (MsgData, data);
1938 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1940 guint64 *parts_size)
1942 ModestMsgEditWindowPrivate *priv;
1944 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1946 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1948 /* TODO: add images */
1949 *parts_size += priv->images_size;
1950 *parts_count += priv->images_count;
1955 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1958 ModestMsgEditWindowPrivate *priv = NULL;
1959 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1961 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1963 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1965 return MODEST_MSG_EDIT_FORMAT_HTML;
1967 return MODEST_MSG_EDIT_FORMAT_TEXT;
1971 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1972 ModestMsgEditFormat format)
1974 ModestMsgEditWindowPrivate *priv;
1975 ModestWindowPrivate *parent_priv;
1977 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1978 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1979 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1982 case MODEST_MSG_EDIT_FORMAT_HTML:
1983 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1984 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
1986 case MODEST_MSG_EDIT_FORMAT_TEXT:
1987 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1988 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
1991 g_return_if_reached ();
1995 ModestMsgEditFormatState *
1996 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1998 ModestMsgEditFormatState *format_state = NULL;
1999 ModestMsgEditWindowPrivate *priv;
2000 WPTextBufferFormat *buffer_format;
2002 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2004 buffer_format = g_new0 (WPTextBufferFormat, 1);
2005 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2007 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2009 format_state = g_new0 (ModestMsgEditFormatState, 1);
2010 format_state->bold = buffer_format->bold&0x1;
2011 format_state->italics = buffer_format->italic&0x1;
2012 format_state->bullet = buffer_format->bullet&0x1;
2013 format_state->color = buffer_format->color;
2014 format_state->font_size = buffer_format->font_size;
2015 format_state->font_family = wp_get_font_name (buffer_format->font);
2016 format_state->justification = buffer_format->justification;
2017 g_free (buffer_format);
2019 return format_state;
2024 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2025 const ModestMsgEditFormatState *format_state)
2027 ModestMsgEditWindowPrivate *priv;
2028 WPTextBufferFormat *buffer_format;
2029 WPTextBufferFormat *current_format;
2031 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2032 g_return_if_fail (format_state != NULL);
2034 buffer_format = g_new0 (WPTextBufferFormat, 1);
2035 current_format = g_new0 (WPTextBufferFormat, 1);
2037 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2038 gtk_widget_grab_focus (priv->msg_body);
2039 buffer_format->bold = (format_state->bold != FALSE);
2040 buffer_format->italic = (format_state->italics != FALSE);
2041 buffer_format->color = format_state->color;
2042 buffer_format->font_size = format_state->font_size;
2043 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2044 buffer_format->justification = format_state->justification;
2045 buffer_format->bullet = format_state->bullet;
2047 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2049 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2050 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2051 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2052 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2053 buffer_format->cs.font = (buffer_format->font != current_format->font);
2054 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2055 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2057 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2058 if (buffer_format->cs.bold) {
2059 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2060 GINT_TO_POINTER (buffer_format->bold&0x1));
2062 if (buffer_format->cs.italic) {
2063 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2064 GINT_TO_POINTER (buffer_format->italic&0x1));
2066 if (buffer_format->cs.color) {
2067 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2068 GINT_TO_POINTER (&(buffer_format->color)));
2070 if (buffer_format->cs.font_size) {
2071 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2072 GINT_TO_POINTER (buffer_format->font_size));
2074 if (buffer_format->cs.justification) {
2075 switch (buffer_format->justification) {
2076 case GTK_JUSTIFY_LEFT:
2077 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2078 GINT_TO_POINTER(TRUE));
2080 case GTK_JUSTIFY_CENTER:
2081 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2082 GINT_TO_POINTER(TRUE));
2084 case GTK_JUSTIFY_RIGHT:
2085 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2086 GINT_TO_POINTER(TRUE));
2093 if (buffer_format->cs.font) {
2094 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2095 GINT_TO_POINTER (buffer_format->font));
2097 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2098 if (buffer_format->cs.bullet) {
2099 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2100 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2102 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2104 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2106 g_free (buffer_format);
2107 g_free (current_format);
2109 /* Check dimming rules */
2110 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2111 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2115 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2117 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2119 ModestWindowPrivate *parent_priv;
2120 ModestMsgEditWindowPrivate *priv;
2122 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2123 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2125 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2126 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2127 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2128 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2130 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2131 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2132 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2135 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2137 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2138 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2140 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2141 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2143 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2144 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2147 switch (buffer_format->justification)
2149 case GTK_JUSTIFY_LEFT:
2150 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2152 case GTK_JUSTIFY_CENTER:
2153 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2155 case GTK_JUSTIFY_RIGHT:
2156 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2163 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2165 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2166 G_CALLBACK (modest_msg_edit_window_color_button_change),
2168 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2169 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2170 G_CALLBACK (modest_msg_edit_window_color_button_change),
2173 if (priv->current_size_index != buffer_format->font_size) {
2177 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2178 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2182 priv->current_size_index = buffer_format->font_size;
2184 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2185 markup = g_strconcat ("<span font_family='Sans'>",
2186 size_text, "</span>", NULL);
2188 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2192 gtk_tree_path_free (path);
2195 if (priv->current_face_index != buffer_format->font) {
2199 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2200 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2204 priv->current_face_index = buffer_format->font;
2205 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2206 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2207 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2214 g_free (buffer_format);
2220 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2222 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2223 ModestMsgEditWindowPrivate *priv;
2224 GtkWidget *dialog = NULL;
2226 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2227 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2229 dialog = hildon_color_chooser_new ();
2230 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2231 g_free (buffer_format);
2233 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2235 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2236 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2239 gtk_widget_destroy (dialog);
2244 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2246 ModestMsgEditWindowPrivate *priv;
2247 GtkWidget *dialog = NULL;
2248 GdkColor *old_color = NULL;
2250 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2251 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2253 dialog = hildon_color_chooser_new ();
2254 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2256 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2258 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2259 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2261 gtk_widget_destroy (dialog);
2266 create_stream_for_uri (const gchar* uri)
2271 TnyStream *result = NULL;
2273 GnomeVFSHandle *handle = NULL;
2274 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2275 if (test == GNOME_VFS_OK) {
2276 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2277 /* Streams over OBEX (Bluetooth) are not seekable but
2278 * we expect them to be (we might need to read them
2279 * several times). So if this is a Bluetooth URI just
2280 * read the whole file into memory (this is not a fast
2281 * protocol so we can assume that these files are not
2282 * going to be very big) */
2283 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2284 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2285 TnyStream *memstream = tny_camel_mem_stream_new ();
2286 tny_stream_write_to_stream (vfssstream, memstream);
2287 g_object_unref (vfssstream);
2290 result = vfssstream;
2298 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2301 ModestMsgEditWindowPrivate *priv;
2302 GtkWidget *dialog = NULL;
2304 GSList *uris = NULL;
2305 GSList *uri_node = NULL;
2307 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2309 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2310 _("mcen_ia_select_inline_image_title"),
2311 (GtkWindow *) window,
2312 GTK_FILE_CHOOSER_ACTION_OPEN);
2313 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2315 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2317 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2318 GTK_WINDOW (dialog), GTK_WINDOW (window));
2320 response = gtk_dialog_run (GTK_DIALOG (dialog));
2322 case GTK_RESPONSE_OK:
2324 gchar *current_folder;
2325 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2326 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2327 if (current_folder && current_folder != '\0') {
2329 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2330 current_folder, &err);
2332 g_debug ("Error storing latest used folder: %s", err->message);
2336 g_free (current_folder);
2342 gtk_widget_destroy (dialog);
2344 g_object_ref (window);
2345 /* The operation could take some time so allow the dialog to be closed */
2346 while (gtk_events_pending ())
2347 gtk_main_iteration ();
2349 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2351 GnomeVFSHandle *handle = NULL;
2352 GnomeVFSResult result;
2353 GtkTextIter position;
2354 GtkTextMark *insert_mark;
2356 uri = (const gchar *) uri_node->data;
2357 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2358 if (result == GNOME_VFS_OK) {
2360 GnomeVFSFileInfo *info;
2361 gchar *filename, *basename, *escaped_filename;
2362 TnyMimePart *mime_part;
2364 const gchar *mime_type = NULL;
2365 GnomeVFSURI *vfs_uri;
2366 guint64 stream_size;
2368 gnome_vfs_close (handle);
2369 vfs_uri = gnome_vfs_uri_new (uri);
2371 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2372 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2373 g_free (escaped_filename);
2374 gnome_vfs_uri_unref (vfs_uri);
2375 info = gnome_vfs_file_info_new ();
2377 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2378 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2380 mime_type = gnome_vfs_file_info_get_mime_type (info);
2382 mime_part = tny_platform_factory_new_mime_part
2383 (modest_runtime_get_platform_factory ());
2385 TnyStream *stream = create_stream_for_uri (uri);
2387 if (stream == NULL) {
2389 modest_platform_information_banner (NULL, NULL,
2390 _FM("sfil_ib_opening_not_allowed"));
2392 g_object_unref (mime_part);
2393 gnome_vfs_file_info_unref (info);
2397 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2399 content_id = g_strdup_printf ("%d", priv->next_cid);
2400 tny_mime_part_set_content_id (mime_part, content_id);
2401 g_free (content_id);
2404 basename = g_path_get_basename (filename);
2405 tny_mime_part_set_filename (mime_part, basename);
2408 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2410 if (pixbuf != NULL) {
2411 priv->images_size += stream_size;
2412 priv->images_count ++;
2413 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2414 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2415 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2416 tny_mime_part_get_content_id (mime_part), pixbuf);
2417 g_object_unref (pixbuf);
2419 tny_list_prepend (priv->images, (GObject *) mime_part);
2420 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2422 modest_platform_information_banner (NULL, NULL,
2423 _("mail_ib_file_operation_failed"));
2427 g_object_unref (mime_part);
2428 gnome_vfs_file_info_unref (info);
2432 g_object_unref (window);
2436 on_attach_file_response (GtkDialog *dialog,
2440 GSList *uris = NULL;
2442 GnomeVFSFileSize total_size, allowed_size;
2443 ModestMsgEditWindow *window;
2444 ModestMsgEditWindowPrivate *priv;
2449 case GTK_RESPONSE_OK:
2451 gchar *current_folder;
2453 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2454 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2455 if (current_folder && current_folder != '\0') {
2457 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2458 current_folder, &err);
2460 g_debug ("Error storing latest used folder: %s", err->message);
2464 g_free (current_folder);
2471 window = MODEST_MSG_EDIT_WINDOW (user_data);
2472 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2474 /* allowed size is the maximum size - what's already there */
2475 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2476 &att_num, &att_size);
2477 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2480 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2482 const gchar *uri = (const gchar *) uri_node->data;
2485 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2487 if (total_size > allowed_size) {
2488 g_debug ("%s: total size: %u",
2489 __FUNCTION__, (unsigned int)total_size);
2492 allowed_size -= total_size;
2494 g_slist_foreach (uris, (GFunc) g_free, NULL);
2495 g_slist_free (uris);
2497 gtk_widget_destroy (GTK_WIDGET (dialog));
2501 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2503 GtkWidget *dialog = NULL;
2504 ModestMsgEditWindowPrivate *priv;
2507 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2509 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2511 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2514 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2515 _("mcen_ia_select_attachment_title"),
2516 (GtkWindow *) window,
2517 GTK_FILE_CHOOSER_ACTION_OPEN);
2518 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2519 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2520 if (conf_folder && conf_folder[0] != '\0') {
2521 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2524 /* Set the default folder to documents folder */
2525 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2528 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2529 ".documents", NULL);
2531 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2532 g_free (docs_folder);
2534 g_free (conf_folder);
2535 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2536 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2537 GTK_WINDOW (dialog), GTK_WINDOW (window));
2539 /* Connect to response & show */
2540 g_signal_connect (dialog, "response",
2541 G_CALLBACK (on_attach_file_response), window);
2542 gtk_widget_show (dialog);
2547 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2549 GnomeVFSFileSize allowed_size)
2552 GnomeVFSHandle *handle = NULL;
2553 ModestMsgEditWindowPrivate *priv;
2554 GnomeVFSResult result;
2555 GnomeVFSFileSize size = 0;
2556 g_return_val_if_fail (window, 0);
2557 g_return_val_if_fail (uri, 0);
2559 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2561 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2562 if (result == GNOME_VFS_OK) {
2563 TnyMimePart *mime_part;
2565 const gchar *mime_type = NULL;
2567 gchar *escaped_filename;
2570 GnomeVFSFileInfo *info;
2571 GnomeVFSURI *vfs_uri;
2573 gnome_vfs_close (handle);
2574 vfs_uri = gnome_vfs_uri_new (uri);
2577 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2578 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2579 g_free (escaped_filename);
2580 gnome_vfs_uri_unref (vfs_uri);
2582 info = gnome_vfs_file_info_new ();
2584 if (gnome_vfs_get_file_info (uri,
2586 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2588 mime_type = gnome_vfs_file_info_get_mime_type (info);
2589 mime_part = tny_platform_factory_new_mime_part
2590 (modest_runtime_get_platform_factory ());
2592 /* try to get the attachment's size; this may fail for weird
2593 * file systems, like obex, upnp... */
2594 if (allowed_size != 0 &&
2595 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2597 if (size > allowed_size) {
2598 modest_platform_information_banner (NULL, NULL,
2599 _("mail_ib_error_attachment_size"));
2604 g_debug ("%s: could not get attachment size", __FUNCTION__);
2606 stream = create_stream_for_uri (uri);
2608 if (stream == NULL) {
2610 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2612 g_object_unref (mime_part);
2614 gnome_vfs_file_info_unref (info);
2618 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2619 g_object_unref (stream);
2621 content_id = g_strdup_printf ("%d", priv->next_cid);
2622 tny_mime_part_set_content_id (mime_part, content_id);
2623 g_free (content_id);
2626 basename = g_path_get_basename (filename);
2627 tny_mime_part_set_filename (mime_part, basename);
2630 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2631 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2633 info->size == 0, info->size);
2634 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2635 gtk_widget_show_all (priv->attachments_caption);
2636 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2638 g_object_unref (mime_part);
2639 gnome_vfs_file_info_unref (info);
2646 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2649 ModestMsgEditWindowPrivate *priv;
2652 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2653 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2655 if (att_list == NULL) {
2656 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2657 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2658 g_object_unref (att_list);
2662 g_object_ref (att_list);
2665 if (tny_list_get_length (att_list) == 0) {
2666 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2668 gboolean dialog_response;
2669 gchar *message = NULL;
2670 gchar *filename = NULL;
2672 if (tny_list_get_length (att_list) == 1) {
2674 iter = tny_list_create_iterator (att_list);
2675 part = (TnyMimePart *) tny_iterator_get_current (iter);
2676 g_object_unref (iter);
2677 if (TNY_IS_MSG (part)) {
2678 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2680 filename = tny_header_dup_subject (header);
2681 g_object_unref (header);
2683 if (filename == NULL) {
2684 filename = g_strdup (_("mail_va_no_subject"));
2687 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2689 g_object_unref (part);
2691 filename = g_strdup ("");
2693 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2694 "emev_nc_delete_attachments",
2695 tny_list_get_length (att_list)), filename);
2698 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2702 if (dialog_response != GTK_RESPONSE_OK) {
2703 g_object_unref (att_list);
2707 for (iter = tny_list_create_iterator (att_list);
2708 !tny_iterator_is_done (iter);
2709 tny_iterator_next (iter)) {
2710 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2711 const gchar *att_id;
2712 tny_list_remove (priv->attachments, (GObject *) mime_part);
2714 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2716 if (tny_list_get_length (priv->attachments) == 0)
2717 gtk_widget_hide (priv->attachments_caption);
2718 att_id = tny_mime_part_get_content_id (mime_part);
2720 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2722 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2723 g_object_unref (mime_part);
2725 g_object_unref (iter);
2728 g_object_unref (att_list);
2730 /* if the last attachment has been removed, focus the Subject: field */
2731 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2732 gtk_widget_grab_focus (priv->subject_field);
2736 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2739 ModestMsgEditWindowPrivate *priv;
2742 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2744 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2746 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2748 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2752 font_size_clicked (GtkToolButton *button,
2753 ModestMsgEditWindow *window)
2755 ModestMsgEditWindowPrivate *priv;
2756 GtkWidget *selector, *dialog;
2758 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2760 selector = hildon_touch_selector_new ();
2761 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2762 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2764 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2765 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2766 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2768 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2772 WPTextBufferFormat format;
2774 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2776 memset (&format, 0, sizeof (format));
2777 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2779 format.cs.font_size = TRUE;
2780 format.cs.text_position = TRUE;
2781 format.cs.font = TRUE;
2782 format.font_size = new_index;
2783 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2785 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2786 GINT_TO_POINTER (new_index)))
2787 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2789 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2790 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2791 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2792 size_text, "</span>", NULL);
2794 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2798 gtk_widget_destroy (dialog);
2800 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2805 font_face_clicked (GtkToolButton *button,
2806 ModestMsgEditWindow *window)
2808 ModestMsgEditWindowPrivate *priv;
2809 GtkWidget *selector, *dialog;
2810 GtkCellRenderer *renderer;
2812 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2814 selector = hildon_touch_selector_new ();
2815 renderer = gtk_cell_renderer_text_new ();
2816 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2817 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2818 renderer, "family", 0, "text", 0, NULL);
2819 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2821 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2822 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2823 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2825 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2826 gint new_font_index;
2830 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2831 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2832 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2836 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2838 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2839 GINT_TO_POINTER(new_font_index)))
2840 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2842 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2843 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2845 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2849 gtk_tree_path_free (path);
2852 gtk_widget_destroy (dialog);
2854 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2859 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2862 ModestMsgEditWindowPrivate *priv = NULL;
2863 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2865 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2866 if (!priv->update_caption_visibility)
2869 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2871 gtk_widget_show (priv->cc_caption);
2873 gtk_widget_hide (priv->cc_caption);
2875 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2879 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2882 ModestMsgEditWindowPrivate *priv = NULL;
2883 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2885 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2886 if (!priv->update_caption_visibility)
2889 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2891 gtk_widget_show (priv->bcc_caption);
2893 gtk_widget_hide (priv->bcc_caption);
2895 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2899 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2900 ModestRecptEditor *editor)
2902 ModestMsgEditWindowPrivate *priv;
2904 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2905 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2907 /* we check for low-mem; in that case, show a warning, and don't allow
2908 * for the addressbook
2910 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2913 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2915 if (editor == NULL) {
2916 GtkWidget *view_focus, *parent;
2917 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2919 /* This code should be kept in sync with ModestRecptEditor. The
2920 textview inside the recpt editor is the one that really gets the
2921 focus. As it's inside a scrolled window, and this one inside the
2922 hbox recpt editor inherits from, we'll need to go up in the
2923 hierarchy to know if the text view is part of the recpt editor
2924 or if it's a different text entry */
2925 parent = gtk_widget_get_parent (view_focus);
2926 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2927 editor = MODEST_RECPT_EDITOR (parent);
2930 editor = MODEST_RECPT_EDITOR (priv->to_field);
2933 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2937 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2939 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2941 modest_msg_edit_window_open_addressbook (window, NULL);
2945 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2946 gboolean show_toolbar)
2948 ModestWindowPrivate *parent_priv;
2949 ModestMsgEditWindowPrivate *priv;
2951 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2952 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2953 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2955 /* We can not just use the code of
2956 modest_msg_edit_window_setup_toolbar because it has a
2957 mixture of both initialization and creation code. */
2959 gint current_format;
2960 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2961 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2962 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2963 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2965 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2968 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2973 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2974 TnyHeaderFlags priority_flags)
2976 ModestMsgEditWindowPrivate *priv;
2977 ModestWindowPrivate *parent_priv;
2979 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2981 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2982 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2984 if (priv->priority_flags != priority_flags) {
2985 GtkAction *priority_action = NULL;
2987 priv->priority_flags = priority_flags;
2989 switch (priority_flags) {
2990 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2991 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2992 MODEST_HEADER_ICON_HIGH,
2993 HILDON_ICON_SIZE_SMALL);
2994 gtk_widget_show (priv->priority_icon);
2995 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2996 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2998 case TNY_HEADER_FLAG_LOW_PRIORITY:
2999 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3000 MODEST_HEADER_ICON_LOW,
3001 HILDON_ICON_SIZE_SMALL);
3002 gtk_widget_show (priv->priority_icon);
3003 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3004 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3007 gtk_widget_hide (priv->priority_icon);
3008 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3009 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3012 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3013 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3015 gtk_widget_queue_resize (priv->subject_box);
3019 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3022 ModestMsgEditWindowPrivate *priv;
3023 ModestWindowPrivate *parent_priv;
3024 gint current_format;
3026 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3028 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3029 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3031 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3032 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3034 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3036 if (current_format != file_format) {
3037 switch (file_format) {
3038 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3039 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3040 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3041 if (parent_priv->toolbar)
3042 gtk_widget_show (parent_priv->toolbar);
3044 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3048 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3049 response = gtk_dialog_run (GTK_DIALOG (dialog));
3050 gtk_widget_destroy (dialog);
3051 if (response == GTK_RESPONSE_OK) {
3052 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3053 if (parent_priv->toolbar)
3054 gtk_widget_hide (parent_priv->toolbar);
3056 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3057 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3062 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3063 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3064 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3069 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3072 ModestMsgEditWindowPrivate *priv;
3073 WPTextBufferFormat oldfmt, fmt;
3074 gint old_position = 0;
3078 GdkColor *color = NULL;
3079 gboolean bold, bold_set, italic, italic_set;
3080 gboolean underline, underline_set;
3081 gboolean strikethrough, strikethrough_set;
3082 gboolean position_set;
3083 gboolean font_size_set, font_set, color_set;
3086 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3087 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3089 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3090 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3091 GTK_WINDOW(dialog), GTK_WINDOW (window));
3093 /* First we get the currently selected font information */
3094 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3096 switch (oldfmt.text_position) {
3097 case TEXT_POSITION_NORMAL:
3100 case TEXT_POSITION_SUPERSCRIPT:
3108 g_object_set (G_OBJECT (dialog),
3109 "bold", oldfmt.bold != FALSE,
3110 "bold-set", !oldfmt.cs.bold,
3111 "underline", oldfmt.underline != FALSE,
3112 "underline-set", !oldfmt.cs.underline,
3113 "italic", oldfmt.italic != FALSE,
3114 "italic-set", !oldfmt.cs.italic,
3115 "strikethrough", oldfmt.strikethrough != FALSE,
3116 "strikethrough-set", !oldfmt.cs.strikethrough,
3117 "color", &oldfmt.color,
3118 "color-set", !oldfmt.cs.color,
3119 "size", wp_font_size[oldfmt.font_size],
3120 "size-set", !oldfmt.cs.font_size,
3121 "position", old_position,
3122 "position-set", !oldfmt.cs.text_position,
3123 "family", wp_get_font_name (oldfmt.font),
3124 "family-set", !oldfmt.cs.font,
3127 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3128 GTK_WINDOW (dialog), GTK_WINDOW (window));
3129 gtk_widget_show_all (dialog);
3130 priv->font_dialog = dialog;
3131 response = gtk_dialog_run (GTK_DIALOG (dialog));
3132 priv->font_dialog = NULL;
3133 if (response == GTK_RESPONSE_OK) {
3135 g_object_get( dialog,
3137 "bold-set", &bold_set,
3138 "underline", &underline,
3139 "underline-set", &underline_set,
3141 "italic-set", &italic_set,
3142 "strikethrough", &strikethrough,
3143 "strikethrough-set", &strikethrough_set,
3145 "color-set", &color_set,
3147 "size-set", &font_size_set,
3148 "family", &font_name,
3149 "family-set", &font_set,
3150 "position", &position,
3151 "position-set", &position_set,
3156 if (response == GTK_RESPONSE_OK) {
3157 memset(&fmt, 0, sizeof(fmt));
3163 fmt.italic = italic;
3164 fmt.cs.italic = TRUE;
3166 if (underline_set) {
3167 fmt.underline = underline;
3168 fmt.cs.underline = TRUE;
3170 if (strikethrough_set) {
3171 fmt.strikethrough = strikethrough;
3172 fmt.cs.strikethrough = TRUE;
3177 ? TEXT_POSITION_NORMAL
3178 : ( ( position == 1 )
3179 ? TEXT_POSITION_SUPERSCRIPT
3180 : TEXT_POSITION_SUBSCRIPT );
3181 fmt.cs.text_position = TRUE;
3182 fmt.font_size = oldfmt.font_size;
3186 fmt.cs.color = TRUE;
3189 fmt.font = wp_get_font_index(font_name,
3194 if (font_size_set) {
3195 fmt.cs.font_size = TRUE;
3196 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3198 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3199 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3201 gtk_widget_destroy (dialog);
3203 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3207 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3209 ModestMsgEditWindowPrivate *priv;
3210 ModestWindowPrivate *parent_priv;
3211 gboolean was_rich_text, is_rich_text;
3213 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3214 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3215 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3217 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3219 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3221 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3223 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3225 gtk_widget_show (parent_priv->toolbar);
3227 gtk_widget_hide (parent_priv->toolbar);
3230 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3231 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3235 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3237 ModestMsgEditWindowPrivate *priv;
3239 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3240 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3242 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3244 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3245 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3250 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3252 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3254 priv->can_undo = can_undo;
3258 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3260 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3262 priv->can_redo = can_redo;
3266 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3268 ModestMsgEditWindowPrivate *priv;
3269 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3270 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3272 return priv->can_undo;
3276 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3278 ModestMsgEditWindowPrivate *priv;
3279 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3280 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3282 return priv->can_redo;
3287 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3290 GtkTextIter match_start, match_end;
3292 if (image_id == NULL)
3295 gtk_text_buffer_get_start_iter (buffer, &iter);
3297 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3298 GSList *tags = gtk_text_iter_get_tags (&match_start);
3300 for (node = tags; node != NULL; node = g_slist_next (node)) {
3301 GtkTextTag *tag = (GtkTextTag *) node->data;
3302 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3303 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3304 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3306 offset = gtk_text_iter_get_offset (&match_start);
3307 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3308 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3312 gtk_text_iter_forward_char (&iter);
3317 message_is_empty (ModestMsgEditWindow *window)
3319 ModestMsgEditWindowPrivate *priv = NULL;
3321 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3322 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3324 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3325 * so we can ignore markup.
3327 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3330 count = gtk_text_buffer_get_char_count (buf);
3336 msg_body_focus (GtkWidget *focus,
3337 GdkEventFocus *event,
3341 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3342 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3343 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3348 recpt_field_changed (GtkTextBuffer *buffer,
3349 ModestMsgEditWindow *editor)
3351 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3352 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3356 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3358 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3359 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3363 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3366 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3367 GtkTextBuffer *buffer;
3369 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3370 gtk_text_buffer_set_modified (buffer, modified);
3371 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3372 gtk_text_buffer_set_modified (buffer, modified);
3373 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3374 gtk_text_buffer_set_modified (buffer, modified);
3375 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3379 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3381 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3382 const char *account_name;
3383 GtkTextBuffer *buffer;
3385 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3386 if (gtk_text_buffer_get_modified (buffer))
3388 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3389 if (gtk_text_buffer_get_modified (buffer))
3391 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3392 if (gtk_text_buffer_get_modified (buffer))
3394 if (gtk_text_buffer_get_modified (priv->text_buffer))
3397 account_name = modest_selector_get_active_id (priv->from_field);
3398 if (priv->original_mailbox) {
3399 if (!account_name || strcmp (account_name, priv->original_mailbox))
3401 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3412 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3414 ModestMsgEditWindowPrivate *priv = NULL;
3415 GSList *address_list = NULL;
3417 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3418 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3420 /* check if there's no recipient added */
3421 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3422 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3423 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3424 /* no recipient contents, then select contacts */
3425 modest_msg_edit_window_open_addressbook (window, NULL);
3430 g_object_ref (window);
3431 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3432 (add_to_addressbook) ? &address_list : NULL)) {
3433 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3434 g_object_unref (window);
3437 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3438 (add_to_addressbook) ? &address_list : NULL)) {
3439 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3440 g_object_unref (window);
3443 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3444 (add_to_addressbook) ? &address_list : NULL)) {
3445 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3446 g_object_unref (window);
3450 /* Add contacts to address book */
3451 if (add_to_addressbook && address_list)
3452 modest_address_book_add_address_list (address_list);
3454 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3455 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3456 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3457 g_object_unref (window);
3464 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3466 GSList *recipients = NULL;
3467 ModestMsgEditWindowPrivate *priv;
3468 gchar *joined, *after_remove, *to, *cc, *bcc;
3470 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3472 /* First of all check names */
3473 if (!modest_msg_edit_window_check_names (self, FALSE))
3476 if (!modest_msg_edit_window_has_pending_addresses (self))
3479 /* Don't add the from obviously */
3480 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3481 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3482 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3484 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3489 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3492 recipients = modest_text_utils_split_addresses_list (after_remove);
3493 g_free (after_remove);
3496 /* Offer the user to add recipients to the address book */
3497 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3498 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3503 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3504 ModestMsgEditWindow *window)
3506 modest_msg_edit_window_offer_attach_file (window);
3510 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3512 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3514 return priv->clipboard_text;
3518 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3520 ModestMsgEditWindow *window)
3522 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3523 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3526 /* It could happen that the window was already closed */
3527 if (!GTK_WIDGET_VISIBLE (window))
3530 g_object_ref (window);
3531 text = gtk_clipboard_wait_for_text (selection_clipboard);
3533 if (priv->clipboard_text != NULL) {
3534 g_free (priv->clipboard_text);
3536 priv->clipboard_text = text;
3538 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3540 g_object_unref (window);
3543 static gboolean clipboard_owner_change_idle (gpointer userdata)
3545 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3546 ModestMsgEditWindowPrivate *priv;
3548 gdk_threads_enter ();
3549 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3550 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3552 priv->clipboard_owner_idle = 0;
3553 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3554 gdk_threads_leave ();
3560 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3562 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3563 if (priv->clipboard_owner_idle == 0) {
3564 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3565 clipboard_owner_change_idle,
3566 g_object_ref (window),
3572 subject_field_move_cursor (GtkEntry *entry,
3573 GtkMovementStep step,
3578 /* It could happen that the window was already closed */
3579 if (!GTK_WIDGET_VISIBLE (window))
3582 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3586 update_window_title (ModestMsgEditWindow *window)
3588 ModestMsgEditWindowPrivate *priv = NULL;
3589 const gchar *subject;
3591 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3592 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3593 if (subject == NULL || subject[0] == '\0')
3594 subject = _("mail_va_new_email");
3596 modest_window_set_title (MODEST_WINDOW (window), subject);
3602 body_insert_text (GtkTextBuffer *buffer,
3603 GtkTextIter *location,
3606 ModestMsgEditWindow *window)
3608 GtkTextIter end_iter;
3615 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3617 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3619 offset = gtk_text_iter_get_offset (&end_iter);
3620 line = gtk_text_iter_get_line (&end_iter);
3624 while (text_offset < text + len) {
3625 if (*text_offset == '\n')
3627 if (text_lines + line >= MAX_BODY_LINES) {
3628 len = text_offset - text;
3634 utf8_len = g_utf8_strlen (text, len);
3636 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3637 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3638 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3643 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3645 /* Prevent endless recursion */
3646 result = g_strndup (text, utf8_end - text);
3647 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3648 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3649 (gpointer) result, (gpointer) (utf8_end - text),
3651 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3655 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3656 if (priv->max_chars_banner == NULL) {
3657 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3658 _CS("ckdg_ib_maximum_characters_reached"));
3659 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3665 subject_field_changed (GtkEditable *editable,
3666 ModestMsgEditWindow *window)
3668 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3669 update_window_title (window);
3670 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3671 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3672 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3675 subject_field_insert_text (GtkEditable *editable,
3677 gint new_text_length,
3679 ModestMsgEditWindow *window)
3681 GString *result = g_string_new ("");
3683 gint result_len = 0;
3684 const gchar *entry_text = NULL;
3687 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3688 old_length = g_utf8_strlen (entry_text, -1);
3690 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3691 gunichar c = g_utf8_get_char_validated (current, 8);
3692 /* Invalid unichar, stop */
3698 result = g_string_append_unichar (result, c);
3702 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3703 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3706 /* Prevent endless recursion */
3707 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3708 g_signal_emit_by_name (editable, "insert-text",
3709 (gpointer) result->str, (gpointer) result->len,
3710 (gpointer) position, (gpointer) window);
3711 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3715 if (result_len + old_length > 1000) {
3716 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3717 _CS("ckdg_ib_maximum_characters_reached"));
3719 g_string_free (result, TRUE);
3723 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3726 ModestMsgEditWindowPrivate *priv = NULL;
3728 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3729 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3731 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3734 gtk_widget_show_all (priv->isearch_toolbar);
3735 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3737 gtk_widget_hide_all (priv->isearch_toolbar);
3738 gtk_widget_grab_focus (priv->msg_body);
3743 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3745 GtkTextIter *match_start,
3746 GtkTextIter *match_end)
3748 GtkTextIter end_iter;
3749 gchar *str_casefold;
3752 gchar *range_casefold;
3755 gboolean result = FALSE;
3762 gtk_text_iter_forward_to_end (&end_iter);
3764 str_casefold = g_utf8_casefold (str, -1);
3765 str_chars_n = strlen (str);
3767 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3768 range_casefold = g_utf8_casefold (range_text, -1);
3769 range_chars_n = strlen (range_casefold);
3771 if (range_chars_n < str_chars_n) {
3772 g_free (str_casefold);
3773 g_free (range_text);
3774 g_free (range_casefold);
3778 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3779 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3780 if (!g_utf8_collate (range_subtext, str_casefold)) {
3781 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3783 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3784 match_start, match_end, NULL)) {
3785 g_debug ("Matched string with collate, but not matched in model");
3787 g_free (found_text);
3789 g_free (range_subtext);
3793 g_free (str_casefold);
3794 g_free (range_text);
3795 g_free (range_casefold);
3802 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
3803 ModestMsgEditWindow *window)
3805 const gchar *current_search = NULL;
3806 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3808 GtkTextIter selection_start, selection_end;
3809 GtkTextIter match_start, match_end;
3810 gboolean continue_search = FALSE;
3812 if (message_is_empty (window)) {
3813 g_free (priv->last_search);
3814 priv->last_search = NULL;
3815 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3819 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
3820 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3821 g_free (priv->last_search);
3822 priv->last_search = NULL;
3823 /* Information banner about empty search */
3824 modest_platform_system_banner (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3828 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3829 continue_search = TRUE;
3831 g_free (priv->last_search);
3832 priv->last_search = g_strdup (current_search);
3835 if (continue_search) {
3836 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3837 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3838 &match_start, &match_end);
3840 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3842 GtkTextIter buffer_start;
3843 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3844 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3845 &match_start, &match_end);
3847 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3850 /* Mark as selected the string found in search */
3852 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3853 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3854 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3856 g_free (priv->last_search);
3857 priv->last_search = NULL;
3862 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3864 ModestMsgEditWindowPrivate *priv;
3866 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3871 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3874 ModestMsgEditWindowPrivate *priv;
3876 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3881 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
3882 ModestMsgEditWindow *window)
3884 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
3888 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3891 ModestMsgEditWindowPrivate *priv;
3892 TnyHeader *header = NULL;
3894 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3895 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3897 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3899 if (priv->draft_msg != NULL) {
3900 g_object_unref (priv->draft_msg);
3903 if (draft != NULL) {
3904 g_object_ref (draft);
3905 header = tny_msg_get_header (draft);
3906 if (priv->msg_uid) {
3907 g_free (priv->msg_uid);
3908 priv->msg_uid = NULL;
3910 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3913 priv->draft_msg = draft;
3917 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3918 GtkTextIter *start, GtkTextIter *end,
3921 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3922 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3925 if (tag == NULL) return;
3926 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3927 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3928 replace_with_images (window, priv->images);
3933 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3936 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3938 g_return_if_fail (TNY_IS_MIME_PART (part));
3939 tny_list_prepend (priv->attachments, (GObject *) part);
3940 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3941 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3942 gtk_widget_show_all (priv->attachments_caption);
3943 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3947 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3949 ModestMsgEditWindowPrivate *priv;
3951 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3952 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3954 return priv->msg_uid;
3958 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3959 ModestMsgEditWindowWidgetType widget_type)
3961 ModestMsgEditWindowPrivate *priv;
3963 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3964 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3966 switch (widget_type) {
3967 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3968 return priv->msg_body;
3970 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3971 return priv->to_field;
3973 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3974 return priv->cc_field;
3976 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3977 return priv->bcc_field;
3979 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3980 return priv->subject_field;
3982 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3983 return priv->attachments_view;
3991 remove_tags (WPTextBuffer *buffer)
3993 GtkTextIter start, end;
3995 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3996 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3998 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4002 on_account_removed (TnyAccountStore *account_store,
4003 TnyAccount *account,
4006 /* Do nothing if it's a store account, because we use the
4007 transport to send the messages */
4008 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4009 const gchar *parent_acc = NULL;
4010 const gchar *our_acc = NULL;
4012 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4013 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4014 /* Close this window if I'm showing a message of the removed account */
4015 if (strcmp (parent_acc, our_acc) == 0)
4016 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4021 update_signature (ModestMsgEditWindow *self,
4022 const gchar *old_account,
4023 const gchar *new_account)
4025 ModestMsgEditWindowPrivate *priv;
4026 gboolean has_old_signature, has_new_signature;
4028 ModestAccountMgr *mgr;
4031 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4033 gtk_text_buffer_begin_user_action (priv->text_buffer);
4035 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4036 mgr = modest_runtime_get_account_mgr ();
4040 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4041 if (has_old_signature) {
4042 GtkTextIter match_start, match_end;
4044 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4045 seems that the search has some problems
4046 with the blank space at the end */
4047 if (gtk_text_iter_forward_search (&iter, "--",
4048 GTK_TEXT_SEARCH_TEXT_ONLY,
4049 &match_start, NULL, NULL)) {
4050 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4051 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4053 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4054 &match_start, &match_end, NULL)) {
4058 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4063 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4064 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4065 if (has_new_signature) {
4067 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4068 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4070 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4071 g_free (full_signature);
4074 gtk_text_buffer_end_user_action (priv->text_buffer);
4077 static void update_branding (ModestMsgEditWindow *self,
4078 const gchar *new_account)
4080 ModestMsgEditWindowPrivate *priv;
4081 ModestAccountMgr *mgr;
4082 const GdkPixbuf *new_icon = NULL;
4083 gchar *new_label = NULL;
4084 gboolean show = FALSE;
4086 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4088 mgr = modest_runtime_get_account_mgr ();
4090 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4092 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4093 gtk_widget_show (priv->brand_icon);
4096 gtk_widget_hide (priv->brand_icon);
4099 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4100 gtk_widget_show (priv->brand_label);
4104 gtk_widget_hide (priv->brand_label);
4108 gtk_widget_show (priv->brand_container);
4110 gtk_widget_hide (priv->brand_container);
4114 from_field_changed (GtkWidget *button,
4115 ModestMsgEditWindow *self)
4117 ModestMsgEditWindowPrivate *priv;
4118 gchar *old_account, *new_account;
4120 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4122 old_account = priv->last_from_account;
4123 new_account = modest_selector_get_active_id (priv->from_field);
4126 g_warning ("%s, could not get the new account", __FUNCTION__);
4130 /* If the From is the same do nothing */
4131 if (old_account && new_account && !strcmp (old_account, new_account))
4134 priv->last_from_account = new_account;
4136 update_signature (self, old_account, new_account);
4137 update_branding (self, new_account);
4141 typedef struct _MessageSettingsHelper {
4142 ModestMsgEditWindow *window;
4143 GSList *priority_group;
4144 GSList *format_group;
4145 GtkToggleButton *current_priority;
4146 GtkToggleButton *current_format;
4147 } MessageSettingsHelper;
4150 on_priority_toggle (GtkToggleButton *button,
4151 MessageSettingsHelper *helper)
4154 ModestMsgEditWindowPrivate *priv;
4156 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4157 if (gtk_toggle_button_get_active (button)) {
4159 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4160 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4161 if ((node_button != button) &&
4162 gtk_toggle_button_get_active (node_button)) {
4163 gtk_toggle_button_set_active (node_button, FALSE);
4166 helper->current_priority = button;
4168 gboolean found = FALSE;
4169 /* If no one is active, activate it again */
4170 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4171 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4172 if (gtk_toggle_button_get_active (node_button)) {
4178 gtk_toggle_button_set_active (button, TRUE);
4184 on_format_toggle (GtkToggleButton *button,
4185 MessageSettingsHelper *helper)
4188 ModestMsgEditWindowPrivate *priv;
4190 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4191 if (gtk_toggle_button_get_active (button)) {
4193 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4194 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4195 if ((node_button != button) &&
4196 gtk_toggle_button_get_active (node_button)) {
4197 gtk_toggle_button_set_active (node_button, FALSE);
4200 helper->current_format = button;
4202 gboolean found = FALSE;
4203 /* If no one is active, activate it again */
4204 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4205 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4206 if (gtk_toggle_button_get_active (node_button)) {
4212 gtk_toggle_button_set_active (button, TRUE);
4219 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4224 GtkWidget *priority_hbox;
4225 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4226 GtkWidget *captioned;
4227 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4228 GtkWidget *format_hbox;
4229 GtkWidget *html_toggle, *text_toggle;
4230 ModestMsgEditWindowPrivate *priv;
4231 MessageSettingsHelper helper = {0,};
4233 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4234 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4235 helper.window = window;
4236 helper.priority_group = NULL;
4237 helper.format_group = NULL;
4239 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4240 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4242 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4243 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4244 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4245 vbox = gtk_vbox_new (FALSE, 0);
4246 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4247 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4248 gtk_container_add (GTK_CONTAINER (align), vbox);
4249 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4250 gtk_widget_show (align);
4251 gtk_widget_show (vbox);
4253 /* Priority toggles */
4254 priority_hbox = gtk_hbox_new (TRUE, 0);
4255 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4256 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4257 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4258 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4259 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4260 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4261 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4262 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4263 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4264 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4265 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4266 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4267 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4268 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4269 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4270 gtk_widget_show_all (priority_hbox);
4271 captioned = modest_toolkit_utils_create_captioned (title_sizegroup, value_sizegroup,
4272 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4273 gtk_widget_show (captioned);
4274 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4276 /* format toggles */
4277 format_hbox = gtk_hbox_new (TRUE, 0);
4278 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4279 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4280 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4281 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4282 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4283 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4284 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4285 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4286 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4287 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4288 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4289 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4290 gtk_widget_show_all (format_hbox);
4291 gtk_widget_show (format_hbox);
4292 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4295 g_object_unref (title_sizegroup);
4296 g_object_unref (value_sizegroup);
4298 /* Set current values */
4299 switch (priv->priority_flags) {
4300 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4301 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4302 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4304 case TNY_HEADER_FLAG_LOW_PRIORITY:
4305 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4306 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4309 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4310 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4314 switch (modest_msg_edit_window_get_format (window)) {
4315 case MODEST_MSG_EDIT_FORMAT_TEXT:
4316 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4317 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4319 case MODEST_MSG_EDIT_FORMAT_HTML:
4321 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4322 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4326 /* Signal connects */
4327 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4328 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4329 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4330 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4331 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4333 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4334 GTK_WINDOW (dialog), GTK_WINDOW (window));
4336 /* Save settings if the user clicked on done */
4337 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4338 TnyHeaderFlags flags;
4339 ModestMsgEditFormat old_format, new_format;
4341 /* Set priority flags */
4342 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4343 if (priv->priority_flags != flags)
4344 modest_msg_edit_window_set_priority_flags (window, flags);
4346 /* Set edit format */
4347 old_format = modest_msg_edit_window_get_format (window);
4348 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4349 if (old_format != new_format) {
4350 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4351 modest_msg_edit_window_set_file_format (window, file_format);
4355 gtk_widget_destroy (dialog);
4356 g_slist_free (helper.priority_group);
4360 on_message_settings (GtkAction *action,
4361 ModestMsgEditWindow *window)
4363 modest_msg_edit_window_show_msg_settings_dialog (window);
4367 on_cc_button_toggled (GtkWidget *button,
4368 ModestMsgEditWindow *window)
4370 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4372 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4373 modest_togglable_get_active (button));
4377 on_bcc_button_toggled (GtkWidget *button,
4378 ModestMsgEditWindow *window)
4380 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4382 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4383 modest_togglable_get_active (button));
4387 setup_menu (ModestMsgEditWindow *self)
4389 ModestMsgEditWindowPrivate *priv = NULL;
4391 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4393 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4395 /* Settings menu buttons */
4396 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4397 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4399 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4400 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4401 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4402 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4403 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4404 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4406 priv->cc_button = hildon_check_button_new (0);
4407 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4408 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4410 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4411 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4412 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4414 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4415 _("mcen_me_editor_showbcc"));
4416 modest_togglable_set_active (priv->bcc_button,
4418 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4420 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4421 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4423 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4424 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4425 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4426 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4427 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4429 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4430 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4431 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4432 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4433 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4435 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4436 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4441 emit_open_addressbook (GtkButton *button,
4442 ModestRecptEditor *editor)
4444 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4448 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4449 const gchar *label, GtkWidget *control)
4451 GtkWidget *abook_button;
4454 GtkWidget *label_widget;
4456 box = gtk_hbox_new (FALSE, 0);
4458 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4459 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4461 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4462 label_widget = gtk_label_new (label);
4463 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4464 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4466 gtk_container_add (GTK_CONTAINER (align), abook_button);
4467 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4468 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4469 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4470 if (title_size_group)
4471 gtk_size_group_add_widget (title_size_group, label_widget);
4472 if (value_size_group)
4473 gtk_size_group_add_widget (value_size_group, control);
4475 g_signal_connect (G_OBJECT (abook_button), "clicked",
4476 G_CALLBACK (emit_open_addressbook), control);
4482 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4484 ModestMsgEditWindowPrivate *priv = NULL;
4486 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4488 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4489 priv->max_chars_banner = NULL;
4493 has_pending_addresses (ModestRecptEditor *recpt_editor)
4495 const gchar *recipients = NULL;
4496 GSList *start_indexes = NULL, *end_indexes = NULL;
4497 GSList *current_start, *current_end;
4498 GtkTextBuffer *buffer;
4499 gint offset_delta = 0;
4501 gboolean has_recipients_to_add = FALSE;
4503 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4504 last_length = g_utf8_strlen (recipients, -1);
4505 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4510 current_start = start_indexes;
4511 current_end = end_indexes;
4512 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4514 while (current_start && !has_recipients_to_add) {
4516 gchar *start_ptr, *end_ptr;
4517 gint start_pos, end_pos;
4519 start_pos = (*((gint*) current_start->data)) + offset_delta;
4520 end_pos = (*((gint*) current_end->data)) + offset_delta;
4522 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4523 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4525 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4527 if (modest_text_utils_validate_recipient (address, NULL)) {
4528 if (!modest_address_book_has_address (address)) {
4529 has_recipients_to_add = TRUE;
4532 current_start = g_slist_next (current_start);
4533 current_end = g_slist_next (current_end);
4535 return has_recipients_to_add;
4539 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4541 ModestMsgEditWindowPrivate *priv = NULL;
4543 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4545 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4547 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4548 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4549 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))