1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38 #include <tny-camel-mem-stream.h>
39 #include <modest-account-protocol.h>
43 #include <modest-account-mgr.h>
44 #include <modest-account-mgr-helpers.h>
46 #include <widgets/modest-msg-edit-window.h>
47 #include <modest-selector-picker.h>
48 #include <widgets/modest-recpt-editor.h>
49 #include <widgets/modest-attachments-view.h>
51 #include <modest-runtime.h>
53 #include "modest-platform.h"
54 #include "modest-icon-names.h"
55 #include "modest-widget-memory.h"
56 #include "modest-window-priv.h"
57 #include "modest-mail-operation.h"
58 #include "modest-tny-platform-factory.h"
59 #include "modest-tny-msg.h"
60 #include "modest-tny-folder.h"
61 #include "modest-tny-account.h"
62 #include "modest-address-book.h"
63 #include "modest-text-utils.h"
64 #include <tny-simple-list.h>
65 #include <modest-wp-text-view.h>
66 #include <wptextbuffer.h>
67 #include <modest-scrollable.h>
68 #include <modest-isearch-toolbar.h>
69 #include <hildon/hildon-touch-selector.h>
70 #include <hildon/hildon-picker-dialog.h>
71 #include "modest-msg-edit-window-ui-dimming.h"
73 #include "modest-hildon-includes.h"
74 #include "widgets/modest-msg-edit-window-ui.h"
75 #include <libgnomevfs/gnome-vfs-mime.h>
76 #include <modest-utils.h>
77 #include "modest-maemo-utils.h"
78 #include <modest-ui-constants.h>
80 #ifdef MODEST_USE_CALENDAR_WIDGETS
81 #include <calendar-ui-widgets.h>
84 #define DEFAULT_FONT_SIZE 3
85 #define DEFAULT_FONT 2
86 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
87 #define DEFAULT_MAIN_VBOX_SPACING 0
88 #define SUBJECT_MAX_LENGTH 1000
89 #define IMAGE_MAX_WIDTH 560
90 #define DEFAULT_FONT_SCALE 1.5
91 #define ATTACHMENT_BUTTON_WIDTH 118
92 #define MAX_FROM_VALUE 36
93 #define MAX_BODY_LENGTH 128*1024
94 #define MAX_BODY_LINES 2048
96 static gboolean is_wp_text_buffer_started = FALSE;
98 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
99 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
100 static void modest_msg_edit_window_finalize (GObject *obj);
102 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
103 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
104 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
106 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
107 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
108 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
109 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
110 GtkTextIter *start, GtkTextIter *end,
112 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
113 static void body_insert_text (GtkTextBuffer *buffer,
114 GtkTextIter *location,
117 ModestMsgEditWindow *window);
118 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
119 static void subject_field_insert_text (GtkEditable *editable,
121 gint new_text_length,
123 ModestMsgEditWindow *window);
124 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
126 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
128 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
129 ModestRecptEditor *editor);
130 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
131 ModestMsgEditWindow *window);
133 /* ModestWindow methods implementation */
134 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
135 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
136 gboolean show_toolbar);
137 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
139 ModestMsgEditWindow *window);
140 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
141 static void subject_field_move_cursor (GtkEntry *entry,
142 GtkMovementStep step,
146 static void update_window_title (ModestMsgEditWindow *window);
149 static void modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
150 ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
152 ModestMsgEditWindow *window);
153 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
155 GtkTextIter *match_start,
156 GtkTextIter *match_end);
158 static void remove_tags (WPTextBuffer *buffer);
160 static void on_account_removed (TnyAccountStore *account_store,
164 static void init_window (ModestMsgEditWindow *obj);
166 gboolean scroll_drag_timeout (gpointer userdata);
167 static void correct_scroll (ModestMsgEditWindow *w);
168 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
169 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
170 ModestMsgEditWindow *userdata);
171 static void text_buffer_mark_set (GtkTextBuffer *buffer,
174 ModestMsgEditWindow *userdata);
175 static void on_message_settings (GtkAction *action,
176 ModestMsgEditWindow *window);
177 static void setup_menu (ModestMsgEditWindow *self);
179 static void from_field_changed (GtkWidget *button,
180 ModestMsgEditWindow *self);
181 static void font_size_clicked (GtkToolButton *button,
182 ModestMsgEditWindow *window);
183 static void font_face_clicked (GtkToolButton *button,
184 ModestMsgEditWindow *window);
185 static void update_signature (ModestMsgEditWindow *self,
186 const gchar *old_account,
187 const gchar *new_account);
188 static void update_branding (ModestMsgEditWindow *self,
189 const gchar *new_account);
190 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
191 const gchar *label, GtkWidget *control);
192 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
193 static void DEBUG_BUFFER (WPTextBuffer *buffer)
197 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
199 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
200 while (!gtk_text_iter_is_end (&iter)) {
201 GString *output = g_string_new ("");
202 GSList *toggled_tags;
205 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
206 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
207 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
208 GtkTextTag *tag = (GtkTextTag *) node->data;
210 g_object_get (G_OBJECT (tag), "name", &name, NULL);
211 output = g_string_append (output, name);
212 g_string_append (output, " ");
214 output = g_string_append (output, "] OPENED [ ");
215 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
216 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
217 GtkTextTag *tag = (GtkTextTag *) node->data;
219 g_object_get (G_OBJECT (tag), "name", &name, NULL);
220 output = g_string_append (output, name);
221 g_string_append (output, " ");
223 output = g_string_append (output, "]\n");
224 g_debug ("%s", output->str);
225 g_string_free (output, TRUE);
226 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
228 g_debug ("END BUFFER");
232 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
233 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
237 /* static gboolean */
238 /* on_key_pressed (GtkWidget *self, */
239 /* GdkEventKey *event, */
240 /* gpointer user_data); */
242 /* list my signals */
249 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
250 struct _ModestMsgEditWindowPrivate {
252 GtkWidget *header_box;
254 ModestPairList *from_field_protos;
255 GtkWidget *from_field;
256 gchar *last_from_account;
257 gchar *original_account_name;
262 gchar *original_mailbox;
266 GtkWidget *bcc_field;
267 GtkWidget *subject_field;
268 GtkWidget *attachments_view;
269 GtkWidget *priority_icon;
270 GtkWidget *subject_box;
271 GtkWidget *send_button;
273 GtkWidget *cc_caption;
274 GtkWidget *bcc_caption;
275 gboolean update_caption_visibility;
276 GtkWidget *attachments_caption;
278 GtkTextBuffer *text_buffer;
280 GtkWidget *font_size_toolitem;
281 GtkWidget *font_face_toolitem;
282 GtkWidget *font_color_button;
283 GtkWidget *font_color_toolitem;
284 GSList *font_items_group;
285 GtkTreeModel *faces_model;
286 gint current_face_index;
287 GtkWidget *font_tool_button_label;
288 GtkTreeModel *sizes_model;
289 gint current_size_index;
290 GtkWidget *size_tool_button_label;
292 GtkWidget *isearch_toolbar;
295 GtkWidget *font_dialog;
297 GtkWidget *scrollable;
298 guint correct_scroll_idle;
299 guint scroll_drag_timeout_id;
303 TnyList *attachments;
308 TnyHeaderFlags priority_flags;
310 gboolean can_undo, can_redo;
311 gulong clipboard_change_handler_id;
312 gulong default_clipboard_change_handler_id;
313 gulong account_removed_handler_id;
314 guint clipboard_owner_idle;
315 gchar *clipboard_text;
324 GtkWidget *cc_button;
325 GtkWidget *bcc_button;
327 GtkWidget *max_chars_banner;
329 GtkWidget *brand_icon;
330 GtkWidget *brand_label;
331 GtkWidget *brand_container;
334 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
335 MODEST_TYPE_MSG_EDIT_WINDOW, \
336 ModestMsgEditWindowPrivate))
338 static GtkWindowClass *parent_class = NULL;
340 /* uncomment the following if you have defined any signals */
341 /* static guint signals[LAST_SIGNAL] = {0}; */
344 modest_msg_edit_window_get_type (void)
346 static GType my_type = 0;
348 static const GTypeInfo my_info = {
349 sizeof(ModestMsgEditWindowClass),
350 NULL, /* base init */
351 NULL, /* base finalize */
352 (GClassInitFunc) modest_msg_edit_window_class_init,
353 NULL, /* class finalize */
354 NULL, /* class data */
355 sizeof(ModestMsgEditWindow),
357 (GInstanceInitFunc) modest_msg_edit_window_init,
360 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
361 "ModestMsgEditWindow",
369 save_state (ModestWindow *self)
371 modest_widget_memory_save (modest_runtime_get_conf(),
372 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
377 restore_settings (ModestMsgEditWindow *self)
379 ModestConf *conf = NULL;
381 conf = modest_runtime_get_conf ();
383 /* Dim at start clipboard actions */
384 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
389 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
391 GObjectClass *gobject_class;
392 ModestWindowClass *modest_window_class;
393 gobject_class = (GObjectClass*) klass;
394 modest_window_class = (ModestWindowClass*) klass;
396 parent_class = g_type_class_peek_parent (klass);
397 gobject_class->finalize = modest_msg_edit_window_finalize;
399 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
400 modest_window_class->save_state_func = save_state;
401 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
403 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
407 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
409 ModestMsgEditWindowPrivate *priv;
410 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
412 priv->msg_body = NULL;
413 priv->from_field = NULL;
414 priv->to_field = NULL;
415 priv->cc_field = NULL;
416 priv->bcc_field = NULL;
417 priv->subject_field = NULL;
418 priv->attachments = TNY_LIST (tny_simple_list_new ());
419 priv->images = TNY_LIST (tny_simple_list_new ());
420 priv->images_size = 0;
421 priv->images_count = 0;
424 priv->cc_caption = NULL;
425 priv->bcc_caption = NULL;
426 priv->update_caption_visibility = FALSE;
428 priv->priority_flags = 0;
430 priv->isearch_toolbar = NULL;
431 priv->last_search = NULL;
433 priv->draft_msg = NULL;
434 priv->outbox_msg = NULL;
435 priv->msg_uid = NULL;
437 priv->can_undo = FALSE;
438 priv->can_redo = FALSE;
439 priv->clipboard_change_handler_id = 0;
440 priv->default_clipboard_change_handler_id = 0;
441 priv->account_removed_handler_id = 0;
442 priv->clipboard_owner_idle = 0;
443 priv->clipboard_text = NULL;
446 priv->scroll_drag_timeout_id = 0;
447 priv->correct_scroll_idle = 0;
448 priv->last_upper = 0.0;
450 priv->font_dialog = NULL;
451 priv->app_menu = NULL;
453 priv->references = NULL;
454 priv->in_reply_to = NULL;
455 priv->max_chars_banner = NULL;
457 if (!is_wp_text_buffer_started) {
458 is_wp_text_buffer_started = TRUE;
459 wp_text_buffer_library_init ();
464 hildon_program_add_window (hildon_program_get_instance(),
469 multimailbox_get_default_mailbox (const gchar *account_name)
471 gchar *transport_account;
472 gchar *result = NULL;
474 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
476 TNY_ACCOUNT_TYPE_TRANSPORT);
477 if (transport_account) {
479 ModestProtocolRegistry *registry;
481 registry = modest_runtime_get_protocol_registry ();
483 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
484 MODEST_ACCOUNT_PROTO, TRUE);
486 ModestProtocol *protocol =
487 modest_protocol_registry_get_protocol_by_name (registry,
488 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
490 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
491 ModestPairList *pair_list;
493 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
496 ModestPair *pair = (ModestPair *) pair_list->data;
497 result = g_strdup ((const gchar *) pair->first);
498 modest_pair_list_free (pair_list);
509 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
511 static ModestPairList*
512 get_transports (void)
514 GSList *transports = NULL;
516 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
517 GSList *accounts = modest_account_mgr_account_names (account_mgr,
518 TRUE /* only enabled accounts. */);
520 GSList *cursor = accounts;
522 gchar *account_name = cursor->data;
525 gchar *transport_account;
526 gboolean multi_mailbox = FALSE;
527 ModestProtocol *protocol = NULL;
529 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
531 transport_account = modest_account_mgr_get_server_account_name
532 (modest_runtime_get_account_mgr (),
534 TNY_ACCOUNT_TYPE_TRANSPORT);
535 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
536 ModestPairList *pair_list;
537 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
540 transports = g_slist_concat (transports, pair_list);
541 multi_mailbox = TRUE;
546 if (!multi_mailbox) {
547 gchar *from_string = NULL;
549 from_string = modest_account_mgr_get_from_string (account_mgr,
551 if (from_string && account_name) {
552 gchar *name = account_name;
553 ModestPair *pair = modest_pair_new ((gpointer) name,
554 (gpointer) from_string , TRUE);
555 transports = g_slist_prepend (transports, pair);
560 cursor = cursor->next;
562 g_slist_free (accounts); /* only free the accounts, not the elements,
563 * because they are used in the pairlist */
567 static void window_focus (GtkWindow *window,
571 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
575 scroll_drag_timeout (gpointer userdata)
577 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
578 ModestMsgEditWindowPrivate *priv;
580 /* It could happen that the window was already closed */
581 if (!GTK_WIDGET_VISIBLE (win))
584 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
586 correct_scroll_without_drag_check (win, TRUE);
588 priv->scroll_drag_timeout_id = 0;
594 correct_scroll_without_drag_check_idle (gpointer userdata)
596 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
597 ModestMsgEditWindowPrivate *priv;
599 GdkRectangle rectangle;
600 gint offset_min, offset_max;
604 /* It could happen that the window was already closed */
605 if (!GTK_WIDGET_VISIBLE (w))
608 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
610 insert = gtk_text_buffer_get_insert (priv->text_buffer);
611 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
613 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
614 offset_min = priv->msg_body->allocation.y + rectangle.y;
615 offset_max = offset_min + rectangle.height;
617 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
618 offset_min = MAX (offset_min - 48, 0);
619 offset_max = MIN (offset_max + 48, vadj->upper);
621 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
623 priv->correct_scroll_idle = 0;
628 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
630 ModestMsgEditWindowPrivate *priv;
632 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
634 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
637 if (priv->correct_scroll_idle > 0) {
641 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
642 (GSourceFunc) correct_scroll_without_drag_check_idle,
648 correct_scroll (ModestMsgEditWindow *w)
650 ModestMsgEditWindowPrivate *priv;
652 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
653 if (gtk_grab_get_current () == priv->msg_body) {
654 if (priv->scroll_drag_timeout_id == 0) {
655 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
657 (GSourceFunc) scroll_drag_timeout,
664 correct_scroll_without_drag_check (w, TRUE);
668 text_buffer_end_user_action (GtkTextBuffer *buffer,
669 ModestMsgEditWindow *userdata)
672 correct_scroll (userdata);
676 text_buffer_mark_set (GtkTextBuffer *buffer,
679 ModestMsgEditWindow *userdata)
681 gtk_text_buffer_begin_user_action (buffer);
682 gtk_text_buffer_end_user_action (buffer);
686 cut_clipboard_check (GtkTextView *text_view,
689 GtkTextBuffer *buffer;
691 buffer = gtk_text_view_get_buffer (text_view);
692 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
693 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
698 copy_clipboard_check (GtkTextView *text_view,
701 GtkTextBuffer *buffer;
703 buffer = gtk_text_view_get_buffer (text_view);
704 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
705 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
710 attachment_deleted (ModestAttachmentsView *attachments_view,
713 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
718 body_size_request (GtkWidget *body,
722 /* Make sure the body always get at least 70 pixels */
723 if (req->height < 70)
728 connect_signals (ModestMsgEditWindow *obj)
730 ModestMsgEditWindowPrivate *priv;
732 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
734 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
735 G_CALLBACK (text_buffer_refresh_attributes), obj);
736 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
737 G_CALLBACK (text_buffer_can_undo), obj);
738 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
739 G_CALLBACK (text_buffer_can_redo), obj);
740 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
741 G_CALLBACK (body_changed), obj);
742 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
743 G_CALLBACK (body_insert_text), obj);
744 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
745 G_CALLBACK (body_changed), obj);
746 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
747 G_CALLBACK (text_buffer_end_user_action), obj);
748 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
749 G_CALLBACK (text_buffer_mark_set), obj);
750 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
751 G_CALLBACK (text_buffer_apply_tag), obj);
752 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
753 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
754 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
755 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
756 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
757 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
759 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
760 G_CALLBACK (modest_ui_actions_on_send), obj);
762 if (GTK_IS_COMBO_BOX (priv->from_field)) {
763 g_signal_connect (G_OBJECT (priv->from_field), "changed",
764 G_CALLBACK (from_field_changed), obj);
766 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
767 G_CALLBACK (from_field_changed), obj);
770 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
771 G_CALLBACK (msg_body_focus), obj);
772 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
773 G_CALLBACK (msg_body_focus), obj);
774 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
775 G_CALLBACK (body_size_request), obj);
776 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
777 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
778 "changed", G_CALLBACK (recpt_field_changed), obj);
779 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
780 "changed", G_CALLBACK (recpt_field_changed), obj);
781 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
782 "changed", G_CALLBACK (recpt_field_changed), obj);
783 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
784 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
785 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
787 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
788 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
789 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
790 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_close), obj);
792 priv->clipboard_change_handler_id =
793 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
794 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
795 priv->default_clipboard_change_handler_id =
796 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
797 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
799 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
800 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
801 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
805 init_wp_text_view_style ()
807 static gboolean initialized = FALSE;
810 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
816 init_window (ModestMsgEditWindow *obj)
818 GtkWidget *to_caption, *subject_caption;
819 GtkWidget *main_vbox;
820 ModestMsgEditWindowPrivate *priv;
821 GtkActionGroup *action_group;
822 ModestWindowPrivate *parent_priv;
823 GdkPixbuf *window_icon = NULL;
824 GError *error = NULL;
826 GtkSizeGroup *title_size_group;
827 GtkSizeGroup *value_size_group;
828 GtkWidget *window_box;
829 GtkWidget *window_align;
830 #if (GTK_MINOR_VERSION >= 10)
831 GdkAtom deserialize_type;
833 GtkWidget *from_send_hbox;
834 GtkWidget *send_icon;
835 GtkWidget *attachments_label;
836 GtkWidget *branding_box;
837 GtkWidget *from_caption;
839 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
840 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
842 parent_priv->ui_manager = gtk_ui_manager_new();
843 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
844 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
846 /* Add common actions */
847 gtk_action_group_add_actions (action_group,
848 modest_msg_edit_action_entries,
849 G_N_ELEMENTS (modest_msg_edit_action_entries),
851 gtk_action_group_add_actions (action_group,
852 hildon2_msg_edit_action_entries,
853 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
855 gtk_action_group_add_toggle_actions (action_group,
856 modest_msg_edit_toggle_action_entries,
857 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
859 gtk_action_group_add_radio_actions (action_group,
860 modest_msg_edit_alignment_radio_action_entries,
861 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
863 G_CALLBACK (modest_ui_actions_on_change_justify),
865 gtk_action_group_add_radio_actions (action_group,
866 modest_msg_edit_priority_action_entries,
867 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
869 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
871 gtk_action_group_add_radio_actions (action_group,
872 modest_msg_edit_file_format_action_entries,
873 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
874 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
875 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
877 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
878 g_object_unref (action_group);
880 /* Load the UI definition */
881 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
884 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
885 g_clear_error (&error);
888 /* Add accelerators */
889 gtk_window_add_accel_group (GTK_WINDOW (obj),
890 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
892 parent_priv->menubar = NULL;
894 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
895 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
897 /* Note: This ModestPairList* must exist for as long as the picker
898 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
899 * so it can't know how to manage its memory. */
900 priv->from_field = modest_toolkit_factory_create_selector (modest_runtime_get_toolkit_factory (),
902 modest_selector_set_value_max_chars (priv->from_field, MAX_FROM_VALUE);
903 if (GTK_IS_COMBO_BOX (priv->from_field)) {
904 from_caption = modest_maemo_utils_create_captioned (title_size_group, NULL,
905 _("mail_va_from"), FALSE,
907 gtk_widget_show (from_caption);
909 modest_maemo_utils_set_hbutton_layout (title_size_group, NULL,
910 _("mail_va_from"), priv->from_field);
911 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
912 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
913 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
914 from_caption = priv->from_field;
917 priv->to_field = modest_recpt_editor_new ();
918 priv->cc_field = modest_recpt_editor_new ();
919 priv->bcc_field = modest_recpt_editor_new ();
920 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
921 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
922 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
923 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
924 priv->priority_icon = gtk_image_new ();
925 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
926 priv->subject_field = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
927 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
928 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
929 modest_entry_set_hint (priv->subject_field, _("mail_va_no_subject"));
930 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
931 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
932 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
933 priv->attachments_view = modest_attachments_view_new (NULL);
934 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
935 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
937 priv->header_box = gtk_vbox_new (FALSE, 0);
939 to_caption = _create_addressbook_box
940 (title_size_group, value_size_group,
941 _("mail_va_to"), priv->to_field);
942 priv->cc_caption = _create_addressbook_box
943 (title_size_group, value_size_group,
944 _("mail_va_cc"), priv->cc_field);
945 priv->bcc_caption = _create_addressbook_box
946 (title_size_group, value_size_group,
947 _("mail_va_hotfix1"), priv->bcc_field);
948 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
949 _("mail_va_subject"), FALSE, priv->subject_box);
950 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (NULL, NULL,
951 _("mail_va_attachment"),
953 priv->attachments_view,
954 HILDON_SIZE_AUTO_WIDTH |
955 HILDON_SIZE_AUTO_HEIGHT);
956 attachments_label = modest_maemo_utils_captioned_get_label_widget (priv->attachments_caption);
957 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
960 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
961 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
962 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
963 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
965 g_object_unref (title_size_group);
966 g_object_unref (value_size_group);
968 priv->brand_icon = gtk_image_new ();
969 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
970 priv->brand_label = gtk_label_new (NULL);
971 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
972 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
973 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
974 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
976 from_send_hbox = gtk_hbox_new (FALSE, 0);
977 gtk_box_pack_start (GTK_BOX (from_send_hbox), from_caption, TRUE, TRUE, 0);
978 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
980 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
981 gtk_widget_show (branding_box);
982 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
983 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
985 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
986 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
987 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
988 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
991 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
992 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
993 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
994 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
995 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
996 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
997 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
998 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1000 init_wp_text_view_style ();
1002 priv->msg_body = modest_wp_text_view_new ();
1005 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1006 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1007 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1008 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1009 #if (GTK_MINOR_VERSION >= 10)
1010 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1011 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1013 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1014 deserialize_type, TRUE);
1016 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1018 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1020 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1022 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1024 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1026 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1028 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1029 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1030 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1032 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1033 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1034 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1036 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1037 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1039 window_box = gtk_vbox_new (FALSE, 0);
1040 gtk_container_add (GTK_CONTAINER(obj), window_box);
1042 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1044 /* Set window icon */
1045 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1047 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1048 g_object_unref (window_icon);
1053 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1055 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1057 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1058 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1059 priv->clipboard_change_handler_id))
1060 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1061 priv->clipboard_change_handler_id);
1062 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1063 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1064 priv->default_clipboard_change_handler_id))
1065 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1066 priv->default_clipboard_change_handler_id);
1068 if (priv->account_removed_handler_id &&
1069 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1070 priv->account_removed_handler_id))
1071 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1072 priv->account_removed_handler_id);
1076 modest_msg_edit_window_finalize (GObject *obj)
1078 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1080 if (priv->max_chars_banner) {
1081 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1082 priv->max_chars_banner = FALSE;
1085 /* Sanity check: shouldn't be needed, the window mgr should
1086 call this function before */
1087 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1089 if (priv->font_dialog != NULL) {
1090 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1093 if (priv->clipboard_text != NULL) {
1094 g_free (priv->clipboard_text);
1095 priv->clipboard_text = NULL;
1098 if (priv->draft_msg != NULL) {
1099 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1100 if (TNY_IS_HEADER (header)) {
1101 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1102 modest_window_mgr_unregister_header (mgr, header);
1104 g_object_unref (priv->draft_msg);
1105 priv->draft_msg = NULL;
1107 if (priv->outbox_msg != NULL) {
1108 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1109 if (TNY_IS_HEADER (header)) {
1110 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1111 modest_window_mgr_unregister_header (mgr, header);
1113 g_object_unref (priv->outbox_msg);
1114 priv->outbox_msg = NULL;
1116 if (priv->correct_scroll_idle > 0) {
1117 g_source_remove (priv->correct_scroll_idle);
1118 priv->correct_scroll_idle = 0;
1120 if (priv->scroll_drag_timeout_id > 0) {
1121 g_source_remove (priv->scroll_drag_timeout_id);
1122 priv->scroll_drag_timeout_id = 0;
1124 if (priv->clipboard_owner_idle > 0) {
1125 g_source_remove (priv->clipboard_owner_idle);
1126 priv->clipboard_owner_idle = 0;
1128 if (priv->original_account_name)
1129 g_free (priv->original_account_name);
1130 if (priv->original_mailbox)
1131 g_free (priv->original_mailbox);
1132 g_free (priv->msg_uid);
1133 g_free (priv->last_search);
1134 g_free (priv->references);
1135 g_free (priv->in_reply_to);
1136 g_object_unref (priv->attachments);
1137 g_object_unref (priv->images);
1139 /* This had to stay alive for as long as the picker that used it: */
1140 modest_pair_list_free (priv->from_field_protos);
1142 G_OBJECT_CLASS(parent_class)->finalize (obj);
1146 pixbuf_size_prepared (GdkPixbufLoader *loader,
1149 ModestMsgEditWindow *self)
1151 gint new_height, new_width;
1154 new_height = height;
1158 if (width > IMAGE_MAX_WIDTH) {
1159 new_height = height * IMAGE_MAX_WIDTH / width;
1160 new_width = IMAGE_MAX_WIDTH;
1163 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1167 pixbuf_from_stream (TnyStream *stream,
1168 const gchar *mime_type,
1169 guint64 *stream_size,
1170 ModestMsgEditWindow *self)
1172 GdkPixbufLoader *loader;
1175 GError *error = NULL;
1179 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1181 if (loader == NULL) {
1186 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1188 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1190 tny_stream_reset (TNY_STREAM (stream));
1191 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1192 unsigned char read_buffer[128];
1194 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1196 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1199 /* Allow some UI responsiveness */
1200 while (gtk_events_pending ())
1201 gtk_main_iteration ();
1203 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1205 gdk_pixbuf_loader_close (loader, &error);
1208 g_error_free (error);
1209 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1211 g_object_ref (pixbuf);
1212 g_object_unref (loader);
1217 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1218 GdkPixbuf *new_pixbuf;
1220 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1221 gdk_pixbuf_get_width (pixbuf);
1222 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1223 g_object_unref (pixbuf);
1224 pixbuf = new_pixbuf;
1228 *stream_size = size;
1234 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1236 ModestMsgEditWindowPrivate *priv;
1239 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1241 g_object_ref (self);
1242 for (iter = tny_list_create_iterator (attachments);
1243 !tny_iterator_is_done (iter);
1244 tny_iterator_next (iter)) {
1245 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1246 const gchar *cid = tny_mime_part_get_content_id (part);
1247 const gchar *mime_type = tny_mime_part_get_content_type (part);
1248 if ((cid != NULL)&&(mime_type != NULL)) {
1249 guint64 stream_size;
1250 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1251 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1254 g_object_unref (stream);
1256 if (pixbuf != NULL) {
1257 priv->images_count ++;
1258 priv->images_size += stream_size;
1259 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1260 g_object_unref (pixbuf);
1263 g_object_unref (part);
1265 g_object_unref (iter);
1266 g_object_unref (self);
1270 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1272 TnyMimePart *parent = NULL;
1273 const gchar *content_type = NULL;
1274 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1276 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1278 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1279 parent = g_object_ref (msg);
1280 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1281 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1284 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1285 iter = tny_list_create_iterator (parts);
1286 while (!tny_iterator_is_done (iter)) {
1288 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1289 content_type = tny_mime_part_get_content_type (part);
1290 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1294 g_object_unref (part);
1296 tny_iterator_next (iter);
1298 g_object_unref (iter);
1299 g_object_unref (parts);
1302 if (parent != NULL) {
1303 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1306 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1307 iter = tny_list_create_iterator (parts);
1308 while (!tny_iterator_is_done (iter)) {
1310 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1311 content_type = tny_mime_part_get_content_type (part);
1312 if (content_type && g_str_has_prefix (content_type, "image/")) {
1313 tny_list_prepend (priv->images, (GObject *) part);
1315 g_object_unref (part);
1316 tny_iterator_next (iter);
1318 g_object_unref (iter);
1319 g_object_unref (parts);
1320 g_object_unref (parent);
1325 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1328 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1330 for (iter = tny_list_create_iterator (attachments) ;
1331 !tny_iterator_is_done (iter);
1332 tny_iterator_next (iter)) {
1333 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1334 const gchar *cid = tny_mime_part_get_content_id (part);
1336 char *invalid = NULL;
1337 gint int_cid = strtol (cid, &invalid, 10);
1338 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1339 priv->next_cid = int_cid + 1;
1342 g_object_unref (part);
1344 g_object_unref (iter);
1348 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1351 gchar *to, *cc, *bcc, *subject;
1353 ModestMsgEditWindowPrivate *priv;
1354 ModestWindowPrivate *parent_priv;
1356 TnyHeaderFlags priority_flags;
1357 TnyFolder *msg_folder;
1358 gboolean is_html = FALSE;
1359 gboolean field_view_set;
1361 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1362 g_return_if_fail (TNY_IS_MSG (msg));
1364 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1365 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1367 header = tny_msg_get_header (msg);
1368 to = tny_header_dup_to (header);
1369 cc = tny_header_dup_cc (header);
1370 bcc = tny_header_dup_bcc (header);
1371 subject = tny_header_dup_subject (header);
1373 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1374 priority_flags = tny_header_get_priority (header);
1377 gchar *quoted_names = modest_text_utils_quote_names (to);
1378 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1379 g_free (quoted_names);
1382 field_view_set = TRUE;
1384 gchar *quoted_names = modest_text_utils_quote_names (cc);
1385 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1386 g_free (quoted_names);
1387 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1388 gtk_widget_show (priv->cc_caption);
1389 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1390 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1391 gtk_widget_hide (priv->cc_caption);
1392 field_view_set = FALSE;
1394 modest_togglable_set_active (priv->cc_button, field_view_set);
1396 field_view_set = TRUE;
1398 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1399 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1400 g_free (quoted_names);
1401 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1402 gtk_widget_show (priv->bcc_caption);
1403 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1404 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1405 gtk_widget_hide (priv->bcc_caption);
1406 field_view_set = FALSE;
1408 modest_togglable_set_active (priv->bcc_button, field_view_set);
1412 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1413 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1416 update_window_title (self);
1418 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1419 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1421 if ((body == NULL)||(body[0] == '\0')) {
1423 body = modest_text_utils_convert_to_html ("");
1426 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1427 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1430 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1433 /* Add attachments to the view */
1434 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1435 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1436 if (tny_list_get_length (priv->attachments) == 0) {
1437 gtk_widget_hide (priv->attachments_caption);
1439 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1440 gtk_widget_show_all (priv->attachments_caption);
1442 get_related_images (self, msg);
1443 update_next_cid (self, priv->attachments);
1444 update_next_cid (self, priv->images);
1445 replace_with_images (self, priv->images);
1447 if (preserve_is_rich && !is_html) {
1448 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1449 /* Get the default format required from configuration */
1450 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1451 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1454 /* Set the default focus depending on having already a To: field or not */
1455 if ((!to)||(*to == '\0')) {
1456 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1458 gtk_widget_grab_focus (priv->msg_body);
1461 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1463 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1464 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1466 modest_msg_edit_window_set_modified (self, FALSE);
1468 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1469 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1470 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1471 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1473 if (priv->msg_uid) {
1474 g_free (priv->msg_uid);
1475 priv->msg_uid = NULL;
1478 /* we should set a reference to the incoming message if it is a draft */
1479 msg_folder = tny_msg_get_folder (msg);
1481 if (modest_tny_folder_is_local_folder (msg_folder)) {
1482 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1483 if (type == TNY_FOLDER_TYPE_INVALID)
1484 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1486 if (type == TNY_FOLDER_TYPE_DRAFTS)
1487 priv->draft_msg = g_object_ref(msg);
1488 if (type == TNY_FOLDER_TYPE_OUTBOX)
1489 priv->outbox_msg = g_object_ref(msg);
1490 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1492 g_object_unref (msg_folder);
1501 #ifdef MODEST_USE_CALENDAR_WIDGETS
1503 color_button_clicked (GtkButton *button)
1505 PipCalendarColor color;
1507 /* Show ColorPicker dialog */
1508 color = pip_color_picker_select_color(PipCalendarColorInvalid, PipColorPickerText);
1510 /* Check if some color is selected rather than dialog is dismissed */
1511 if (color != PipCalendarColorInvalid) {
1512 GdkColor *gdk_color = (GdkColor *) pip_calendar_color_get_gdkcolor (color);
1514 hildon_color_button_set_color ((HildonColorButton *) button, gdk_color);
1520 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1522 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1523 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1524 GtkWidget *placeholder;
1525 GtkWidget *tool_item;
1530 GtkWidget *sizes_menu;
1531 GtkWidget *fonts_menu;
1537 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1538 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1539 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1540 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1542 /* Font color placeholder */
1543 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1544 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1547 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1548 priv->font_color_button = hildon_color_button_new ();
1549 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1550 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1551 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1552 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1553 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1554 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1555 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1556 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1558 G_CALLBACK (modest_msg_edit_window_color_button_change),
1561 /* Yes I know this is a horrible hack, but it works for the
1562 moment while we don't create a ModestColorButton */
1563 #ifdef MODEST_USE_CALENDAR_WIDGETS
1564 GtkButtonClass *button_class = GTK_BUTTON_CLASS (HILDON_COLOR_BUTTON_GET_CLASS (priv->font_color_button));
1565 button_class->clicked = color_button_clicked;
1568 /* Font size and face placeholder */
1569 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1570 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1572 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1573 priv->size_tool_button_label = gtk_label_new (NULL);
1574 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1575 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1576 size_text, "</span>", NULL);
1577 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1578 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1580 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1581 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1582 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1583 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1584 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1585 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1586 gtk_widget_set_sensitive (arrow, FALSE);
1587 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1588 sizes_menu = gtk_menu_new ();
1589 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1590 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1593 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1594 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1596 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1600 if (wp_font_size[size_index] == 12)
1601 priv->current_size_index = size_index;
1605 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1606 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1607 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1608 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1609 priv->font_size_toolitem = tool_item;
1612 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1613 priv->font_tool_button_label = gtk_label_new (NULL);
1614 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1615 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1616 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1618 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1619 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1620 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1621 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1622 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1623 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1624 gtk_widget_set_sensitive (arrow, FALSE);
1625 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1626 fonts_menu = gtk_menu_new ();
1627 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1628 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1631 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1633 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1634 0, wp_get_font_name (font_index),
1637 if (font_index == DEFAULT_FONT)
1638 priv->current_face_index = font_index;
1640 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1641 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1642 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1643 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1644 priv->font_face_toolitem = tool_item;
1646 /* Set expand and homogeneous for remaining items */
1647 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1648 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1649 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1650 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1651 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1652 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1654 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1655 will not show the tool items added to the placeholders) */
1656 gtk_widget_show_all (parent_priv->toolbar);
1658 /* Set the no show all *after* showing all items. We do not
1659 want the toolbar to be shown with a show all because it
1660 could go agains the gconf setting regarding showing or not
1661 the toolbar of the editor window */
1662 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1668 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1671 ModestWindowPrivate *parent_priv;
1672 ModestMsgEditWindowPrivate *priv;
1673 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1674 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1675 ModestWindowMgr *mgr = NULL;
1677 g_return_val_if_fail (msg, NULL);
1678 g_return_val_if_fail (account_name, NULL);
1680 mgr = modest_runtime_get_window_mgr ();
1682 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1684 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1685 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1687 /* Menubar. Update the state of some toggles */
1688 priv->from_field_protos = get_transports ();
1689 priv->original_mailbox = NULL;
1690 modest_selector_set_pair_list (priv->from_field, priv->from_field_protos);
1691 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1692 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1693 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1694 modest_selector_set_active_id (priv->from_field, (gpointer) mailbox);
1695 priv->original_mailbox = g_strdup (mailbox);
1696 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1697 /* We set the first mailbox as the active mailbox */
1698 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1699 if (priv->original_mailbox != NULL)
1700 modest_selector_set_active_id (priv->from_field,
1701 (gpointer) priv->original_mailbox);
1703 modest_selector_set_active_id (priv->from_field,
1704 (gpointer) account_name);
1706 modest_selector_set_active_id (priv->from_field, (gpointer) account_name);
1708 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
1709 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1710 if (!GTK_IS_COMBO_BOX (priv->from_field)) {
1711 #ifdef HILDON_TOOLKIT_HILDON2
1712 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1714 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1715 hildon_touch_selector_get_current_text
1716 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1719 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1720 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1723 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1725 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1727 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1728 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1730 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1732 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1733 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1734 /* Add common dimming rules */
1735 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1736 modest_msg_edit_window_toolbar_dimming_entries,
1737 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1738 MODEST_WINDOW (obj));
1739 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1740 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1741 MODEST_WINDOW (obj));
1742 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1743 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1744 MODEST_WINDOW (obj));
1745 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1746 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1747 MODEST_WINDOW (obj));
1748 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1749 G_CALLBACK (modest_ui_dimming_rules_on_send),
1750 MODEST_WINDOW (obj));
1751 /* Insert dimming rules group for this window */
1752 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1753 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1755 /* Setup app menu */
1756 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1758 /* Checks the dimming rules */
1759 g_object_unref (toolbar_rules_group);
1760 g_object_unref (clipboard_rules_group);
1761 gtk_widget_hide (priv->priority_icon);
1762 gtk_widget_queue_resize (priv->subject_box);
1763 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1765 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1767 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1768 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1769 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1770 priv->update_caption_visibility = TRUE;
1772 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1774 /* Track account-removed signal, this window should be closed
1775 in the case we're creating a mail associated to the account
1777 priv->account_removed_handler_id =
1778 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1780 G_CALLBACK(on_account_removed),
1783 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1785 return (ModestWindow*) obj;
1789 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1791 GString **string_buffer = (GString **) user_data;
1793 *string_buffer = g_string_append (*string_buffer, buffer);
1799 * @result: A new string which should be freed with g_free().
1802 get_formatted_data (ModestMsgEditWindow *edit_window)
1804 ModestMsgEditWindowPrivate *priv;
1805 GString *string_buffer = g_string_new ("");
1807 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1809 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1811 modest_text_utils_hyperlinkify (string_buffer);
1813 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1815 return g_string_free (string_buffer, FALSE);
1820 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1823 const gchar *account_name;
1824 ModestMsgEditWindowPrivate *priv;
1825 TnyIterator *att_iter;
1826 const gchar *picker_active_id;
1828 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1830 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1832 picker_active_id = modest_selector_get_active_id (priv->from_field);
1833 g_return_val_if_fail (picker_active_id, NULL);
1834 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1836 /* don't free these (except from) */
1837 data = g_slice_new0 (MsgData);
1838 data->from = g_strdup ((gchar *) modest_selector_get_active_display_name (priv->from_field));
1839 data->account_name = g_strdup (account_name);
1840 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1841 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1842 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1843 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1844 data->references = g_strdup (priv->references);
1845 data->in_reply_to = g_strdup (priv->in_reply_to);
1846 if (priv->draft_msg) {
1847 data->draft_msg = g_object_ref (priv->draft_msg);
1848 } else if (priv->outbox_msg) {
1849 data->draft_msg = g_object_ref (priv->outbox_msg);
1851 data->draft_msg = NULL;
1854 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1856 gtk_text_buffer_get_bounds (buf, &b, &e);
1857 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1859 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1860 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1862 data->html_body = NULL;
1864 /* deep-copy the data */
1865 att_iter = tny_list_create_iterator (priv->attachments);
1866 data->attachments = NULL;
1867 while (!tny_iterator_is_done (att_iter)) {
1868 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1869 if (!(TNY_IS_MIME_PART(part))) {
1870 g_warning ("strange data in attachment list");
1871 g_object_unref (part);
1872 tny_iterator_next (att_iter);
1875 data->attachments = g_list_append (data->attachments,
1877 tny_iterator_next (att_iter);
1879 g_object_unref (att_iter);
1881 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1882 att_iter = tny_list_create_iterator (priv->images);
1883 data->images = NULL;
1884 while (!tny_iterator_is_done (att_iter)) {
1885 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1887 if (!(TNY_IS_MIME_PART(part))) {
1888 g_warning ("strange data in attachment list");
1889 g_object_unref (part);
1890 tny_iterator_next (att_iter);
1893 cid = tny_mime_part_get_content_id (part);
1895 gchar *image_tag_id;
1896 GtkTextTag *image_tag;
1898 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1899 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1900 g_free (image_tag_id);
1902 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1904 ((gtk_text_iter_has_tag (&iter, image_tag))||
1905 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1906 data->images = g_list_append (data->images,
1907 g_object_ref (part));
1909 g_object_unref (part);
1910 tny_iterator_next (att_iter);
1912 g_object_unref (att_iter);
1914 data->priority_flags = priv->priority_flags;
1921 unref_gobject (GObject *obj, gpointer data)
1923 if (!G_IS_OBJECT(obj))
1925 g_object_unref (obj);
1929 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1932 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1940 g_free (data->from);
1941 g_free (data->subject);
1942 g_free (data->plain_body);
1943 g_free (data->html_body);
1944 g_free (data->account_name);
1945 g_free (data->references);
1946 g_free (data->in_reply_to);
1948 if (data->draft_msg != NULL) {
1949 g_object_unref (data->draft_msg);
1950 data->draft_msg = NULL;
1953 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1954 g_list_free (data->attachments);
1955 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1956 g_list_free (data->images);
1958 g_slice_free (MsgData, data);
1962 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1964 guint64 *parts_size)
1966 ModestMsgEditWindowPrivate *priv;
1968 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1970 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1972 /* TODO: add images */
1973 *parts_size += priv->images_size;
1974 *parts_count += priv->images_count;
1979 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1982 ModestMsgEditWindowPrivate *priv = NULL;
1983 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1985 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1987 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1989 return MODEST_MSG_EDIT_FORMAT_HTML;
1991 return MODEST_MSG_EDIT_FORMAT_TEXT;
1995 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1996 ModestMsgEditFormat format)
1998 ModestMsgEditWindowPrivate *priv;
1999 ModestWindowPrivate *parent_priv;
2001 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2002 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2003 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2006 case MODEST_MSG_EDIT_FORMAT_HTML:
2007 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2008 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
2010 case MODEST_MSG_EDIT_FORMAT_TEXT:
2011 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2012 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
2015 g_return_if_reached ();
2019 ModestMsgEditFormatState *
2020 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2022 ModestMsgEditFormatState *format_state = NULL;
2023 ModestMsgEditWindowPrivate *priv;
2024 WPTextBufferFormat *buffer_format;
2026 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2028 buffer_format = g_new0 (WPTextBufferFormat, 1);
2029 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2031 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2033 format_state = g_new0 (ModestMsgEditFormatState, 1);
2034 format_state->bold = buffer_format->bold&0x1;
2035 format_state->italics = buffer_format->italic&0x1;
2036 format_state->bullet = buffer_format->bullet&0x1;
2037 format_state->color = buffer_format->color;
2038 format_state->font_size = buffer_format->font_size;
2039 format_state->font_family = wp_get_font_name (buffer_format->font);
2040 format_state->justification = buffer_format->justification;
2041 g_free (buffer_format);
2043 return format_state;
2048 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2049 const ModestMsgEditFormatState *format_state)
2051 ModestMsgEditWindowPrivate *priv;
2052 WPTextBufferFormat *buffer_format;
2053 WPTextBufferFormat *current_format;
2055 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2056 g_return_if_fail (format_state != NULL);
2058 buffer_format = g_new0 (WPTextBufferFormat, 1);
2059 current_format = g_new0 (WPTextBufferFormat, 1);
2061 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2062 gtk_widget_grab_focus (priv->msg_body);
2063 buffer_format->bold = (format_state->bold != FALSE);
2064 buffer_format->italic = (format_state->italics != FALSE);
2065 buffer_format->color = format_state->color;
2066 buffer_format->font_size = format_state->font_size;
2067 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2068 buffer_format->justification = format_state->justification;
2069 buffer_format->bullet = format_state->bullet;
2071 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2073 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2074 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2075 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2076 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2077 buffer_format->cs.font = (buffer_format->font != current_format->font);
2078 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2079 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2081 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2082 if (buffer_format->cs.bold) {
2083 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2084 GINT_TO_POINTER (buffer_format->bold&0x1));
2086 if (buffer_format->cs.italic) {
2087 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2088 GINT_TO_POINTER (buffer_format->italic&0x1));
2090 if (buffer_format->cs.color) {
2091 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2092 GINT_TO_POINTER (&(buffer_format->color)));
2094 if (buffer_format->cs.font_size) {
2095 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2096 GINT_TO_POINTER (buffer_format->font_size));
2098 if (buffer_format->cs.justification) {
2099 switch (buffer_format->justification) {
2100 case GTK_JUSTIFY_LEFT:
2101 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2102 GINT_TO_POINTER(TRUE));
2104 case GTK_JUSTIFY_CENTER:
2105 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2106 GINT_TO_POINTER(TRUE));
2108 case GTK_JUSTIFY_RIGHT:
2109 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2110 GINT_TO_POINTER(TRUE));
2117 if (buffer_format->cs.font) {
2118 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2119 GINT_TO_POINTER (buffer_format->font));
2121 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2122 if (buffer_format->cs.bullet) {
2123 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2124 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2126 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2128 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2130 g_free (buffer_format);
2131 g_free (current_format);
2133 /* Check dimming rules */
2134 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2135 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2139 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2141 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2143 ModestWindowPrivate *parent_priv;
2144 ModestMsgEditWindowPrivate *priv;
2146 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2147 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2149 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2150 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2151 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2152 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2154 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2155 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2156 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2159 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2161 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2162 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2164 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2165 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2167 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2168 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2171 switch (buffer_format->justification)
2173 case GTK_JUSTIFY_LEFT:
2174 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2176 case GTK_JUSTIFY_CENTER:
2177 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2179 case GTK_JUSTIFY_RIGHT:
2180 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2187 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2189 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2190 G_CALLBACK (modest_msg_edit_window_color_button_change),
2192 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2193 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2194 G_CALLBACK (modest_msg_edit_window_color_button_change),
2197 if (priv->current_size_index != buffer_format->font_size) {
2201 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2202 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2206 priv->current_size_index = buffer_format->font_size;
2208 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2209 markup = g_strconcat ("<span font_family='Sans'>",
2210 size_text, "</span>", NULL);
2212 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2216 gtk_tree_path_free (path);
2219 if (priv->current_face_index != buffer_format->font) {
2223 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2224 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2228 priv->current_face_index = buffer_format->font;
2229 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2230 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2231 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2238 g_free (buffer_format);
2244 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2246 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2247 ModestMsgEditWindowPrivate *priv;
2248 GtkWidget *dialog = NULL;
2250 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2251 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2253 dialog = hildon_color_chooser_new ();
2254 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2255 g_free (buffer_format);
2257 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2259 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2260 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2263 gtk_widget_destroy (dialog);
2268 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2270 ModestMsgEditWindowPrivate *priv;
2271 GtkWidget *dialog = NULL;
2272 GdkColor *old_color = NULL;
2274 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2275 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2277 dialog = hildon_color_chooser_new ();
2278 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2280 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2282 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2283 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2285 gtk_widget_destroy (dialog);
2290 create_stream_for_uri (const gchar* uri)
2295 TnyStream *result = NULL;
2297 GnomeVFSHandle *handle = NULL;
2298 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2299 if (test == GNOME_VFS_OK) {
2300 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2301 /* Streams over OBEX (Bluetooth) are not seekable but
2302 * we expect them to be (we might need to read them
2303 * several times). So if this is a Bluetooth URI just
2304 * read the whole file into memory (this is not a fast
2305 * protocol so we can assume that these files are not
2306 * going to be very big) */
2307 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2308 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2309 TnyStream *memstream = tny_camel_mem_stream_new ();
2310 tny_stream_write_to_stream (vfssstream, memstream);
2311 g_object_unref (vfssstream);
2314 result = vfssstream;
2322 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2325 ModestMsgEditWindowPrivate *priv;
2326 GtkWidget *dialog = NULL;
2328 GSList *uris = NULL;
2329 GSList *uri_node = NULL;
2331 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2333 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2334 _("mcen_ia_select_inline_image_title"),
2335 (GtkWindow *) window,
2336 GTK_FILE_CHOOSER_ACTION_OPEN);
2337 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2339 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2341 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2342 GTK_WINDOW (dialog), GTK_WINDOW (window));
2344 response = gtk_dialog_run (GTK_DIALOG (dialog));
2346 case GTK_RESPONSE_OK:
2348 gchar *current_folder;
2349 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2350 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2351 if (current_folder && current_folder != '\0') {
2353 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2354 current_folder, &err);
2356 g_debug ("Error storing latest used folder: %s", err->message);
2360 g_free (current_folder);
2366 gtk_widget_destroy (dialog);
2368 g_object_ref (window);
2369 /* The operation could take some time so allow the dialog to be closed */
2370 while (gtk_events_pending ())
2371 gtk_main_iteration ();
2373 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2375 GnomeVFSHandle *handle = NULL;
2376 GnomeVFSResult result;
2377 GtkTextIter position;
2378 GtkTextMark *insert_mark;
2380 uri = (const gchar *) uri_node->data;
2381 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2382 if (result == GNOME_VFS_OK) {
2384 GnomeVFSFileInfo *info;
2385 gchar *filename, *basename, *escaped_filename;
2386 TnyMimePart *mime_part;
2388 const gchar *mime_type = NULL;
2389 GnomeVFSURI *vfs_uri;
2390 guint64 stream_size;
2392 gnome_vfs_close (handle);
2393 vfs_uri = gnome_vfs_uri_new (uri);
2395 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2396 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2397 g_free (escaped_filename);
2398 gnome_vfs_uri_unref (vfs_uri);
2399 info = gnome_vfs_file_info_new ();
2401 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2402 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2404 mime_type = gnome_vfs_file_info_get_mime_type (info);
2406 mime_part = tny_platform_factory_new_mime_part
2407 (modest_runtime_get_platform_factory ());
2409 TnyStream *stream = create_stream_for_uri (uri);
2411 if (stream == NULL) {
2413 modest_platform_information_banner (NULL, NULL,
2414 _FM("sfil_ib_opening_not_allowed"));
2416 g_object_unref (mime_part);
2417 gnome_vfs_file_info_unref (info);
2421 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2423 content_id = g_strdup_printf ("%d", priv->next_cid);
2424 tny_mime_part_set_content_id (mime_part, content_id);
2425 g_free (content_id);
2428 basename = g_path_get_basename (filename);
2429 tny_mime_part_set_filename (mime_part, basename);
2432 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2434 if (pixbuf != NULL) {
2435 priv->images_size += stream_size;
2436 priv->images_count ++;
2437 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2438 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2439 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2440 tny_mime_part_get_content_id (mime_part), pixbuf);
2441 g_object_unref (pixbuf);
2443 tny_list_prepend (priv->images, (GObject *) mime_part);
2444 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2446 modest_platform_information_banner (NULL, NULL,
2447 _("mail_ib_file_operation_failed"));
2451 g_object_unref (mime_part);
2452 gnome_vfs_file_info_unref (info);
2456 g_object_unref (window);
2460 on_attach_file_response (GtkDialog *dialog,
2464 GSList *uris = NULL;
2466 GnomeVFSFileSize total_size, allowed_size;
2467 ModestMsgEditWindow *window;
2468 ModestMsgEditWindowPrivate *priv;
2473 case GTK_RESPONSE_OK:
2475 gchar *current_folder;
2477 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2478 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2479 if (current_folder && current_folder != '\0') {
2481 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2482 current_folder, &err);
2484 g_debug ("Error storing latest used folder: %s", err->message);
2488 g_free (current_folder);
2495 window = MODEST_MSG_EDIT_WINDOW (user_data);
2496 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2498 /* allowed size is the maximum size - what's already there */
2499 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2500 &att_num, &att_size);
2501 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2504 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2506 const gchar *uri = (const gchar *) uri_node->data;
2509 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2511 if (total_size > allowed_size) {
2512 g_debug ("%s: total size: %u",
2513 __FUNCTION__, (unsigned int)total_size);
2516 allowed_size -= total_size;
2518 g_slist_foreach (uris, (GFunc) g_free, NULL);
2519 g_slist_free (uris);
2521 gtk_widget_destroy (GTK_WIDGET (dialog));
2525 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2527 GtkWidget *dialog = NULL;
2528 ModestMsgEditWindowPrivate *priv;
2531 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2533 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2535 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2538 dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
2539 _("mcen_ia_select_attachment_title"),
2540 (GtkWindow *) window,
2541 GTK_FILE_CHOOSER_ACTION_OPEN);
2542 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2543 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2544 if (conf_folder && conf_folder[0] != '\0') {
2545 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2548 /* Set the default folder to documents folder */
2549 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2552 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2553 ".documents", NULL);
2555 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2556 g_free (docs_folder);
2558 g_free (conf_folder);
2559 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2560 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2561 GTK_WINDOW (dialog), GTK_WINDOW (window));
2563 /* Connect to response & show */
2564 g_signal_connect (dialog, "response",
2565 G_CALLBACK (on_attach_file_response), window);
2566 gtk_widget_show (dialog);
2571 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2573 GnomeVFSFileSize allowed_size)
2576 GnomeVFSHandle *handle = NULL;
2577 ModestMsgEditWindowPrivate *priv;
2578 GnomeVFSResult result;
2579 GnomeVFSFileSize size = 0;
2580 g_return_val_if_fail (window, 0);
2581 g_return_val_if_fail (uri, 0);
2583 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2585 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2586 if (result == GNOME_VFS_OK) {
2587 TnyMimePart *mime_part;
2589 const gchar *mime_type = NULL;
2591 gchar *escaped_filename;
2594 GnomeVFSFileInfo *info;
2595 GnomeVFSURI *vfs_uri;
2597 gnome_vfs_close (handle);
2598 vfs_uri = gnome_vfs_uri_new (uri);
2601 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2602 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2603 g_free (escaped_filename);
2604 gnome_vfs_uri_unref (vfs_uri);
2606 info = gnome_vfs_file_info_new ();
2608 if (gnome_vfs_get_file_info (uri,
2610 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2612 mime_type = gnome_vfs_file_info_get_mime_type (info);
2613 mime_part = tny_platform_factory_new_mime_part
2614 (modest_runtime_get_platform_factory ());
2616 /* try to get the attachment's size; this may fail for weird
2617 * file systems, like obex, upnp... */
2618 if (allowed_size != 0 &&
2619 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2621 if (size > allowed_size) {
2622 modest_platform_information_banner (NULL, NULL,
2623 _("mail_ib_error_attachment_size"));
2628 g_debug ("%s: could not get attachment size", __FUNCTION__);
2630 stream = create_stream_for_uri (uri);
2632 if (stream == NULL) {
2634 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2636 g_object_unref (mime_part);
2638 gnome_vfs_file_info_unref (info);
2642 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2643 g_object_unref (stream);
2645 content_id = g_strdup_printf ("%d", priv->next_cid);
2646 tny_mime_part_set_content_id (mime_part, content_id);
2647 g_free (content_id);
2650 basename = g_path_get_basename (filename);
2651 tny_mime_part_set_filename (mime_part, basename);
2654 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2655 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2657 info->size == 0, info->size);
2658 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2659 gtk_widget_show_all (priv->attachments_caption);
2660 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2662 g_object_unref (mime_part);
2663 gnome_vfs_file_info_unref (info);
2670 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2673 ModestMsgEditWindowPrivate *priv;
2676 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2677 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2679 if (att_list == NULL) {
2680 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2681 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2682 g_object_unref (att_list);
2686 g_object_ref (att_list);
2689 if (tny_list_get_length (att_list) == 0) {
2690 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2692 gboolean dialog_response;
2693 gchar *message = NULL;
2694 gchar *filename = NULL;
2696 if (tny_list_get_length (att_list) == 1) {
2698 iter = tny_list_create_iterator (att_list);
2699 part = (TnyMimePart *) tny_iterator_get_current (iter);
2700 g_object_unref (iter);
2701 if (TNY_IS_MSG (part)) {
2702 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2704 filename = tny_header_dup_subject (header);
2705 g_object_unref (header);
2707 if (filename == NULL) {
2708 filename = g_strdup (_("mail_va_no_subject"));
2711 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2713 g_object_unref (part);
2715 filename = g_strdup ("");
2717 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2718 "emev_nc_delete_attachments",
2719 tny_list_get_length (att_list)), filename);
2722 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2726 if (dialog_response != GTK_RESPONSE_OK) {
2727 g_object_unref (att_list);
2731 for (iter = tny_list_create_iterator (att_list);
2732 !tny_iterator_is_done (iter);
2733 tny_iterator_next (iter)) {
2734 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2735 const gchar *att_id;
2736 tny_list_remove (priv->attachments, (GObject *) mime_part);
2738 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2740 if (tny_list_get_length (priv->attachments) == 0)
2741 gtk_widget_hide (priv->attachments_caption);
2742 att_id = tny_mime_part_get_content_id (mime_part);
2744 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2746 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2747 g_object_unref (mime_part);
2749 g_object_unref (iter);
2752 g_object_unref (att_list);
2754 /* if the last attachment has been removed, focus the Subject: field */
2755 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2756 gtk_widget_grab_focus (priv->subject_field);
2760 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2763 ModestMsgEditWindowPrivate *priv;
2766 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2768 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2770 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2772 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2776 font_size_clicked (GtkToolButton *button,
2777 ModestMsgEditWindow *window)
2779 ModestMsgEditWindowPrivate *priv;
2780 GtkWidget *selector, *dialog;
2782 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2784 selector = hildon_touch_selector_new ();
2785 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2786 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2788 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2789 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2790 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2792 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2796 WPTextBufferFormat format;
2798 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2800 memset (&format, 0, sizeof (format));
2801 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2803 format.cs.font_size = TRUE;
2804 format.cs.text_position = TRUE;
2805 format.cs.font = TRUE;
2806 format.font_size = new_index;
2807 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2809 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2810 GINT_TO_POINTER (new_index)))
2811 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2813 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2814 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2815 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2816 size_text, "</span>", NULL);
2818 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2822 gtk_widget_destroy (dialog);
2824 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2829 font_face_clicked (GtkToolButton *button,
2830 ModestMsgEditWindow *window)
2832 ModestMsgEditWindowPrivate *priv;
2833 GtkWidget *selector, *dialog;
2834 GtkCellRenderer *renderer;
2836 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2838 selector = hildon_touch_selector_new ();
2839 renderer = gtk_cell_renderer_text_new ();
2840 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2841 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2842 renderer, "family", 0, "text", 0, NULL);
2843 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2845 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2846 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2847 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2849 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2850 gint new_font_index;
2854 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2855 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2856 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2860 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2862 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2863 GINT_TO_POINTER(new_font_index)))
2864 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2866 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2867 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2869 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2873 gtk_tree_path_free (path);
2876 gtk_widget_destroy (dialog);
2878 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2883 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2886 ModestMsgEditWindowPrivate *priv = NULL;
2887 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2889 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2890 if (!priv->update_caption_visibility)
2893 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2895 gtk_widget_show (priv->cc_caption);
2897 gtk_widget_hide (priv->cc_caption);
2899 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2903 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2906 ModestMsgEditWindowPrivate *priv = NULL;
2907 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2909 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2910 if (!priv->update_caption_visibility)
2913 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2915 gtk_widget_show (priv->bcc_caption);
2917 gtk_widget_hide (priv->bcc_caption);
2919 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2923 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2924 ModestRecptEditor *editor)
2926 ModestMsgEditWindowPrivate *priv;
2928 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2929 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2931 /* we check for low-mem; in that case, show a warning, and don't allow
2932 * for the addressbook
2934 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2937 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2939 if (editor == NULL) {
2940 GtkWidget *view_focus, *parent;
2941 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2943 /* This code should be kept in sync with ModestRecptEditor. The
2944 textview inside the recpt editor is the one that really gets the
2945 focus. As it's inside a scrolled window, and this one inside the
2946 hbox recpt editor inherits from, we'll need to go up in the
2947 hierarchy to know if the text view is part of the recpt editor
2948 or if it's a different text entry */
2949 parent = gtk_widget_get_parent (view_focus);
2950 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2951 editor = MODEST_RECPT_EDITOR (parent);
2954 editor = MODEST_RECPT_EDITOR (priv->to_field);
2957 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2961 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2963 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2965 modest_msg_edit_window_open_addressbook (window, NULL);
2969 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2970 gboolean show_toolbar)
2972 ModestWindowPrivate *parent_priv;
2973 ModestMsgEditWindowPrivate *priv;
2975 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2976 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2977 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2979 /* We can not just use the code of
2980 modest_msg_edit_window_setup_toolbar because it has a
2981 mixture of both initialization and creation code. */
2983 gint current_format;
2984 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2985 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2986 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2987 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2989 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2992 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2997 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2998 TnyHeaderFlags priority_flags)
3000 ModestMsgEditWindowPrivate *priv;
3001 ModestWindowPrivate *parent_priv;
3003 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3005 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3006 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3008 if (priv->priority_flags != priority_flags) {
3009 GtkAction *priority_action = NULL;
3011 priv->priority_flags = priority_flags;
3013 switch (priority_flags) {
3014 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3015 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3016 MODEST_HEADER_ICON_HIGH,
3017 HILDON_ICON_SIZE_SMALL);
3018 gtk_widget_show (priv->priority_icon);
3019 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3020 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3022 case TNY_HEADER_FLAG_LOW_PRIORITY:
3023 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3024 MODEST_HEADER_ICON_LOW,
3025 HILDON_ICON_SIZE_SMALL);
3026 gtk_widget_show (priv->priority_icon);
3027 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3028 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3031 gtk_widget_hide (priv->priority_icon);
3032 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3033 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3036 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3037 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3039 gtk_widget_queue_resize (priv->subject_box);
3043 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3046 ModestMsgEditWindowPrivate *priv;
3047 ModestWindowPrivate *parent_priv;
3048 gint current_format;
3050 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3052 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3053 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3055 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3056 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3058 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3060 if (current_format != file_format) {
3061 switch (file_format) {
3062 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3063 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3064 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3065 if (parent_priv->toolbar)
3066 gtk_widget_show (parent_priv->toolbar);
3068 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3072 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3073 response = gtk_dialog_run (GTK_DIALOG (dialog));
3074 gtk_widget_destroy (dialog);
3075 if (response == GTK_RESPONSE_OK) {
3076 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3077 if (parent_priv->toolbar)
3078 gtk_widget_hide (parent_priv->toolbar);
3080 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3081 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3086 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3087 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3088 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3093 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3096 ModestMsgEditWindowPrivate *priv;
3097 WPTextBufferFormat oldfmt, fmt;
3098 gint old_position = 0;
3102 GdkColor *color = NULL;
3103 gboolean bold, bold_set, italic, italic_set;
3104 gboolean underline, underline_set;
3105 gboolean strikethrough, strikethrough_set;
3106 gboolean position_set;
3107 gboolean font_size_set, font_set, color_set;
3110 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3111 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3113 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3114 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3115 GTK_WINDOW(dialog), GTK_WINDOW (window));
3117 /* First we get the currently selected font information */
3118 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3120 switch (oldfmt.text_position) {
3121 case TEXT_POSITION_NORMAL:
3124 case TEXT_POSITION_SUPERSCRIPT:
3132 g_object_set (G_OBJECT (dialog),
3133 "bold", oldfmt.bold != FALSE,
3134 "bold-set", !oldfmt.cs.bold,
3135 "underline", oldfmt.underline != FALSE,
3136 "underline-set", !oldfmt.cs.underline,
3137 "italic", oldfmt.italic != FALSE,
3138 "italic-set", !oldfmt.cs.italic,
3139 "strikethrough", oldfmt.strikethrough != FALSE,
3140 "strikethrough-set", !oldfmt.cs.strikethrough,
3141 "color", &oldfmt.color,
3142 "color-set", !oldfmt.cs.color,
3143 "size", wp_font_size[oldfmt.font_size],
3144 "size-set", !oldfmt.cs.font_size,
3145 "position", old_position,
3146 "position-set", !oldfmt.cs.text_position,
3147 "family", wp_get_font_name (oldfmt.font),
3148 "family-set", !oldfmt.cs.font,
3151 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3152 GTK_WINDOW (dialog), GTK_WINDOW (window));
3153 gtk_widget_show_all (dialog);
3154 priv->font_dialog = dialog;
3155 response = gtk_dialog_run (GTK_DIALOG (dialog));
3156 priv->font_dialog = NULL;
3157 if (response == GTK_RESPONSE_OK) {
3159 g_object_get( dialog,
3161 "bold-set", &bold_set,
3162 "underline", &underline,
3163 "underline-set", &underline_set,
3165 "italic-set", &italic_set,
3166 "strikethrough", &strikethrough,
3167 "strikethrough-set", &strikethrough_set,
3169 "color-set", &color_set,
3171 "size-set", &font_size_set,
3172 "family", &font_name,
3173 "family-set", &font_set,
3174 "position", &position,
3175 "position-set", &position_set,
3180 if (response == GTK_RESPONSE_OK) {
3181 memset(&fmt, 0, sizeof(fmt));
3187 fmt.italic = italic;
3188 fmt.cs.italic = TRUE;
3190 if (underline_set) {
3191 fmt.underline = underline;
3192 fmt.cs.underline = TRUE;
3194 if (strikethrough_set) {
3195 fmt.strikethrough = strikethrough;
3196 fmt.cs.strikethrough = TRUE;
3201 ? TEXT_POSITION_NORMAL
3202 : ( ( position == 1 )
3203 ? TEXT_POSITION_SUPERSCRIPT
3204 : TEXT_POSITION_SUBSCRIPT );
3205 fmt.cs.text_position = TRUE;
3206 fmt.font_size = oldfmt.font_size;
3210 fmt.cs.color = TRUE;
3213 fmt.font = wp_get_font_index(font_name,
3218 if (font_size_set) {
3219 fmt.cs.font_size = TRUE;
3220 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3222 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3223 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3225 gtk_widget_destroy (dialog);
3227 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3231 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3233 ModestMsgEditWindowPrivate *priv;
3234 ModestWindowPrivate *parent_priv;
3235 gboolean was_rich_text, is_rich_text;
3237 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3238 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3239 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3241 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3243 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3245 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3247 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3249 gtk_widget_show (parent_priv->toolbar);
3251 gtk_widget_hide (parent_priv->toolbar);
3254 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3255 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3259 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3261 ModestMsgEditWindowPrivate *priv;
3263 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3264 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3266 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3268 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3269 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3274 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3276 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3278 priv->can_undo = can_undo;
3282 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3284 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3286 priv->can_redo = can_redo;
3290 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3292 ModestMsgEditWindowPrivate *priv;
3293 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3294 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3296 return priv->can_undo;
3300 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3302 ModestMsgEditWindowPrivate *priv;
3303 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3304 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3306 return priv->can_redo;
3311 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3314 GtkTextIter match_start, match_end;
3316 if (image_id == NULL)
3319 gtk_text_buffer_get_start_iter (buffer, &iter);
3321 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3322 GSList *tags = gtk_text_iter_get_tags (&match_start);
3324 for (node = tags; node != NULL; node = g_slist_next (node)) {
3325 GtkTextTag *tag = (GtkTextTag *) node->data;
3326 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3327 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3328 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3330 offset = gtk_text_iter_get_offset (&match_start);
3331 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3332 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3336 gtk_text_iter_forward_char (&iter);
3341 message_is_empty (ModestMsgEditWindow *window)
3343 ModestMsgEditWindowPrivate *priv = NULL;
3345 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3346 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3348 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3349 * so we can ignore markup.
3351 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3354 count = gtk_text_buffer_get_char_count (buf);
3360 msg_body_focus (GtkWidget *focus,
3361 GdkEventFocus *event,
3365 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3366 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3367 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3372 recpt_field_changed (GtkTextBuffer *buffer,
3373 ModestMsgEditWindow *editor)
3375 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3376 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3380 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3382 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3383 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3387 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3390 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3391 GtkTextBuffer *buffer;
3393 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3394 gtk_text_buffer_set_modified (buffer, modified);
3395 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3396 gtk_text_buffer_set_modified (buffer, modified);
3397 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3398 gtk_text_buffer_set_modified (buffer, modified);
3399 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3403 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3405 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3406 const char *account_name;
3407 GtkTextBuffer *buffer;
3409 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3410 if (gtk_text_buffer_get_modified (buffer))
3412 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3413 if (gtk_text_buffer_get_modified (buffer))
3415 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3416 if (gtk_text_buffer_get_modified (buffer))
3418 if (gtk_text_buffer_get_modified (priv->text_buffer))
3421 account_name = modest_selector_get_active_id (priv->from_field);
3422 if (priv->original_mailbox) {
3423 if (!account_name || strcmp (account_name, priv->original_mailbox))
3425 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3436 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3438 ModestMsgEditWindowPrivate *priv = NULL;
3439 GSList *address_list = NULL;
3441 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3442 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3444 /* check if there's no recipient added */
3445 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3446 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3447 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3448 /* no recipient contents, then select contacts */
3449 modest_msg_edit_window_open_addressbook (window, NULL);
3454 g_object_ref (window);
3455 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3456 (add_to_addressbook) ? &address_list : NULL)) {
3457 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3458 g_object_unref (window);
3461 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3462 (add_to_addressbook) ? &address_list : NULL)) {
3463 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3464 g_object_unref (window);
3467 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3468 (add_to_addressbook) ? &address_list : NULL)) {
3469 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3470 g_object_unref (window);
3474 /* Add contacts to address book */
3475 if (add_to_addressbook && address_list)
3476 modest_address_book_add_address_list (address_list);
3478 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3479 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3480 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3481 g_object_unref (window);
3488 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3490 GSList *recipients = NULL;
3491 ModestMsgEditWindowPrivate *priv;
3492 gchar *joined, *after_remove, *to, *cc, *bcc;
3494 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3496 /* First of all check names */
3497 if (!modest_msg_edit_window_check_names (self, FALSE))
3500 if (!modest_msg_edit_window_has_pending_addresses (self))
3503 /* Don't add the from obviously */
3504 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3505 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3506 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3508 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3513 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3516 recipients = modest_text_utils_split_addresses_list (after_remove);
3517 g_free (after_remove);
3520 /* Offer the user to add recipients to the address book */
3521 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3522 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3527 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3528 ModestMsgEditWindow *window)
3530 modest_msg_edit_window_offer_attach_file (window);
3534 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3536 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3538 return priv->clipboard_text;
3542 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3544 ModestMsgEditWindow *window)
3546 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3547 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3550 /* It could happen that the window was already closed */
3551 if (!GTK_WIDGET_VISIBLE (window))
3554 g_object_ref (window);
3555 text = gtk_clipboard_wait_for_text (selection_clipboard);
3557 if (priv->clipboard_text != NULL) {
3558 g_free (priv->clipboard_text);
3560 priv->clipboard_text = text;
3562 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3564 g_object_unref (window);
3567 static gboolean clipboard_owner_change_idle (gpointer userdata)
3569 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3570 ModestMsgEditWindowPrivate *priv;
3572 gdk_threads_enter ();
3573 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3574 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3576 priv->clipboard_owner_idle = 0;
3577 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3578 gdk_threads_leave ();
3584 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3586 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3587 if (priv->clipboard_owner_idle == 0) {
3588 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3589 clipboard_owner_change_idle,
3590 g_object_ref (window),
3596 subject_field_move_cursor (GtkEntry *entry,
3597 GtkMovementStep step,
3602 /* It could happen that the window was already closed */
3603 if (!GTK_WIDGET_VISIBLE (window))
3606 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3610 update_window_title (ModestMsgEditWindow *window)
3612 ModestMsgEditWindowPrivate *priv = NULL;
3613 const gchar *subject;
3615 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3616 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3617 if (subject == NULL || subject[0] == '\0')
3618 subject = _("mail_va_new_email");
3620 modest_window_set_title (MODEST_WINDOW (window), subject);
3626 body_insert_text (GtkTextBuffer *buffer,
3627 GtkTextIter *location,
3630 ModestMsgEditWindow *window)
3632 GtkTextIter end_iter;
3639 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3641 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3643 offset = gtk_text_iter_get_offset (&end_iter);
3644 line = gtk_text_iter_get_line (&end_iter);
3648 while (text_offset < text + len) {
3649 if (*text_offset == '\n')
3651 if (text_lines + line >= MAX_BODY_LINES) {
3652 len = text_offset - text;
3658 utf8_len = g_utf8_strlen (text, len);
3660 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3661 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3662 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3667 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3669 /* Prevent endless recursion */
3670 result = g_strndup (text, utf8_end - text);
3671 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3672 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3673 (gpointer) result, (gpointer) (utf8_end - text),
3675 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3679 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3680 if (priv->max_chars_banner == NULL) {
3681 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3682 _CS("ckdg_ib_maximum_characters_reached"));
3683 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3689 subject_field_changed (GtkEditable *editable,
3690 ModestMsgEditWindow *window)
3692 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3693 update_window_title (window);
3694 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3695 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3696 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3699 subject_field_insert_text (GtkEditable *editable,
3701 gint new_text_length,
3703 ModestMsgEditWindow *window)
3705 GString *result = g_string_new ("");
3707 gint result_len = 0;
3708 const gchar *entry_text = NULL;
3711 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3712 old_length = g_utf8_strlen (entry_text, -1);
3714 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3715 gunichar c = g_utf8_get_char_validated (current, 8);
3716 /* Invalid unichar, stop */
3722 result = g_string_append_unichar (result, c);
3726 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3727 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3730 /* Prevent endless recursion */
3731 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3732 g_signal_emit_by_name (editable, "insert-text",
3733 (gpointer) result->str, (gpointer) result->len,
3734 (gpointer) position, (gpointer) window);
3735 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3739 if (result_len + old_length > 1000) {
3740 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3741 _CS("ckdg_ib_maximum_characters_reached"));
3743 g_string_free (result, TRUE);
3747 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3750 ModestMsgEditWindowPrivate *priv = NULL;
3752 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3753 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3755 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3758 gtk_widget_show_all (priv->isearch_toolbar);
3759 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3761 gtk_widget_hide_all (priv->isearch_toolbar);
3762 gtk_widget_grab_focus (priv->msg_body);
3767 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3769 GtkTextIter *match_start,
3770 GtkTextIter *match_end)
3772 GtkTextIter end_iter;
3773 gchar *str_casefold;
3776 gchar *range_casefold;
3779 gboolean result = FALSE;
3786 gtk_text_iter_forward_to_end (&end_iter);
3788 str_casefold = g_utf8_casefold (str, -1);
3789 str_chars_n = strlen (str);
3791 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3792 range_casefold = g_utf8_casefold (range_text, -1);
3793 range_chars_n = strlen (range_casefold);
3795 if (range_chars_n < str_chars_n) {
3796 g_free (str_casefold);
3797 g_free (range_text);
3798 g_free (range_casefold);
3802 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3803 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3804 if (!g_utf8_collate (range_subtext, str_casefold)) {
3805 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3807 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3808 match_start, match_end, NULL)) {
3809 g_debug ("Matched string with collate, but not matched in model");
3811 g_free (found_text);
3813 g_free (range_subtext);
3817 g_free (str_casefold);
3818 g_free (range_text);
3819 g_free (range_casefold);
3826 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
3827 ModestMsgEditWindow *window)
3829 const gchar *current_search = NULL;
3830 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3832 GtkTextIter selection_start, selection_end;
3833 GtkTextIter match_start, match_end;
3834 gboolean continue_search = FALSE;
3836 if (message_is_empty (window)) {
3837 g_free (priv->last_search);
3838 priv->last_search = NULL;
3839 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3843 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
3844 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3845 g_free (priv->last_search);
3846 priv->last_search = NULL;
3847 /* Information banner about empty search */
3848 modest_platform_system_banner (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3852 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3853 continue_search = TRUE;
3855 g_free (priv->last_search);
3856 priv->last_search = g_strdup (current_search);
3859 if (continue_search) {
3860 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3861 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3862 &match_start, &match_end);
3864 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3866 GtkTextIter buffer_start;
3867 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3868 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3869 &match_start, &match_end);
3871 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3874 /* Mark as selected the string found in search */
3876 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3877 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3878 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3880 g_free (priv->last_search);
3881 priv->last_search = NULL;
3886 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3888 ModestMsgEditWindowPrivate *priv;
3890 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3895 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3898 ModestMsgEditWindowPrivate *priv;
3900 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3905 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
3906 ModestMsgEditWindow *window)
3908 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
3912 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3915 ModestMsgEditWindowPrivate *priv;
3916 TnyHeader *header = NULL;
3918 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3919 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3921 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3923 if (priv->draft_msg != NULL) {
3924 g_object_unref (priv->draft_msg);
3927 if (draft != NULL) {
3928 g_object_ref (draft);
3929 header = tny_msg_get_header (draft);
3930 if (priv->msg_uid) {
3931 g_free (priv->msg_uid);
3932 priv->msg_uid = NULL;
3934 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3937 priv->draft_msg = draft;
3941 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3942 GtkTextIter *start, GtkTextIter *end,
3945 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3946 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3949 if (tag == NULL) return;
3950 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3951 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3952 replace_with_images (window, priv->images);
3957 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3960 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3962 g_return_if_fail (TNY_IS_MIME_PART (part));
3963 tny_list_prepend (priv->attachments, (GObject *) part);
3964 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3965 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3966 gtk_widget_show_all (priv->attachments_caption);
3967 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3971 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3973 ModestMsgEditWindowPrivate *priv;
3975 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3976 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3978 return priv->msg_uid;
3982 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3983 ModestMsgEditWindowWidgetType widget_type)
3985 ModestMsgEditWindowPrivate *priv;
3987 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3988 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3990 switch (widget_type) {
3991 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3992 return priv->msg_body;
3994 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3995 return priv->to_field;
3997 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3998 return priv->cc_field;
4000 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4001 return priv->bcc_field;
4003 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4004 return priv->subject_field;
4006 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4007 return priv->attachments_view;
4015 remove_tags (WPTextBuffer *buffer)
4017 GtkTextIter start, end;
4019 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4020 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4022 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4026 on_account_removed (TnyAccountStore *account_store,
4027 TnyAccount *account,
4030 /* Do nothing if it's a store account, because we use the
4031 transport to send the messages */
4032 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4033 const gchar *parent_acc = NULL;
4034 const gchar *our_acc = NULL;
4036 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4037 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4038 /* Close this window if I'm showing a message of the removed account */
4039 if (strcmp (parent_acc, our_acc) == 0)
4040 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4045 update_signature (ModestMsgEditWindow *self,
4046 const gchar *old_account,
4047 const gchar *new_account)
4049 ModestMsgEditWindowPrivate *priv;
4050 gboolean has_old_signature, has_new_signature;
4052 ModestAccountMgr *mgr;
4055 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4057 gtk_text_buffer_begin_user_action (priv->text_buffer);
4059 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4060 mgr = modest_runtime_get_account_mgr ();
4064 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4065 if (has_old_signature) {
4066 GtkTextIter match_start, match_end;
4068 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4069 seems that the search has some problems
4070 with the blank space at the end */
4071 if (gtk_text_iter_forward_search (&iter, "--",
4072 GTK_TEXT_SEARCH_TEXT_ONLY,
4073 &match_start, NULL, NULL)) {
4074 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4075 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4077 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4078 &match_start, &match_end, NULL)) {
4082 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4087 priv->last_from_account = modest_selector_get_active_id (priv->from_field);
4088 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4089 if (has_new_signature) {
4091 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4092 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4094 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4095 g_free (full_signature);
4098 gtk_text_buffer_end_user_action (priv->text_buffer);
4101 static void update_branding (ModestMsgEditWindow *self,
4102 const gchar *new_account)
4104 ModestMsgEditWindowPrivate *priv;
4105 ModestAccountMgr *mgr;
4106 const GdkPixbuf *new_icon = NULL;
4107 gchar *new_label = NULL;
4108 gboolean show = FALSE;
4110 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4112 mgr = modest_runtime_get_account_mgr ();
4114 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4116 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4117 gtk_widget_show (priv->brand_icon);
4120 gtk_widget_hide (priv->brand_icon);
4123 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4124 gtk_widget_show (priv->brand_label);
4128 gtk_widget_hide (priv->brand_label);
4132 gtk_widget_show (priv->brand_container);
4134 gtk_widget_hide (priv->brand_container);
4138 from_field_changed (GtkWidget *button,
4139 ModestMsgEditWindow *self)
4141 ModestMsgEditWindowPrivate *priv;
4142 gchar *old_account, *new_account;
4144 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4146 old_account = priv->last_from_account;
4147 new_account = modest_selector_get_active_id (priv->from_field);
4150 g_warning ("%s, could not get the new account", __FUNCTION__);
4154 /* If the From is the same do nothing */
4155 if (old_account && new_account && !strcmp (old_account, new_account))
4158 priv->last_from_account = new_account;
4160 update_signature (self, old_account, new_account);
4161 update_branding (self, new_account);
4165 typedef struct _MessageSettingsHelper {
4166 ModestMsgEditWindow *window;
4167 GSList *priority_group;
4168 GSList *format_group;
4169 GtkToggleButton *current_priority;
4170 GtkToggleButton *current_format;
4171 } MessageSettingsHelper;
4174 on_priority_toggle (GtkToggleButton *button,
4175 MessageSettingsHelper *helper)
4178 ModestMsgEditWindowPrivate *priv;
4180 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4181 if (gtk_toggle_button_get_active (button)) {
4183 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4184 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4185 if ((node_button != button) &&
4186 gtk_toggle_button_get_active (node_button)) {
4187 gtk_toggle_button_set_active (node_button, FALSE);
4190 helper->current_priority = button;
4192 gboolean found = FALSE;
4193 /* If no one is active, activate it again */
4194 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4195 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4196 if (gtk_toggle_button_get_active (node_button)) {
4202 gtk_toggle_button_set_active (button, TRUE);
4208 on_format_toggle (GtkToggleButton *button,
4209 MessageSettingsHelper *helper)
4212 ModestMsgEditWindowPrivate *priv;
4214 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4215 if (gtk_toggle_button_get_active (button)) {
4217 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4218 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4219 if ((node_button != button) &&
4220 gtk_toggle_button_get_active (node_button)) {
4221 gtk_toggle_button_set_active (node_button, FALSE);
4224 helper->current_format = button;
4226 gboolean found = FALSE;
4227 /* If no one is active, activate it again */
4228 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4229 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4230 if (gtk_toggle_button_get_active (node_button)) {
4236 gtk_toggle_button_set_active (button, TRUE);
4243 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4248 GtkWidget *priority_hbox;
4249 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4250 GtkWidget *captioned;
4251 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4252 GtkWidget *format_hbox;
4253 GtkWidget *html_toggle, *text_toggle;
4254 ModestMsgEditWindowPrivate *priv;
4255 MessageSettingsHelper helper = {0,};
4257 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4258 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4259 helper.window = window;
4260 helper.priority_group = NULL;
4261 helper.format_group = NULL;
4263 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4264 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4266 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4267 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4268 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4269 vbox = gtk_vbox_new (FALSE, 0);
4270 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4271 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4272 gtk_container_add (GTK_CONTAINER (align), vbox);
4273 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4274 gtk_widget_show (align);
4275 gtk_widget_show (vbox);
4277 /* Priority toggles */
4278 priority_hbox = gtk_hbox_new (TRUE, 0);
4279 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4280 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4281 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4282 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4283 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4284 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4285 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4286 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4287 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4288 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4289 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4290 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4291 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4292 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4293 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4294 gtk_widget_show_all (priority_hbox);
4295 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4296 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4297 gtk_widget_show (captioned);
4298 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4300 /* format toggles */
4301 format_hbox = gtk_hbox_new (TRUE, 0);
4302 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4303 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4304 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4305 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4306 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4307 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4308 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4309 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4310 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4311 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4312 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4313 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4314 gtk_widget_show_all (format_hbox);
4315 gtk_widget_show (format_hbox);
4316 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4319 g_object_unref (title_sizegroup);
4320 g_object_unref (value_sizegroup);
4322 /* Set current values */
4323 switch (priv->priority_flags) {
4324 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4325 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4326 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4328 case TNY_HEADER_FLAG_LOW_PRIORITY:
4329 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4330 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4333 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4334 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4338 switch (modest_msg_edit_window_get_format (window)) {
4339 case MODEST_MSG_EDIT_FORMAT_TEXT:
4340 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4341 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4343 case MODEST_MSG_EDIT_FORMAT_HTML:
4345 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4346 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4350 /* Signal connects */
4351 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4352 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4353 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4354 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4355 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4357 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4358 GTK_WINDOW (dialog), GTK_WINDOW (window));
4360 /* Save settings if the user clicked on done */
4361 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4362 TnyHeaderFlags flags;
4363 ModestMsgEditFormat old_format, new_format;
4365 /* Set priority flags */
4366 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4367 if (priv->priority_flags != flags)
4368 modest_msg_edit_window_set_priority_flags (window, flags);
4370 /* Set edit format */
4371 old_format = modest_msg_edit_window_get_format (window);
4372 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4373 if (old_format != new_format) {
4374 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4375 modest_msg_edit_window_set_file_format (window, file_format);
4379 gtk_widget_destroy (dialog);
4380 g_slist_free (helper.priority_group);
4384 on_message_settings (GtkAction *action,
4385 ModestMsgEditWindow *window)
4387 modest_msg_edit_window_show_msg_settings_dialog (window);
4391 on_cc_button_toggled (GtkWidget *button,
4392 ModestMsgEditWindow *window)
4394 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4396 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4397 modest_togglable_get_active (button));
4401 on_bcc_button_toggled (GtkWidget *button,
4402 ModestMsgEditWindow *window)
4404 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4406 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4407 modest_togglable_get_active (button));
4411 setup_menu (ModestMsgEditWindow *self)
4413 ModestMsgEditWindowPrivate *priv = NULL;
4415 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4417 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4419 /* Settings menu buttons */
4420 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4421 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4423 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4424 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4425 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4426 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4427 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4428 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4430 priv->cc_button = hildon_check_button_new (0);
4431 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4432 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4434 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4435 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4436 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4438 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4439 _("mcen_me_editor_showbcc"));
4440 modest_togglable_set_active (priv->bcc_button,
4442 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4444 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4445 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4447 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4448 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4449 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4450 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4451 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4453 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4454 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4455 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4456 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4457 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4459 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4460 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4465 emit_open_addressbook (GtkButton *button,
4466 ModestRecptEditor *editor)
4468 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4472 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4473 const gchar *label, GtkWidget *control)
4475 GtkWidget *abook_button;
4478 GtkWidget *label_widget;
4480 box = gtk_hbox_new (FALSE, 0);
4482 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4483 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4485 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4486 label_widget = gtk_label_new (label);
4487 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4488 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4490 gtk_container_add (GTK_CONTAINER (align), abook_button);
4491 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4492 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4493 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4494 if (title_size_group)
4495 gtk_size_group_add_widget (title_size_group, label_widget);
4496 if (value_size_group)
4497 gtk_size_group_add_widget (value_size_group, control);
4499 g_signal_connect (G_OBJECT (abook_button), "clicked",
4500 G_CALLBACK (emit_open_addressbook), control);
4506 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4508 ModestMsgEditWindowPrivate *priv = NULL;
4510 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4512 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4513 priv->max_chars_banner = NULL;
4517 has_pending_addresses (ModestRecptEditor *recpt_editor)
4519 const gchar *recipients = NULL;
4520 GSList *start_indexes = NULL, *end_indexes = NULL;
4521 GSList *current_start, *current_end;
4522 GtkTextBuffer *buffer;
4523 gint offset_delta = 0;
4525 gboolean has_recipients_to_add = FALSE;
4527 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4528 last_length = g_utf8_strlen (recipients, -1);
4529 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4534 current_start = start_indexes;
4535 current_end = end_indexes;
4536 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4538 while (current_start && !has_recipients_to_add) {
4540 gchar *start_ptr, *end_ptr;
4541 gint start_pos, end_pos;
4543 start_pos = (*((gint*) current_start->data)) + offset_delta;
4544 end_pos = (*((gint*) current_end->data)) + offset_delta;
4546 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4547 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4549 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4551 if (modest_text_utils_validate_recipient (address, NULL)) {
4552 if (!modest_address_book_has_address (address)) {
4553 has_recipients_to_add = TRUE;
4556 current_start = g_slist_next (current_start);
4557 current_end = g_slist_next (current_end);
4559 return has_recipients_to_add;
4563 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4565 ModestMsgEditWindowPrivate *priv = NULL;
4567 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4569 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4571 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4572 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4573 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))