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>
42 #include <modest-account-mgr.h>
43 #include <modest-account-mgr-helpers.h>
45 #include <widgets/modest-msg-edit-window.h>
46 #include <modest-selector-picker.h>
47 #include <widgets/modest-recpt-editor.h>
48 #include <widgets/modest-attachments-view.h>
50 #include <modest-runtime.h>
52 #include "modest-platform.h"
53 #include "modest-icon-names.h"
54 #include "modest-widget-memory.h"
55 #include "modest-window-priv.h"
56 #include "modest-mail-operation.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-tny-folder.h"
60 #include "modest-tny-account.h"
61 #include "modest-address-book.h"
62 #include "modest-text-utils.h"
63 #include <tny-simple-list.h>
64 #include <modest-wp-text-view.h>
65 #include <wptextbuffer.h>
66 #include <hildon/hildon-pannable-area.h>
67 #include <hildon/hildon-touch-selector.h>
68 #include <hildon/hildon-picker-dialog.h>
69 #include "modest-msg-edit-window-ui-dimming.h"
71 #include "modest-hildon-includes.h"
72 #ifdef MODEST_HAVE_HILDON0_WIDGETS
73 #include <hildon-widgets/hildon-color-chooser.h>
75 #include "widgets/modest-msg-edit-window-ui.h"
76 #ifdef MODEST_HAVE_HILDON0_WIDGETS
77 #include <libgnomevfs/gnome-vfs-mime-utils.h>
79 #include <libgnomevfs/gnome-vfs-mime.h>
81 #include <modest-utils.h>
82 #include "modest-maemo-utils.h"
83 #include <modest-ui-constants.h>
86 #define DEFAULT_FONT_SIZE 3
87 #define DEFAULT_FONT 2
88 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
89 #define DEFAULT_MAIN_VBOX_SPACING 6
90 #define SUBJECT_MAX_LENGTH 1000
91 #define IMAGE_MAX_WIDTH 560
92 #define DEFAULT_FONT_SCALE 1.5
93 #define ATTACHMENT_BUTTON_WIDTH 118
95 static gboolean is_wp_text_buffer_started = FALSE;
97 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
98 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
99 static void modest_msg_edit_window_finalize (GObject *obj);
101 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
102 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
103 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
105 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
106 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
107 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
108 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
109 GtkTextIter *start, GtkTextIter *end,
111 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
112 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
113 static void subject_field_insert_text (GtkEditable *editable,
115 gint new_text_length,
117 ModestMsgEditWindow *window);
118 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
122 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
123 ModestRecptEditor *editor);
124 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
125 ModestMsgEditWindow *window);
127 /* ModestWindow methods implementation */
128 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
129 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
130 gboolean show_toolbar);
131 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
133 ModestMsgEditWindow *window);
134 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
135 static void subject_field_move_cursor (GtkEntry *entry,
136 GtkMovementStep step,
140 static void update_window_title (ModestMsgEditWindow *window);
143 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
144 ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
149 GtkTextIter *match_start,
150 GtkTextIter *match_end);
152 static void remove_tags (WPTextBuffer *buffer);
154 static void on_account_removed (TnyAccountStore *account_store,
158 static void init_window (ModestMsgEditWindow *obj);
160 gboolean scroll_drag_timeout (gpointer userdata);
161 static void correct_scroll (ModestMsgEditWindow *w);
162 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
163 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
164 ModestMsgEditWindow *userdata);
165 static void text_buffer_mark_set (GtkTextBuffer *buffer,
168 ModestMsgEditWindow *userdata);
169 static void on_message_settings (GtkAction *action,
170 ModestMsgEditWindow *window);
171 static void setup_menu (ModestMsgEditWindow *self);
173 static void from_field_changed (HildonPickerButton *button,
174 ModestMsgEditWindow *self);
175 static void font_size_clicked (GtkToolButton *button,
176 ModestMsgEditWindow *window);
177 static void font_face_clicked (GtkToolButton *button,
178 ModestMsgEditWindow *window);
179 static void DEBUG_BUFFER (WPTextBuffer *buffer)
183 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
185 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
186 while (!gtk_text_iter_is_end (&iter)) {
187 GString *output = g_string_new ("");
188 GSList *toggled_tags;
191 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
192 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
193 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
194 GtkTextTag *tag = (GtkTextTag *) node->data;
196 g_object_get (G_OBJECT (tag), "name", &name, NULL);
197 output = g_string_append (output, name);
198 g_string_append (output, " ");
200 output = g_string_append (output, "] OPENED [ ");
201 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
202 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
203 GtkTextTag *tag = (GtkTextTag *) node->data;
205 g_object_get (G_OBJECT (tag), "name", &name, NULL);
206 output = g_string_append (output, name);
207 g_string_append (output, " ");
209 output = g_string_append (output, "]\n");
210 g_message ("%s", output->str);
211 g_string_free (output, TRUE);
212 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
214 g_message ("END BUFFER");
218 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
219 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
223 /* static gboolean */
224 /* on_key_pressed (GtkWidget *self, */
225 /* GdkEventKey *event, */
226 /* gpointer user_data); */
228 /* list my signals */
235 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
236 struct _ModestMsgEditWindowPrivate {
238 GtkWidget *header_box;
240 ModestPairList *from_field_protos;
241 GtkWidget *from_field;
242 gchar *last_from_account;
243 gchar *original_account_name;
247 GtkWidget *bcc_field;
248 GtkWidget *subject_field;
249 GtkWidget *attachments_view;
250 GtkWidget *priority_icon;
251 GtkWidget *subject_box;
252 GtkWidget *add_attachment_button;
254 GtkWidget *cc_caption;
255 GtkWidget *bcc_caption;
256 gboolean update_caption_visibility;
257 GtkWidget *attachments_caption;
259 GtkTextBuffer *text_buffer;
261 GtkWidget *font_size_toolitem;
262 GtkWidget *font_face_toolitem;
263 GtkWidget *font_color_button;
264 GtkWidget *font_color_toolitem;
265 GSList *font_items_group;
266 GtkTreeModel *faces_model;
267 gint current_face_index;
268 GtkWidget *font_tool_button_label;
269 GtkTreeModel *sizes_model;
270 gint current_size_index;
271 GtkWidget *size_tool_button_label;
273 GtkWidget *find_toolbar;
276 GtkWidget *font_dialog;
279 guint correct_scroll_idle;
280 guint scroll_drag_timeout_id;
284 TnyList *attachments;
289 TnyHeaderFlags priority_flags;
291 gboolean can_undo, can_redo;
292 gulong clipboard_change_handler_id;
293 gulong default_clipboard_change_handler_id;
294 gulong account_removed_handler_id;
295 guint clipboard_owner_idle;
296 gchar *clipboard_text;
305 GtkWidget *cc_button;
306 GtkWidget *bcc_button;
309 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
310 MODEST_TYPE_MSG_EDIT_WINDOW, \
311 ModestMsgEditWindowPrivate))
313 static GtkWindowClass *parent_class = NULL;
315 /* uncomment the following if you have defined any signals */
316 /* static guint signals[LAST_SIGNAL] = {0}; */
319 modest_msg_edit_window_get_type (void)
321 static GType my_type = 0;
323 static const GTypeInfo my_info = {
324 sizeof(ModestMsgEditWindowClass),
325 NULL, /* base init */
326 NULL, /* base finalize */
327 (GClassInitFunc) modest_msg_edit_window_class_init,
328 NULL, /* class finalize */
329 NULL, /* class data */
330 sizeof(ModestMsgEditWindow),
332 (GInstanceInitFunc) modest_msg_edit_window_init,
335 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
336 "ModestMsgEditWindow",
344 save_state (ModestWindow *self)
346 modest_widget_memory_save (modest_runtime_get_conf(),
347 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
352 restore_settings (ModestMsgEditWindow *self)
354 ModestConf *conf = NULL;
356 conf = modest_runtime_get_conf ();
358 /* Dim at start clipboard actions */
359 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
364 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
366 GObjectClass *gobject_class;
367 ModestWindowClass *modest_window_class;
368 gobject_class = (GObjectClass*) klass;
369 modest_window_class = (ModestWindowClass*) klass;
371 parent_class = g_type_class_peek_parent (klass);
372 gobject_class->finalize = modest_msg_edit_window_finalize;
374 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
375 modest_window_class->save_state_func = save_state;
376 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
378 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
382 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
384 ModestMsgEditWindowPrivate *priv;
385 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
387 priv->msg_body = NULL;
388 priv->from_field = NULL;
389 priv->to_field = NULL;
390 priv->cc_field = NULL;
391 priv->bcc_field = NULL;
392 priv->subject_field = NULL;
393 priv->attachments = TNY_LIST (tny_simple_list_new ());
394 priv->images = TNY_LIST (tny_simple_list_new ());
395 priv->images_size = 0;
396 priv->images_count = 0;
399 priv->cc_caption = NULL;
400 priv->bcc_caption = NULL;
401 priv->update_caption_visibility = FALSE;
403 priv->priority_flags = 0;
405 priv->find_toolbar = NULL;
406 priv->last_search = NULL;
408 priv->draft_msg = NULL;
409 priv->outbox_msg = NULL;
410 priv->msg_uid = NULL;
412 priv->can_undo = FALSE;
413 priv->can_redo = FALSE;
414 priv->clipboard_change_handler_id = 0;
415 priv->default_clipboard_change_handler_id = 0;
416 priv->account_removed_handler_id = 0;
417 priv->clipboard_owner_idle = 0;
418 priv->clipboard_text = NULL;
421 priv->scroll_drag_timeout_id = 0;
422 priv->correct_scroll_idle = 0;
423 priv->last_upper = 0.0;
425 priv->font_dialog = NULL;
426 priv->app_menu = NULL;
428 if (!is_wp_text_buffer_started) {
429 is_wp_text_buffer_started = TRUE;
430 wp_text_buffer_library_init ();
435 hildon_program_add_window (hildon_program_get_instance(),
441 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
443 static ModestPairList*
444 get_transports (void)
446 GSList *transports = NULL;
448 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
449 GSList *accounts = modest_account_mgr_account_names (account_mgr,
450 TRUE /* only enabled accounts. */);
452 GSList *cursor = accounts;
454 gchar *account_name = cursor->data;
455 gchar *from_string = NULL;
457 from_string = modest_account_mgr_get_from_string (account_mgr,
461 if (from_string && account_name) {
462 gchar *name = account_name;
463 ModestPair *pair = modest_pair_new ((gpointer) name,
464 (gpointer) from_string , TRUE);
465 transports = g_slist_prepend (transports, pair);
468 cursor = cursor->next;
470 g_slist_free (accounts); /* only free the accounts, not the elements,
471 * because they are used in the pairlist */
475 static void window_focus (GtkWindow *window,
479 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
483 scroll_drag_timeout (gpointer userdata)
485 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
486 ModestMsgEditWindowPrivate *priv;
488 /* It could happen that the window was already closed */
489 if (!GTK_WIDGET_VISIBLE (win))
492 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
494 correct_scroll_without_drag_check (win, TRUE);
496 priv->scroll_drag_timeout_id = 0;
502 correct_scroll_without_drag_check_idle (gpointer userdata)
504 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
505 ModestMsgEditWindowPrivate *priv;
507 GdkRectangle rectangle;
508 gint offset_min, offset_max;
512 /* It could happen that the window was already closed */
513 if (!GTK_WIDGET_VISIBLE (w))
516 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
518 insert = gtk_text_buffer_get_insert (priv->text_buffer);
519 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
521 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
522 offset_min = priv->msg_body->allocation.y + rectangle.y;
523 offset_max = offset_min + rectangle.height;
525 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
526 offset_min = MAX (offset_min - 48, 0);
527 offset_max = MIN (offset_max + 48, vadj->upper);
529 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
531 priv->correct_scroll_idle = 0;
536 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
538 ModestMsgEditWindowPrivate *priv;
540 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
542 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
545 if (priv->correct_scroll_idle > 0) {
549 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
550 (GSourceFunc) correct_scroll_without_drag_check_idle,
556 correct_scroll (ModestMsgEditWindow *w)
558 ModestMsgEditWindowPrivate *priv;
560 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
561 if (gtk_grab_get_current () == priv->msg_body) {
562 if (priv->scroll_drag_timeout_id == 0) {
563 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
565 (GSourceFunc) scroll_drag_timeout,
572 correct_scroll_without_drag_check (w, TRUE);
576 text_buffer_end_user_action (GtkTextBuffer *buffer,
577 ModestMsgEditWindow *userdata)
580 correct_scroll (userdata);
584 text_buffer_mark_set (GtkTextBuffer *buffer,
587 ModestMsgEditWindow *userdata)
589 gtk_text_buffer_begin_user_action (buffer);
590 gtk_text_buffer_end_user_action (buffer);
594 cut_clipboard_check (GtkTextView *text_view,
597 GtkTextBuffer *buffer;
599 buffer = gtk_text_view_get_buffer (text_view);
600 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
601 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
606 copy_clipboard_check (GtkTextView *text_view,
609 GtkTextBuffer *buffer;
611 buffer = gtk_text_view_get_buffer (text_view);
612 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
613 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
618 attachment_deleted (ModestAttachmentsView *attachments_view,
621 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
626 connect_signals (ModestMsgEditWindow *obj)
628 ModestMsgEditWindowPrivate *priv;
630 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
632 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
633 G_CALLBACK (text_buffer_refresh_attributes), obj);
634 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
635 G_CALLBACK (text_buffer_can_undo), obj);
636 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
637 G_CALLBACK (text_buffer_can_redo), obj);
638 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
639 G_CALLBACK (body_changed), obj);
640 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
641 G_CALLBACK (body_changed), obj);
642 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
643 G_CALLBACK (text_buffer_end_user_action), obj);
644 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
645 G_CALLBACK (text_buffer_mark_set), obj);
646 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
647 G_CALLBACK (text_buffer_apply_tag), obj);
648 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
649 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
650 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
651 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
652 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
653 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
655 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
656 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
657 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
658 G_CALLBACK (from_field_changed), obj);
660 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
661 G_CALLBACK (msg_body_focus), obj);
662 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
663 G_CALLBACK (msg_body_focus), obj);
664 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
665 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
666 "changed", G_CALLBACK (recpt_field_changed), obj);
667 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
668 "changed", G_CALLBACK (recpt_field_changed), obj);
669 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
670 "changed", G_CALLBACK (recpt_field_changed), obj);
671 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
672 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
673 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
675 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
676 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
678 priv->clipboard_change_handler_id =
679 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
680 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
681 priv->default_clipboard_change_handler_id =
682 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
683 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
685 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
686 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
687 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
691 init_wp_text_view_style ()
693 static gboolean initialized = FALSE;
696 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
702 init_window (ModestMsgEditWindow *obj)
704 GtkWidget *to_caption, *subject_caption;
705 GtkWidget *main_vbox;
706 GtkWidget *add_attachment_align;
707 ModestMsgEditWindowPrivate *priv;
708 GtkActionGroup *action_group;
709 ModestWindowPrivate *parent_priv;
710 GdkPixbuf *window_icon = NULL;
711 GError *error = NULL;
713 GtkSizeGroup *title_size_group;
714 GtkSizeGroup *value_size_group;
715 GtkWidget *attachment_icon;
716 GtkWidget *window_box;
717 GtkWidget *window_align;
718 #if (GTK_MINOR_VERSION >= 10)
719 GdkAtom deserialize_type;
722 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
723 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
725 parent_priv->ui_manager = gtk_ui_manager_new();
726 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
727 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
729 /* Add common actions */
730 gtk_action_group_add_actions (action_group,
731 modest_msg_edit_action_entries,
732 G_N_ELEMENTS (modest_msg_edit_action_entries),
734 gtk_action_group_add_actions (action_group,
735 hildon2_msg_edit_action_entries,
736 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
738 gtk_action_group_add_toggle_actions (action_group,
739 modest_msg_edit_toggle_action_entries,
740 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
742 gtk_action_group_add_radio_actions (action_group,
743 modest_msg_edit_alignment_radio_action_entries,
744 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
746 G_CALLBACK (modest_ui_actions_on_change_justify),
748 gtk_action_group_add_radio_actions (action_group,
749 modest_msg_edit_priority_action_entries,
750 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
752 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
754 gtk_action_group_add_radio_actions (action_group,
755 modest_msg_edit_file_format_action_entries,
756 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
757 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
758 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
760 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
761 g_object_unref (action_group);
763 /* Load the UI definition */
764 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
767 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
768 g_clear_error (&error);
771 /* Add accelerators */
772 gtk_window_add_accel_group (GTK_WINDOW (obj),
773 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
775 parent_priv->menubar = NULL;
777 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
778 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
780 /* Note: This ModestPairList* must exist for as long as the picker
781 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
782 * so it can't know how to manage its memory. */
783 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
784 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
786 modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group,
787 _("mail_va_from"), priv->from_field);
789 priv->to_field = modest_recpt_editor_new ();
790 priv->cc_field = modest_recpt_editor_new ();
791 priv->bcc_field = modest_recpt_editor_new ();
792 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
793 priv->priority_icon = gtk_image_new ();
794 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
795 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
796 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
797 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
798 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
799 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
800 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
801 priv->add_attachment_button = hildon_button_new (MODEST_EDITABLE_SIZE, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
802 gtk_widget_set_size_request (priv->add_attachment_button, ATTACHMENT_BUTTON_WIDTH, -1);
803 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
804 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
805 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
806 hildon_button_set_image (HILDON_BUTTON (priv->add_attachment_button), attachment_icon);
807 add_attachment_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
808 gtk_alignment_set_padding (GTK_ALIGNMENT (add_attachment_align), 0, 0, MODEST_MARGIN_DEFAULT, 0);
809 gtk_container_add (GTK_CONTAINER (add_attachment_align), priv->add_attachment_button);
810 gtk_box_pack_start (GTK_BOX (priv->subject_box), add_attachment_align, FALSE, FALSE, 0);
811 priv->attachments_view = modest_attachments_view_new (NULL);
812 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
813 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
815 priv->header_box = gtk_vbox_new (FALSE, 0);
817 to_caption = modest_maemo_utils_create_captioned_with_size_type
818 (title_size_group, value_size_group,
819 _("mail_va_to"), FALSE, priv->to_field,
820 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
821 priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type
822 (title_size_group, value_size_group,
823 _("mail_va_cc"), FALSE, priv->cc_field,
824 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
825 priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
826 (title_size_group, value_size_group,
827 _("mail_va_hotfix1"), FALSE, priv->bcc_field,
828 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
829 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
830 _("mail_va_subject"), FALSE, priv->subject_box);
831 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
832 _("mail_va_attachment"),
834 priv->attachments_view,
835 HILDON_SIZE_AUTO_WIDTH |
836 HILDON_SIZE_AUTO_HEIGHT);
837 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
838 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
839 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
840 g_object_unref (title_size_group);
841 g_object_unref (value_size_group);
843 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
844 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
845 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
846 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
847 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
848 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
849 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
851 init_wp_text_view_style ();
853 priv->msg_body = modest_wp_text_view_new ();
856 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
857 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
858 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
859 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
860 #if (GTK_MINOR_VERSION >= 10)
861 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
862 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
864 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
865 deserialize_type, TRUE);
867 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
869 priv->find_toolbar = hildon_find_toolbar_new (NULL);
870 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
872 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
874 priv->pannable = hildon_pannable_area_new ();
876 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
877 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
878 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
880 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
881 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
882 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
884 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
885 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox),
886 hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable)));
887 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
889 window_box = gtk_vbox_new (FALSE, 0);
890 gtk_container_add (GTK_CONTAINER(obj), window_box);
892 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
894 /* Set window icon */
895 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
897 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
898 g_object_unref (window_icon);
903 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
905 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
907 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
908 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
909 priv->clipboard_change_handler_id))
910 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
911 priv->clipboard_change_handler_id);
912 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
913 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
914 priv->default_clipboard_change_handler_id))
915 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
916 priv->default_clipboard_change_handler_id);
918 if (priv->account_removed_handler_id &&
919 g_signal_handler_is_connected (modest_runtime_get_account_store (),
920 priv->account_removed_handler_id))
921 g_signal_handler_disconnect(modest_runtime_get_account_store (),
922 priv->account_removed_handler_id);
926 modest_msg_edit_window_finalize (GObject *obj)
928 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
930 /* Sanity check: shouldn't be needed, the window mgr should
931 call this function before */
932 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
934 if (priv->font_dialog != NULL) {
935 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
938 if (priv->clipboard_text != NULL) {
939 g_free (priv->clipboard_text);
940 priv->clipboard_text = NULL;
943 if (priv->draft_msg != NULL) {
944 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
945 if (TNY_IS_HEADER (header)) {
946 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
947 modest_window_mgr_unregister_header (mgr, header);
949 g_object_unref (priv->draft_msg);
950 priv->draft_msg = NULL;
952 if (priv->outbox_msg != NULL) {
953 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
954 if (TNY_IS_HEADER (header)) {
955 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
956 modest_window_mgr_unregister_header (mgr, header);
958 g_object_unref (priv->outbox_msg);
959 priv->outbox_msg = NULL;
961 if (priv->correct_scroll_idle > 0) {
962 g_source_remove (priv->correct_scroll_idle);
963 priv->correct_scroll_idle = 0;
965 if (priv->scroll_drag_timeout_id > 0) {
966 g_source_remove (priv->scroll_drag_timeout_id);
967 priv->scroll_drag_timeout_id = 0;
969 if (priv->clipboard_owner_idle > 0) {
970 g_source_remove (priv->clipboard_owner_idle);
971 priv->clipboard_owner_idle = 0;
973 if (priv->original_account_name)
974 g_free (priv->original_account_name);
975 g_free (priv->msg_uid);
976 g_free (priv->last_search);
977 g_object_unref (priv->faces_model);
978 g_object_unref (priv->sizes_model);
979 g_object_unref (priv->attachments);
980 g_object_unref (priv->images);
982 /* This had to stay alive for as long as the picker that used it: */
983 modest_pair_list_free (priv->from_field_protos);
985 G_OBJECT_CLASS(parent_class)->finalize (obj);
989 pixbuf_size_prepared (GdkPixbufLoader *loader,
992 ModestMsgEditWindow *self)
994 gint new_height, new_width;
1001 if (width > IMAGE_MAX_WIDTH) {
1002 new_height = height * IMAGE_MAX_WIDTH / width;
1003 new_width = IMAGE_MAX_WIDTH;
1006 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1010 pixbuf_from_stream (TnyStream *stream,
1011 const gchar *mime_type,
1012 guint64 *stream_size,
1013 ModestMsgEditWindow *self)
1015 GdkPixbufLoader *loader;
1018 GError *error = NULL;
1022 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1024 if (loader == NULL) {
1029 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1031 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1033 tny_stream_reset (TNY_STREAM (stream));
1034 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1035 unsigned char read_buffer[128];
1037 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1039 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1042 /* Allow some UI responsiveness */
1043 while (gtk_events_pending ())
1044 gtk_main_iteration ();
1046 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1048 gdk_pixbuf_loader_close (loader, &error);
1051 g_error_free (error);
1052 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1054 g_object_ref (pixbuf);
1055 g_object_unref (loader);
1060 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1061 GdkPixbuf *new_pixbuf;
1063 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1064 gdk_pixbuf_get_width (pixbuf);
1065 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1066 g_object_unref (pixbuf);
1067 pixbuf = new_pixbuf;
1071 *stream_size = size;
1077 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1079 ModestMsgEditWindowPrivate *priv;
1082 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1084 g_object_ref (self);
1085 for (iter = tny_list_create_iterator (attachments);
1086 !tny_iterator_is_done (iter);
1087 tny_iterator_next (iter)) {
1088 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1089 const gchar *cid = tny_mime_part_get_content_id (part);
1090 const gchar *mime_type = tny_mime_part_get_content_type (part);
1091 if ((cid != NULL)&&(mime_type != NULL)) {
1092 guint64 stream_size;
1093 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1094 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1097 g_object_unref (stream);
1099 if (pixbuf != NULL) {
1100 priv->images_count ++;
1101 priv->images_size += stream_size;
1102 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1103 g_object_unref (pixbuf);
1106 g_object_unref (part);
1108 g_object_unref (iter);
1109 g_object_unref (self);
1113 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1115 TnyMimePart *parent = NULL;
1116 const gchar *content_type = NULL;
1117 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1119 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1121 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1122 parent = g_object_ref (msg);
1123 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1124 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1127 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1128 iter = tny_list_create_iterator (parts);
1129 while (!tny_iterator_is_done (iter)) {
1131 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1132 content_type = tny_mime_part_get_content_type (part);
1133 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1137 g_object_unref (part);
1139 tny_iterator_next (iter);
1141 g_object_unref (iter);
1142 g_object_unref (parts);
1145 if (parent != NULL) {
1146 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1149 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1150 iter = tny_list_create_iterator (parts);
1151 while (!tny_iterator_is_done (iter)) {
1153 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1154 content_type = tny_mime_part_get_content_type (part);
1155 if (content_type && g_str_has_prefix (content_type, "image/")) {
1156 tny_list_prepend (priv->images, (GObject *) part);
1158 g_object_unref (part);
1159 tny_iterator_next (iter);
1161 g_object_unref (iter);
1162 g_object_unref (parts);
1163 g_object_unref (parent);
1168 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1171 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1173 for (iter = tny_list_create_iterator (attachments) ;
1174 !tny_iterator_is_done (iter);
1175 tny_iterator_next (iter)) {
1176 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1177 const gchar *cid = tny_mime_part_get_content_id (part);
1179 char *invalid = NULL;
1180 gint int_cid = strtol (cid, &invalid, 10);
1181 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1182 priv->next_cid = int_cid + 1;
1185 g_object_unref (part);
1187 g_object_unref (iter);
1191 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1194 gchar *to, *cc, *bcc, *subject;
1196 ModestMsgEditWindowPrivate *priv;
1197 ModestWindowPrivate *parent_priv;
1199 TnyHeaderFlags priority_flags;
1200 TnyFolder *msg_folder;
1201 gboolean is_html = FALSE;
1202 gboolean field_view_set;
1204 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1205 g_return_if_fail (TNY_IS_MSG (msg));
1207 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1208 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1210 header = tny_msg_get_header (msg);
1211 to = tny_header_dup_to (header);
1212 cc = tny_header_dup_cc (header);
1213 bcc = tny_header_dup_bcc (header);
1214 subject = tny_header_dup_subject (header);
1215 priority_flags = tny_header_get_priority (header);
1218 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1220 field_view_set = TRUE;
1222 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1223 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1224 gtk_widget_show (priv->cc_caption);
1225 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1226 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1227 gtk_widget_hide (priv->cc_caption);
1228 field_view_set = FALSE;
1230 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1232 field_view_set = TRUE;
1234 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1235 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1236 gtk_widget_show (priv->bcc_caption);
1237 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1238 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1239 gtk_widget_hide (priv->bcc_caption);
1240 field_view_set = FALSE;
1242 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1246 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1247 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1250 update_window_title (self);
1252 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1253 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1255 if ((body == NULL)||(body[0] == '\0')) {
1257 body = modest_text_utils_convert_to_html ("");
1260 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1261 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1264 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1267 /* Add attachments to the view */
1268 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1269 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1270 if (tny_list_get_length (priv->attachments) == 0) {
1271 gtk_widget_hide (priv->attachments_caption);
1273 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1274 gtk_widget_show_all (priv->attachments_caption);
1276 get_related_images (self, msg);
1277 update_next_cid (self, priv->attachments);
1278 update_next_cid (self, priv->images);
1279 replace_with_images (self, priv->images);
1281 if (preserve_is_rich && !is_html) {
1282 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1283 /* Get the default format required from configuration */
1284 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1285 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1288 /* Set the default focus depending on having already a To: field or not */
1289 if ((!to)||(*to == '\0')) {
1290 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1292 gtk_widget_grab_focus (priv->msg_body);
1295 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1297 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1298 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1300 modest_msg_edit_window_set_modified (self, FALSE);
1302 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1303 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1304 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1305 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1307 if (priv->msg_uid) {
1308 g_free (priv->msg_uid);
1309 priv->msg_uid = NULL;
1312 /* we should set a reference to the incoming message if it is a draft */
1313 msg_folder = tny_msg_get_folder (msg);
1315 if (modest_tny_folder_is_local_folder (msg_folder)) {
1316 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1317 if (type == TNY_FOLDER_TYPE_INVALID)
1318 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1320 if (type == TNY_FOLDER_TYPE_DRAFTS)
1321 priv->draft_msg = g_object_ref(msg);
1322 if (type == TNY_FOLDER_TYPE_OUTBOX)
1323 priv->outbox_msg = g_object_ref(msg);
1324 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1326 g_object_unref (msg_folder);
1337 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1339 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1340 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1341 GtkWidget *placeholder;
1342 GtkWidget *tool_item;
1347 GtkWidget *sizes_menu;
1348 GtkWidget *fonts_menu;
1354 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1355 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1356 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1357 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1359 /* Font color placeholder */
1360 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1361 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1364 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1365 priv->font_color_button = hildon_color_button_new ();
1366 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1367 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1368 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1369 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1370 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1371 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1372 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1373 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1375 G_CALLBACK (modest_msg_edit_window_color_button_change),
1378 /* Font size and face placeholder */
1379 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1380 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1382 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1383 priv->size_tool_button_label = gtk_label_new (NULL);
1384 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1385 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1386 size_text, "</span>", NULL);
1387 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1389 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1390 hbox = gtk_hbox_new (0, FALSE);
1391 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, FALSE, FALSE, 0);
1392 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1393 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1394 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1395 sizes_menu = gtk_menu_new ();
1396 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1397 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1400 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1401 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1403 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1407 if (wp_font_size[size_index] == 12)
1408 priv->current_size_index = size_index;
1412 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1413 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1414 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1415 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1416 priv->font_size_toolitem = tool_item;
1419 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1420 priv->font_tool_button_label = gtk_label_new (NULL);
1421 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1422 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1424 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1425 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1426 fonts_menu = gtk_menu_new ();
1427 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1428 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1431 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1433 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1434 0, wp_get_font_name (font_index),
1437 if (font_index == DEFAULT_FONT)
1438 priv->current_face_index = font_index;
1440 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1441 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1442 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1443 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1444 priv->font_face_toolitem = tool_item;
1446 /* Set expand and homogeneous for remaining items */
1447 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1448 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1449 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1450 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1451 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1452 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1453 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1454 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1455 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1457 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1458 will not show the tool items added to the placeholders) */
1459 gtk_widget_show_all (parent_priv->toolbar);
1461 /* Set the no show all *after* showing all items. We do not
1462 want the toolbar to be shown with a show all because it
1463 could go agains the gconf setting regarding showing or not
1464 the toolbar of the editor window */
1465 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1471 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1474 ModestWindowPrivate *parent_priv;
1475 ModestMsgEditWindowPrivate *priv;
1476 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1477 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1478 ModestWindowMgr *mgr = NULL;
1480 g_return_val_if_fail (msg, NULL);
1481 g_return_val_if_fail (account_name, NULL);
1483 mgr = modest_runtime_get_window_mgr ();
1485 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1487 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1488 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1490 /* Menubar. Update the state of some toggles */
1491 priv->from_field_protos = get_transports ();
1492 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1493 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1494 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1495 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1497 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1498 hildon_touch_selector_get_current_text
1499 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1500 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1501 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1504 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1506 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1508 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1510 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1512 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1513 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1514 /* Add common dimming rules */
1515 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1516 modest_msg_edit_window_toolbar_dimming_entries,
1517 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1518 MODEST_WINDOW (obj));
1519 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1520 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1521 MODEST_WINDOW (obj));
1522 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1523 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1524 MODEST_WINDOW (obj));
1525 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1526 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1527 MODEST_WINDOW (obj));
1528 /* Insert dimming rules group for this window */
1529 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1530 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1532 /* Setup app menu */
1533 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1535 /* Checks the dimming rules */
1536 g_object_unref (toolbar_rules_group);
1537 g_object_unref (clipboard_rules_group);
1538 gtk_widget_hide (priv->priority_icon);
1539 gtk_widget_queue_resize (priv->subject_box);
1540 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1542 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1544 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1545 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1546 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1547 priv->update_caption_visibility = TRUE;
1549 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1551 /* Track account-removed signal, this window should be closed
1552 in the case we're creating a mail associated to the account
1554 priv->account_removed_handler_id =
1555 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1557 G_CALLBACK(on_account_removed),
1560 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1562 return (ModestWindow*) obj;
1566 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1568 GString **string_buffer = (GString **) user_data;
1570 *string_buffer = g_string_append (*string_buffer, buffer);
1576 * @result: A new string which should be freed with g_free().
1579 get_formatted_data (ModestMsgEditWindow *edit_window)
1581 ModestMsgEditWindowPrivate *priv;
1582 GString *string_buffer = g_string_new ("");
1584 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1586 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1588 modest_text_utils_hyperlinkify (string_buffer);
1590 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1592 return g_string_free (string_buffer, FALSE);
1597 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1600 const gchar *account_name;
1601 ModestMsgEditWindowPrivate *priv;
1602 TnyIterator *att_iter;
1604 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1606 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1608 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1609 g_return_val_if_fail (account_name, NULL);
1612 /* don't free these (except from) */
1613 data = g_slice_new0 (MsgData);
1614 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1616 data->account_name = g_strdup (account_name);
1617 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1618 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1619 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1620 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1621 if (priv->draft_msg) {
1622 data->draft_msg = g_object_ref (priv->draft_msg);
1623 } else if (priv->outbox_msg) {
1624 data->draft_msg = g_object_ref (priv->outbox_msg);
1626 data->draft_msg = NULL;
1629 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1631 gtk_text_buffer_get_bounds (buf, &b, &e);
1632 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1634 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1635 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1637 data->html_body = NULL;
1639 /* deep-copy the data */
1640 att_iter = tny_list_create_iterator (priv->attachments);
1641 data->attachments = NULL;
1642 while (!tny_iterator_is_done (att_iter)) {
1643 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1644 if (!(TNY_IS_MIME_PART(part))) {
1645 g_warning ("strange data in attachment list");
1646 g_object_unref (part);
1647 tny_iterator_next (att_iter);
1650 data->attachments = g_list_append (data->attachments,
1652 tny_iterator_next (att_iter);
1654 g_object_unref (att_iter);
1656 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1657 att_iter = tny_list_create_iterator (priv->images);
1658 data->images = NULL;
1659 while (!tny_iterator_is_done (att_iter)) {
1660 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1662 if (!(TNY_IS_MIME_PART(part))) {
1663 g_warning ("strange data in attachment list");
1664 g_object_unref (part);
1665 tny_iterator_next (att_iter);
1668 cid = tny_mime_part_get_content_id (part);
1670 gchar *image_tag_id;
1671 GtkTextTag *image_tag;
1673 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1674 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1675 g_free (image_tag_id);
1677 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1679 ((gtk_text_iter_has_tag (&iter, image_tag))||
1680 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1681 data->images = g_list_append (data->images,
1682 g_object_ref (part));
1684 g_object_unref (part);
1685 tny_iterator_next (att_iter);
1687 g_object_unref (att_iter);
1689 data->priority_flags = priv->priority_flags;
1696 unref_gobject (GObject *obj, gpointer data)
1698 if (!G_IS_OBJECT(obj))
1700 g_object_unref (obj);
1704 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1707 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1715 g_free (data->from);
1716 g_free (data->subject);
1717 g_free (data->plain_body);
1718 g_free (data->html_body);
1719 g_free (data->account_name);
1721 if (data->draft_msg != NULL) {
1722 g_object_unref (data->draft_msg);
1723 data->draft_msg = NULL;
1726 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1727 g_list_free (data->attachments);
1728 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1729 g_list_free (data->images);
1731 g_slice_free (MsgData, data);
1735 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1737 guint64 *parts_size)
1739 ModestMsgEditWindowPrivate *priv;
1741 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1743 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1745 /* TODO: add images */
1746 *parts_size += priv->images_size;
1747 *parts_count += priv->images_count;
1752 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1755 ModestMsgEditWindowPrivate *priv = NULL;
1756 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1758 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1760 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1762 return MODEST_MSG_EDIT_FORMAT_HTML;
1764 return MODEST_MSG_EDIT_FORMAT_TEXT;
1768 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1769 ModestMsgEditFormat format)
1771 ModestMsgEditWindowPrivate *priv;
1773 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1774 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1777 case MODEST_MSG_EDIT_FORMAT_HTML:
1778 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1780 case MODEST_MSG_EDIT_FORMAT_TEXT:
1781 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1784 g_return_if_reached ();
1788 ModestMsgEditFormatState *
1789 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1791 ModestMsgEditFormatState *format_state = NULL;
1792 ModestMsgEditWindowPrivate *priv;
1793 WPTextBufferFormat *buffer_format;
1795 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1797 buffer_format = g_new0 (WPTextBufferFormat, 1);
1798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1800 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1802 format_state = g_new0 (ModestMsgEditFormatState, 1);
1803 format_state->bold = buffer_format->bold&0x1;
1804 format_state->italics = buffer_format->italic&0x1;
1805 format_state->bullet = buffer_format->bullet&0x1;
1806 format_state->color = buffer_format->color;
1807 format_state->font_size = buffer_format->font_size;
1808 format_state->font_family = wp_get_font_name (buffer_format->font);
1809 format_state->justification = buffer_format->justification;
1810 g_free (buffer_format);
1812 return format_state;
1817 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1818 const ModestMsgEditFormatState *format_state)
1820 ModestMsgEditWindowPrivate *priv;
1821 WPTextBufferFormat *buffer_format;
1822 WPTextBufferFormat *current_format;
1824 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1825 g_return_if_fail (format_state != NULL);
1827 buffer_format = g_new0 (WPTextBufferFormat, 1);
1828 current_format = g_new0 (WPTextBufferFormat, 1);
1830 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1831 gtk_widget_grab_focus (priv->msg_body);
1832 buffer_format->bold = (format_state->bold != FALSE);
1833 buffer_format->italic = (format_state->italics != FALSE);
1834 buffer_format->color = format_state->color;
1835 buffer_format->font_size = format_state->font_size;
1836 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1837 buffer_format->justification = format_state->justification;
1838 buffer_format->bullet = format_state->bullet;
1840 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1842 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1843 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1844 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1845 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1846 buffer_format->cs.font = (buffer_format->font != current_format->font);
1847 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1848 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1850 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1851 if (buffer_format->cs.bold) {
1852 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1853 GINT_TO_POINTER (buffer_format->bold&0x1));
1855 if (buffer_format->cs.italic) {
1856 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1857 GINT_TO_POINTER (buffer_format->italic&0x1));
1859 if (buffer_format->cs.color) {
1860 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1861 GINT_TO_POINTER (&(buffer_format->color)));
1863 if (buffer_format->cs.font_size) {
1864 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1865 GINT_TO_POINTER (buffer_format->font_size));
1867 if (buffer_format->cs.justification) {
1868 switch (buffer_format->justification) {
1869 case GTK_JUSTIFY_LEFT:
1870 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1871 GINT_TO_POINTER(TRUE));
1873 case GTK_JUSTIFY_CENTER:
1874 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1875 GINT_TO_POINTER(TRUE));
1877 case GTK_JUSTIFY_RIGHT:
1878 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1879 GINT_TO_POINTER(TRUE));
1886 if (buffer_format->cs.font) {
1887 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1888 GINT_TO_POINTER (buffer_format->font));
1890 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1891 if (buffer_format->cs.bullet) {
1892 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1893 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1895 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1897 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1899 g_free (buffer_format);
1900 g_free (current_format);
1902 /* Check dimming rules */
1903 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1904 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1908 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1910 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1912 ModestWindowPrivate *parent_priv;
1913 ModestMsgEditWindowPrivate *priv;
1915 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1916 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1918 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1919 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1920 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1921 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1923 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1924 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1925 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1928 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1930 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1931 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1933 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1934 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1936 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1937 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1940 switch (buffer_format->justification)
1942 case GTK_JUSTIFY_LEFT:
1943 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1945 case GTK_JUSTIFY_CENTER:
1946 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1948 case GTK_JUSTIFY_RIGHT:
1949 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1956 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1958 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1959 G_CALLBACK (modest_msg_edit_window_color_button_change),
1961 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1962 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1963 G_CALLBACK (modest_msg_edit_window_color_button_change),
1966 if (priv->current_size_index != buffer_format->font_size) {
1970 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1971 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1975 priv->current_size_index = buffer_format->font_size;
1977 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
1978 markup = g_strconcat ("<span font_family='Sans'>",
1979 size_text, "</span>", NULL);
1981 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1985 gtk_tree_path_free (path);
1988 if (priv->current_face_index != buffer_format->font) {
1992 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
1993 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
1997 priv->current_face_index = buffer_format->font;
1998 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
1999 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2000 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2007 g_free (buffer_format);
2011 #ifdef MODEST_HILDON_VERSION_0
2013 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2016 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2017 ModestMsgEditWindowPrivate *priv;
2018 GtkWidget *dialog = NULL;
2020 GdkColor *new_color = NULL;
2022 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2023 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2025 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2026 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2027 g_free (buffer_format);
2029 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2030 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2031 if (new_color != NULL) {
2032 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2033 (gpointer) new_color);
2036 gtk_widget_destroy (dialog);
2041 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2044 ModestMsgEditWindowPrivate *priv;
2045 GtkWidget *dialog = NULL;
2047 GdkColor *old_color = NULL;
2048 const GdkColor *new_color = NULL;
2050 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2051 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2053 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2054 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2056 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2057 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2058 if (new_color != NULL)
2059 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2061 gtk_widget_destroy (dialog);
2067 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2070 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2071 ModestMsgEditWindowPrivate *priv;
2072 GtkWidget *dialog = NULL;
2074 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2075 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2077 dialog = hildon_color_chooser_new ();
2078 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2079 g_free (buffer_format);
2081 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2083 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2084 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2087 gtk_widget_destroy (dialog);
2092 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2095 ModestMsgEditWindowPrivate *priv;
2096 GtkWidget *dialog = NULL;
2097 GdkColor *old_color = NULL;
2099 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2100 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2102 dialog = hildon_color_chooser_new ();
2103 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2105 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2107 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2108 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2110 gtk_widget_destroy (dialog);
2113 #endif /*!MODEST_HILDON_VERSION_0*/
2118 create_stream_for_uri (const gchar* uri)
2123 TnyStream *result = NULL;
2125 GnomeVFSHandle *handle = NULL;
2126 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2127 if (test == GNOME_VFS_OK) {
2128 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2129 /* Streams over OBEX (Bluetooth) are not seekable but
2130 * we expect them to be (we might need to read them
2131 * several times). So if this is a Bluetooth URI just
2132 * read the whole file into memory (this is not a fast
2133 * protocol so we can assume that these files are not
2134 * going to be very big) */
2135 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2136 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2137 TnyStream *memstream = tny_camel_mem_stream_new ();
2138 tny_stream_write_to_stream (vfssstream, memstream);
2139 g_object_unref (vfssstream);
2142 result = vfssstream;
2150 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2153 ModestMsgEditWindowPrivate *priv;
2154 GtkWidget *dialog = NULL;
2156 GSList *uris = NULL;
2157 GSList *uri_node = NULL;
2159 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2161 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2162 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2163 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2165 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2167 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2168 GTK_WINDOW (dialog), GTK_WINDOW (window));
2170 response = gtk_dialog_run (GTK_DIALOG (dialog));
2172 case GTK_RESPONSE_OK:
2173 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2178 gtk_widget_destroy (dialog);
2180 g_object_ref (window);
2181 /* The operation could take some time so allow the dialog to be closed */
2182 while (gtk_events_pending ())
2183 gtk_main_iteration ();
2185 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2187 GnomeVFSHandle *handle = NULL;
2188 GnomeVFSResult result;
2189 GtkTextIter position;
2190 GtkTextMark *insert_mark;
2192 uri = (const gchar *) uri_node->data;
2193 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2194 if (result == GNOME_VFS_OK) {
2196 GnomeVFSFileInfo *info;
2197 gchar *filename, *basename, *escaped_filename;
2198 TnyMimePart *mime_part;
2200 const gchar *mime_type = NULL;
2201 GnomeVFSURI *vfs_uri;
2202 guint64 stream_size;
2204 gnome_vfs_close (handle);
2205 vfs_uri = gnome_vfs_uri_new (uri);
2207 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2208 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2209 g_free (escaped_filename);
2210 gnome_vfs_uri_unref (vfs_uri);
2211 info = gnome_vfs_file_info_new ();
2213 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2214 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2216 mime_type = gnome_vfs_file_info_get_mime_type (info);
2218 mime_part = tny_platform_factory_new_mime_part
2219 (modest_runtime_get_platform_factory ());
2221 TnyStream *stream = create_stream_for_uri (uri);
2223 if (stream == NULL) {
2225 modest_platform_information_banner (NULL, NULL,
2226 _FM("sfil_ib_opening_not_allowed"));
2228 g_object_unref (mime_part);
2229 gnome_vfs_file_info_unref (info);
2233 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2235 content_id = g_strdup_printf ("%d", priv->next_cid);
2236 tny_mime_part_set_content_id (mime_part, content_id);
2237 g_free (content_id);
2240 basename = g_path_get_basename (filename);
2241 tny_mime_part_set_filename (mime_part, basename);
2244 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2246 if (pixbuf != NULL) {
2247 priv->images_size += stream_size;
2248 priv->images_count ++;
2249 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2250 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2251 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2252 tny_mime_part_get_content_id (mime_part), pixbuf);
2253 g_object_unref (pixbuf);
2255 tny_list_prepend (priv->images, (GObject *) mime_part);
2256 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2258 modest_platform_information_banner (NULL, NULL,
2259 _("mail_ib_file_operation_failed"));
2263 g_object_unref (mime_part);
2264 gnome_vfs_file_info_unref (info);
2268 g_object_unref (window);
2272 on_attach_file_response (GtkDialog *dialog,
2276 GSList *uris = NULL;
2278 GnomeVFSFileSize total_size, allowed_size;
2279 ModestMsgEditWindow *window;
2280 ModestMsgEditWindowPrivate *priv;
2285 case GTK_RESPONSE_OK:
2286 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2292 window = MODEST_MSG_EDIT_WINDOW (user_data);
2293 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2295 /* allowed size is the maximum size - what's already there */
2296 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2297 &att_num, &att_size);
2298 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2301 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2303 const gchar *uri = (const gchar *) uri_node->data;
2306 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2308 if (total_size > allowed_size) {
2309 g_warning ("%s: total size: %u",
2310 __FUNCTION__, (unsigned int)total_size);
2313 allowed_size -= total_size;
2315 g_slist_foreach (uris, (GFunc) g_free, NULL);
2316 g_slist_free (uris);
2318 gtk_widget_destroy (GTK_WIDGET (dialog));
2322 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2324 GtkWidget *dialog = NULL;
2325 ModestMsgEditWindowPrivate *priv;
2327 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2329 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2331 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2334 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2335 GTK_FILE_CHOOSER_ACTION_OPEN);
2336 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2337 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2338 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2339 GTK_WINDOW (dialog), GTK_WINDOW (window));
2341 /* Connect to response & show */
2342 g_signal_connect (dialog, "response",
2343 G_CALLBACK (on_attach_file_response), window);
2344 gtk_widget_show (dialog);
2349 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2351 GnomeVFSFileSize allowed_size)
2354 GnomeVFSHandle *handle = NULL;
2355 ModestMsgEditWindowPrivate *priv;
2356 GnomeVFSResult result;
2357 GnomeVFSFileSize size = 0;
2358 g_return_val_if_fail (window, 0);
2359 g_return_val_if_fail (uri, 0);
2361 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2363 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2364 if (result == GNOME_VFS_OK) {
2365 TnyMimePart *mime_part;
2367 const gchar *mime_type = NULL;
2369 gchar *escaped_filename;
2372 GnomeVFSFileInfo *info;
2373 GnomeVFSURI *vfs_uri;
2375 gnome_vfs_close (handle);
2376 vfs_uri = gnome_vfs_uri_new (uri);
2379 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2380 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2381 g_free (escaped_filename);
2382 gnome_vfs_uri_unref (vfs_uri);
2384 info = gnome_vfs_file_info_new ();
2386 if (gnome_vfs_get_file_info (uri,
2388 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2390 mime_type = gnome_vfs_file_info_get_mime_type (info);
2391 mime_part = tny_platform_factory_new_mime_part
2392 (modest_runtime_get_platform_factory ());
2394 /* try to get the attachment's size; this may fail for weird
2395 * file systems, like obex, upnp... */
2396 if (allowed_size != 0 &&
2397 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2399 if (size > allowed_size) {
2400 modest_platform_information_banner (NULL, NULL,
2401 _FM("sfil_ib_opening_not_allowed"));
2406 g_warning ("%s: could not get attachment size", __FUNCTION__);
2408 stream = create_stream_for_uri (uri);
2410 if (stream == NULL) {
2412 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2414 g_object_unref (mime_part);
2416 gnome_vfs_file_info_unref (info);
2420 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2421 g_object_unref (stream);
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 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2433 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2435 info->size == 0, info->size);
2436 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2437 gtk_widget_show_all (priv->attachments_caption);
2438 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2440 g_object_unref (mime_part);
2441 gnome_vfs_file_info_unref (info);
2448 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2451 ModestMsgEditWindowPrivate *priv;
2454 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2455 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2457 if (att_list == NULL) {
2458 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2459 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2460 g_object_unref (att_list);
2465 g_object_ref (att_list);
2468 if (tny_list_get_length (att_list) == 0) {
2469 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2471 gboolean dialog_response;
2472 gchar *message = NULL;
2473 gchar *filename = NULL;
2475 if (tny_list_get_length (att_list) == 1) {
2477 iter = tny_list_create_iterator (att_list);
2478 part = (TnyMimePart *) tny_iterator_get_current (iter);
2479 g_object_unref (iter);
2480 if (TNY_IS_MSG (part)) {
2481 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2483 filename = tny_header_dup_subject (header);
2484 g_object_unref (header);
2486 if (filename == NULL) {
2487 filename = g_strdup (_("mail_va_no_subject"));
2490 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2492 g_object_unref (part);
2494 filename = g_strdup ("");
2496 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2497 "emev_nc_delete_attachments",
2498 tny_list_get_length (att_list)), filename);
2501 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2505 if (dialog_response != GTK_RESPONSE_OK) {
2506 g_object_unref (att_list);
2510 for (iter = tny_list_create_iterator (att_list);
2511 !tny_iterator_is_done (iter);
2512 tny_iterator_next (iter)) {
2513 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2514 const gchar *att_id;
2515 tny_list_remove (priv->attachments, (GObject *) mime_part);
2517 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2519 if (tny_list_get_length (priv->attachments) == 0)
2520 gtk_widget_hide (priv->attachments_caption);
2521 att_id = tny_mime_part_get_content_id (mime_part);
2523 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2525 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2526 g_object_unref (mime_part);
2528 g_object_unref (iter);
2531 g_object_unref (att_list);
2533 /* if the last attachment has been removed, focus the Subject: field */
2534 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2535 gtk_widget_grab_focus (priv->subject_field);
2539 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2542 ModestMsgEditWindowPrivate *priv;
2543 GdkColor *new_color;
2544 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2546 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2547 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2550 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2552 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2554 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2556 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2561 font_size_clicked (GtkToolButton *button,
2562 ModestMsgEditWindow *window)
2564 ModestMsgEditWindowPrivate *priv;
2565 GtkWidget *selector, *dialog;
2567 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2569 selector = hildon_touch_selector_new ();
2570 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2571 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2573 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2574 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2575 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2577 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2581 WPTextBufferFormat format;
2583 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2585 memset (&format, 0, sizeof (format));
2586 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2588 format.cs.font_size = TRUE;
2589 format.cs.text_position = TRUE;
2590 format.cs.font = TRUE;
2591 format.font_size = new_index;
2592 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2594 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2595 GINT_TO_POINTER (new_index)))
2596 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2598 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2599 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2600 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2601 size_text, "</span>", NULL);
2603 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2607 gtk_widget_destroy (dialog);
2609 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2614 font_face_clicked (GtkToolButton *button,
2615 ModestMsgEditWindow *window)
2617 ModestMsgEditWindowPrivate *priv;
2618 GtkWidget *selector, *dialog;
2619 GtkCellRenderer *renderer;
2621 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2623 selector = hildon_touch_selector_new ();
2624 renderer = gtk_cell_renderer_text_new ();
2625 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2626 renderer, "family", 0, "text", 0, NULL);
2627 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2629 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2630 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2631 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2633 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2634 gint new_font_index;
2638 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2639 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2640 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2644 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2646 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2647 GINT_TO_POINTER(new_font_index)))
2648 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2650 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2651 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2653 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2657 gtk_tree_path_free (path);
2660 gtk_widget_destroy (dialog);
2662 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2667 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2670 ModestMsgEditWindowPrivate *priv = NULL;
2671 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2673 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2674 if (!priv->update_caption_visibility)
2677 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2679 gtk_widget_show (priv->cc_caption);
2681 gtk_widget_hide (priv->cc_caption);
2683 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2687 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2690 ModestMsgEditWindowPrivate *priv = NULL;
2691 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2693 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2694 if (!priv->update_caption_visibility)
2697 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2699 gtk_widget_show (priv->bcc_caption);
2701 gtk_widget_hide (priv->bcc_caption);
2703 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2707 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2708 ModestRecptEditor *editor)
2710 ModestMsgEditWindowPrivate *priv;
2712 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2713 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2715 /* we check for low-mem; in that case, show a warning, and don't allow
2716 * for the addressbook
2718 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2721 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2723 if (editor == NULL) {
2724 GtkWidget *view_focus;
2725 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2727 /* This code should be kept in sync with ModestRecptEditor. The
2728 textview inside the recpt editor is the one that really gets the
2729 focus. As it's inside a scrolled window, and this one inside the
2730 hbox recpt editor inherits from, we'll need to go up in the
2731 hierarchy to know if the text view is part of the recpt editor
2732 or if it's a different text entry */
2734 if (gtk_widget_get_parent (view_focus)) {
2735 GtkWidget *first_parent;
2737 first_parent = gtk_widget_get_parent (view_focus);
2738 if (gtk_widget_get_parent (first_parent) &&
2739 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2740 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2745 editor = MODEST_RECPT_EDITOR (priv->to_field);
2749 modest_address_book_select_addresses (editor);
2754 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2756 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2758 modest_msg_edit_window_open_addressbook (window, NULL);
2762 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2763 gboolean show_toolbar)
2765 ModestWindowPrivate *parent_priv;
2767 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2768 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2770 /* We can not just use the code of
2771 modest_msg_edit_window_setup_toolbar because it has a
2772 mixture of both initialization and creation code. */
2774 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2776 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2780 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2781 TnyHeaderFlags priority_flags)
2783 ModestMsgEditWindowPrivate *priv;
2784 ModestWindowPrivate *parent_priv;
2786 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2788 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2789 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2791 if (priv->priority_flags != priority_flags) {
2792 GtkAction *priority_action = NULL;
2794 priv->priority_flags = priority_flags;
2796 switch (priority_flags) {
2797 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2798 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2799 MODEST_HEADER_ICON_HIGH,
2800 HILDON_ICON_SIZE_SMALL);
2801 gtk_widget_show (priv->priority_icon);
2802 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2803 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2805 case TNY_HEADER_FLAG_LOW_PRIORITY:
2806 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2807 MODEST_HEADER_ICON_LOW,
2808 HILDON_ICON_SIZE_SMALL);
2809 gtk_widget_show (priv->priority_icon);
2810 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2811 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2814 gtk_widget_hide (priv->priority_icon);
2815 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2816 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2819 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2820 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2822 gtk_widget_queue_resize (priv->subject_box);
2826 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2829 ModestMsgEditWindowPrivate *priv;
2830 ModestWindowPrivate *parent_priv;
2831 gint current_format;
2833 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2835 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2836 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2838 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2839 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2841 if (current_format != file_format) {
2842 switch (file_format) {
2843 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2844 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2845 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2847 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2851 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2852 response = gtk_dialog_run (GTK_DIALOG (dialog));
2853 gtk_widget_destroy (dialog);
2854 if (response == GTK_RESPONSE_OK) {
2855 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2857 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2858 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2863 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2864 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2865 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2870 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2873 ModestMsgEditWindowPrivate *priv;
2874 WPTextBufferFormat oldfmt, fmt;
2875 gint old_position = 0;
2879 GdkColor *color = NULL;
2880 gboolean bold, bold_set, italic, italic_set;
2881 gboolean underline, underline_set;
2882 gboolean strikethrough, strikethrough_set;
2883 gboolean position_set;
2884 gboolean font_size_set, font_set, color_set;
2887 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2888 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2890 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2891 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2892 GTK_WINDOW(dialog), GTK_WINDOW (window));
2894 /* First we get the currently selected font information */
2895 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2897 switch (oldfmt.text_position) {
2898 case TEXT_POSITION_NORMAL:
2901 case TEXT_POSITION_SUPERSCRIPT:
2909 g_object_set (G_OBJECT (dialog),
2910 "bold", oldfmt.bold != FALSE,
2911 "bold-set", !oldfmt.cs.bold,
2912 "underline", oldfmt.underline != FALSE,
2913 "underline-set", !oldfmt.cs.underline,
2914 "italic", oldfmt.italic != FALSE,
2915 "italic-set", !oldfmt.cs.italic,
2916 "strikethrough", oldfmt.strikethrough != FALSE,
2917 "strikethrough-set", !oldfmt.cs.strikethrough,
2918 "color", &oldfmt.color,
2919 "color-set", !oldfmt.cs.color,
2920 "size", wp_font_size[oldfmt.font_size],
2921 "size-set", !oldfmt.cs.font_size,
2922 "position", old_position,
2923 "position-set", !oldfmt.cs.text_position,
2924 "family", wp_get_font_name (oldfmt.font),
2925 "family-set", !oldfmt.cs.font,
2928 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2929 GTK_WINDOW (dialog), GTK_WINDOW (window));
2930 gtk_widget_show_all (dialog);
2931 priv->font_dialog = dialog;
2932 response = gtk_dialog_run (GTK_DIALOG (dialog));
2933 priv->font_dialog = NULL;
2934 if (response == GTK_RESPONSE_OK) {
2936 g_object_get( dialog,
2938 "bold-set", &bold_set,
2939 "underline", &underline,
2940 "underline-set", &underline_set,
2942 "italic-set", &italic_set,
2943 "strikethrough", &strikethrough,
2944 "strikethrough-set", &strikethrough_set,
2946 "color-set", &color_set,
2948 "size-set", &font_size_set,
2949 "family", &font_name,
2950 "family-set", &font_set,
2951 "position", &position,
2952 "position-set", &position_set,
2957 if (response == GTK_RESPONSE_OK) {
2958 memset(&fmt, 0, sizeof(fmt));
2964 fmt.italic = italic;
2965 fmt.cs.italic = TRUE;
2967 if (underline_set) {
2968 fmt.underline = underline;
2969 fmt.cs.underline = TRUE;
2971 if (strikethrough_set) {
2972 fmt.strikethrough = strikethrough;
2973 fmt.cs.strikethrough = TRUE;
2978 ? TEXT_POSITION_NORMAL
2979 : ( ( position == 1 )
2980 ? TEXT_POSITION_SUPERSCRIPT
2981 : TEXT_POSITION_SUBSCRIPT );
2982 fmt.cs.text_position = TRUE;
2983 fmt.font_size = oldfmt.font_size;
2987 fmt.cs.color = TRUE;
2990 fmt.font = wp_get_font_index(font_name,
2995 if (font_size_set) {
2996 fmt.cs.font_size = TRUE;
2997 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2999 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3000 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3002 gtk_widget_destroy (dialog);
3004 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3008 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3010 ModestMsgEditWindowPrivate *priv;
3012 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3013 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3015 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3017 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3018 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3022 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3024 ModestMsgEditWindowPrivate *priv;
3026 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3027 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3029 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3031 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3032 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3037 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3039 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3041 priv->can_undo = can_undo;
3045 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3047 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3049 priv->can_redo = can_redo;
3053 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3055 ModestMsgEditWindowPrivate *priv;
3056 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3057 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3059 return priv->can_undo;
3063 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3065 ModestMsgEditWindowPrivate *priv;
3066 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3067 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3069 return priv->can_redo;
3074 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3077 GtkTextIter match_start, match_end;
3079 if (image_id == NULL)
3082 gtk_text_buffer_get_start_iter (buffer, &iter);
3084 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3085 GSList *tags = gtk_text_iter_get_tags (&match_start);
3087 for (node = tags; node != NULL; node = g_slist_next (node)) {
3088 GtkTextTag *tag = (GtkTextTag *) node->data;
3089 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3090 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3091 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3093 offset = gtk_text_iter_get_offset (&match_start);
3094 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3095 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3099 gtk_text_iter_forward_char (&iter);
3104 message_is_empty (ModestMsgEditWindow *window)
3106 ModestMsgEditWindowPrivate *priv = NULL;
3108 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3109 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3111 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3112 * so we can ignore markup.
3114 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3117 count = gtk_text_buffer_get_char_count (buf);
3123 msg_body_focus (GtkWidget *focus,
3124 GdkEventFocus *event,
3128 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3129 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3130 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3135 recpt_field_changed (GtkTextBuffer *buffer,
3136 ModestMsgEditWindow *editor)
3138 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3139 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3143 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3145 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3146 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3150 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3153 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3154 GtkTextBuffer *buffer;
3156 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3157 gtk_text_buffer_set_modified (buffer, modified);
3158 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3159 gtk_text_buffer_set_modified (buffer, modified);
3160 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3161 gtk_text_buffer_set_modified (buffer, modified);
3162 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3166 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3168 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3169 const char *account_name;
3170 GtkTextBuffer *buffer;
3172 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3173 if (gtk_text_buffer_get_modified (buffer))
3175 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3176 if (gtk_text_buffer_get_modified (buffer))
3178 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3179 if (gtk_text_buffer_get_modified (buffer))
3181 if (gtk_text_buffer_get_modified (priv->text_buffer))
3183 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3184 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3195 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3197 ModestMsgEditWindowPrivate *priv = NULL;
3199 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3200 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3202 /* check if there's no recipient added */
3203 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3204 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3205 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3206 /* no recipient contents, then select contacts */
3207 modest_msg_edit_window_open_addressbook (window, NULL);
3211 g_object_ref (window);
3212 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3213 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3214 g_object_unref (window);
3217 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3218 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3219 g_object_unref (window);
3222 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3223 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3224 g_object_unref (window);
3228 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3229 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3230 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3231 g_object_unref (window);
3238 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3239 ModestMsgEditWindow *window)
3241 modest_msg_edit_window_offer_attach_file (window);
3245 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3247 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3249 return priv->clipboard_text;
3253 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3255 ModestMsgEditWindow *window)
3257 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3258 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3261 /* It could happen that the window was already closed */
3262 if (!GTK_WIDGET_VISIBLE (window))
3265 g_object_ref (window);
3266 text = gtk_clipboard_wait_for_text (selection_clipboard);
3268 if (priv->clipboard_text != NULL) {
3269 g_free (priv->clipboard_text);
3271 priv->clipboard_text = text;
3273 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3275 g_object_unref (window);
3278 static gboolean clipboard_owner_change_idle (gpointer userdata)
3280 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3281 ModestMsgEditWindowPrivate *priv;
3283 gdk_threads_enter ();
3284 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3285 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3287 priv->clipboard_owner_idle = 0;
3288 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3289 gdk_threads_leave ();
3295 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3297 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3298 if (priv->clipboard_owner_idle == 0) {
3299 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3300 clipboard_owner_change_idle,
3301 g_object_ref (window),
3307 subject_field_move_cursor (GtkEntry *entry,
3308 GtkMovementStep step,
3313 /* It could happen that the window was already closed */
3314 if (!GTK_WIDGET_VISIBLE (window))
3317 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3321 update_window_title (ModestMsgEditWindow *window)
3323 ModestMsgEditWindowPrivate *priv = NULL;
3324 const gchar *subject;
3326 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3327 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3328 if (subject == NULL || subject[0] == '\0')
3329 subject = _("mail_va_new_email");
3331 gtk_window_set_title (GTK_WINDOW (window), subject);
3336 subject_field_changed (GtkEditable *editable,
3337 ModestMsgEditWindow *window)
3339 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3340 update_window_title (window);
3341 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3342 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3343 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3347 subject_field_insert_text (GtkEditable *editable,
3349 gint new_text_length,
3351 ModestMsgEditWindow *window)
3353 GString *result = g_string_new ("");
3355 gint result_len = 0;
3356 const gchar *entry_text = NULL;
3359 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3360 old_length = g_utf8_strlen (entry_text, -1);
3362 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3363 gunichar c = g_utf8_get_char_validated (current, 8);
3364 /* Invalid unichar, stop */
3370 result = g_string_append_unichar (result, c);
3374 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3375 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3378 /* Prevent endless recursion */
3379 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3380 g_signal_emit_by_name (editable, "insert-text",
3381 (gpointer) result->str, (gpointer) result->len,
3382 (gpointer) position, (gpointer) window);
3383 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3387 if (result_len + old_length > 1000) {
3388 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3389 _CS("ckdg_ib_maximum_characters_reached"));
3391 g_string_free (result, TRUE);
3395 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3398 ModestMsgEditWindowPrivate *priv = NULL;
3400 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3401 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3403 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3406 gtk_widget_show_all (priv->find_toolbar);
3407 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3409 gtk_widget_hide_all (priv->find_toolbar);
3410 gtk_widget_grab_focus (priv->msg_body);
3415 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3417 GtkTextIter *match_start,
3418 GtkTextIter *match_end)
3420 GtkTextIter end_iter;
3421 gchar *str_casefold;
3424 gchar *range_casefold;
3427 gboolean result = FALSE;
3434 gtk_text_iter_forward_to_end (&end_iter);
3436 str_casefold = g_utf8_casefold (str, -1);
3437 str_chars_n = strlen (str);
3439 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3440 range_casefold = g_utf8_casefold (range_text, -1);
3441 range_chars_n = strlen (range_casefold);
3443 if (range_chars_n < str_chars_n) {
3444 g_free (str_casefold);
3445 g_free (range_text);
3446 g_free (range_casefold);
3450 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3451 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3452 if (!g_utf8_collate (range_subtext, str_casefold)) {
3453 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3455 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3456 match_start, match_end, NULL);
3457 g_free (found_text);
3459 g_free (range_subtext);
3463 g_free (str_casefold);
3464 g_free (range_text);
3465 g_free (range_casefold);
3472 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3473 ModestMsgEditWindow *window)
3475 gchar *current_search = NULL;
3476 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3478 GtkTextIter selection_start, selection_end;
3479 GtkTextIter match_start, match_end;
3480 gboolean continue_search = FALSE;
3482 if (message_is_empty (window)) {
3483 g_free (priv->last_search);
3484 priv->last_search = NULL;
3485 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3489 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3490 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3491 g_free (current_search);
3492 g_free (priv->last_search);
3493 priv->last_search = NULL;
3494 /* Information banner about empty search */
3495 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3499 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3500 continue_search = TRUE;
3502 g_free (priv->last_search);
3503 priv->last_search = g_strdup (current_search);
3506 if (continue_search) {
3507 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3508 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3509 &match_start, &match_end);
3511 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3513 GtkTextIter buffer_start;
3514 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3515 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3516 &match_start, &match_end);
3518 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3521 /* Mark as selected the string found in search */
3523 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3524 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3525 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3527 g_free (priv->last_search);
3528 priv->last_search = NULL;
3530 g_free (current_search);
3534 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3536 ModestMsgEditWindowPrivate *priv;
3538 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3543 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3546 ModestMsgEditWindowPrivate *priv;
3548 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3553 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3554 ModestMsgEditWindow *window)
3556 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3560 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3563 ModestMsgEditWindowPrivate *priv;
3564 TnyHeader *header = NULL;
3566 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3567 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3569 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3570 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3572 if (priv->draft_msg != NULL) {
3573 g_object_unref (priv->draft_msg);
3576 if (draft != NULL) {
3577 g_object_ref (draft);
3578 header = tny_msg_get_header (draft);
3579 if (priv->msg_uid) {
3580 g_free (priv->msg_uid);
3581 priv->msg_uid = NULL;
3583 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3584 if (GTK_WIDGET_REALIZED (window)) {
3585 if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3586 gtk_widget_destroy (GTK_WIDGET (window));
3592 priv->draft_msg = draft;
3596 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3597 GtkTextIter *start, GtkTextIter *end,
3600 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3601 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3604 if (tag == NULL) return;
3605 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3606 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3607 replace_with_images (window, priv->images);
3612 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3615 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3617 g_return_if_fail (TNY_IS_MIME_PART (part));
3618 tny_list_prepend (priv->attachments, (GObject *) part);
3619 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3620 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3621 gtk_widget_show_all (priv->attachments_caption);
3622 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3626 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3628 ModestMsgEditWindowPrivate *priv;
3630 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3631 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3633 return priv->msg_uid;
3637 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3638 ModestMsgEditWindowWidgetType widget_type)
3640 ModestMsgEditWindowPrivate *priv;
3642 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3643 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3645 switch (widget_type) {
3646 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3647 return priv->msg_body;
3649 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3650 return priv->to_field;
3652 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3653 return priv->cc_field;
3655 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3656 return priv->bcc_field;
3658 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3659 return priv->subject_field;
3661 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3662 return priv->attachments_view;
3670 remove_tags (WPTextBuffer *buffer)
3672 GtkTextIter start, end;
3674 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3675 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3677 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3681 on_account_removed (TnyAccountStore *account_store,
3682 TnyAccount *account,
3685 /* Do nothing if it's a store account, because we use the
3686 transport to send the messages */
3687 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3688 const gchar *parent_acc = NULL;
3689 const gchar *our_acc = NULL;
3691 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3692 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3693 /* Close this window if I'm showing a message of the removed account */
3694 if (strcmp (parent_acc, our_acc) == 0)
3695 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3700 from_field_changed (HildonPickerButton *button,
3701 ModestMsgEditWindow *self)
3703 ModestMsgEditWindowPrivate *priv;
3704 gboolean has_old_signature, has_new_signature;
3706 GtkTextIter match_start, match_end;
3707 ModestAccountMgr *mgr;
3709 gchar *full_signature;
3711 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3713 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3714 mgr = modest_runtime_get_account_mgr ();
3715 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3716 if (has_old_signature) {
3717 full_signature = g_strconcat ("\n--\n", signature, NULL);
3718 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3719 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3721 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3722 &match_start, &match_end, NULL)) {
3725 g_free (full_signature);
3729 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3730 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3731 if (has_new_signature) {
3732 full_signature = g_strconcat ("\n--\n", signature, NULL);
3733 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3734 g_free (full_signature);
3739 typedef struct _MessageSettingsHelper {
3740 ModestMsgEditWindow *window;
3741 GSList *priority_group;
3742 GSList *format_group;
3743 GtkToggleButton *current_priority;
3744 GtkToggleButton *current_format;
3745 } MessageSettingsHelper;
3748 on_priority_toggle (GtkToggleButton *button,
3749 MessageSettingsHelper *helper)
3752 ModestMsgEditWindowPrivate *priv;
3754 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3755 if (gtk_toggle_button_get_active (button)) {
3757 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3758 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3759 if ((node_button != button) &&
3760 gtk_toggle_button_get_active (node_button)) {
3761 gtk_toggle_button_set_active (node_button, FALSE);
3764 helper->current_priority = button;
3766 gboolean found = FALSE;
3767 /* If no one is active, activate it again */
3768 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3769 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3770 if (gtk_toggle_button_get_active (node_button)) {
3776 gtk_toggle_button_set_active (button, TRUE);
3782 on_format_toggle (GtkToggleButton *button,
3783 MessageSettingsHelper *helper)
3786 ModestMsgEditWindowPrivate *priv;
3788 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3789 if (gtk_toggle_button_get_active (button)) {
3791 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3792 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3793 if ((node_button != button) &&
3794 gtk_toggle_button_get_active (node_button)) {
3795 gtk_toggle_button_set_active (node_button, FALSE);
3798 helper->current_format = button;
3800 gboolean found = FALSE;
3801 /* If no one is active, activate it again */
3802 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3803 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3804 if (gtk_toggle_button_get_active (node_button)) {
3810 gtk_toggle_button_set_active (button, TRUE);
3817 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3822 GtkWidget *priority_hbox;
3823 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3824 GtkWidget *captioned;
3825 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3826 GtkWidget *format_hbox;
3827 GtkWidget *html_toggle, *text_toggle;
3828 ModestMsgEditWindowPrivate *priv;
3829 MessageSettingsHelper helper = {0,};
3831 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3832 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3833 helper.window = window;
3834 helper.priority_group = NULL;
3835 helper.format_group = NULL;
3837 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3838 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3840 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3841 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3842 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3843 vbox = gtk_vbox_new (FALSE, 0);
3844 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3845 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3846 gtk_container_add (GTK_CONTAINER (align), vbox);
3847 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3848 gtk_widget_show (align);
3849 gtk_widget_show (vbox);
3851 /* Priority toggles */
3852 priority_hbox = gtk_hbox_new (TRUE, 0);
3853 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3854 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3855 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3856 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3857 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3858 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3859 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3860 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3861 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3862 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3863 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3864 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3865 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3866 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3867 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3868 gtk_widget_show_all (priority_hbox);
3869 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3870 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3871 gtk_widget_show (captioned);
3872 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3874 /* format toggles */
3875 format_hbox = gtk_hbox_new (TRUE, 0);
3876 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3877 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3878 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3879 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3880 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3881 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3882 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3883 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3884 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3885 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3886 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3887 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3888 gtk_widget_show_all (format_hbox);
3889 gtk_widget_show (format_hbox);
3890 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3893 g_object_unref (title_sizegroup);
3894 g_object_unref (value_sizegroup);
3896 /* Set current values */
3897 switch (priv->priority_flags) {
3898 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3899 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3900 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3902 case TNY_HEADER_FLAG_LOW_PRIORITY:
3903 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3904 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3907 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3908 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3912 switch (modest_msg_edit_window_get_format (window)) {
3913 case MODEST_MSG_EDIT_FORMAT_TEXT:
3914 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3915 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3917 case MODEST_MSG_EDIT_FORMAT_HTML:
3919 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3920 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3924 /* Signal connects */
3925 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3926 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3927 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3928 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3929 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3931 /* Save settings if the user clicked on done */
3932 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3933 TnyHeaderFlags flags;
3934 ModestMsgEditFormat old_format, new_format;
3936 /* Set priority flags */
3937 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3938 if (priv->priority_flags != flags)
3939 modest_msg_edit_window_set_priority_flags (window, flags);
3941 /* Set edit format */
3942 old_format = modest_msg_edit_window_get_format (window);
3943 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3944 if (old_format != new_format) {
3945 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3946 modest_msg_edit_window_set_file_format (window, file_format);
3950 gtk_widget_destroy (dialog);
3951 g_slist_free (helper.priority_group);
3955 on_message_settings (GtkAction *action,
3956 ModestMsgEditWindow *window)
3958 modest_msg_edit_window_show_msg_settings_dialog (window);
3962 on_cc_button_toggled (HildonCheckButton *button,
3963 ModestMsgEditWindow *window)
3965 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3967 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3968 hildon_check_button_get_active (button));
3972 on_bcc_button_toggled (HildonCheckButton *button,
3973 ModestMsgEditWindow *window)
3975 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3977 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3978 hildon_check_button_get_active (button));
3982 setup_menu (ModestMsgEditWindow *self)
3984 ModestMsgEditWindowPrivate *priv = NULL;
3986 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3988 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3990 /* Settings menu buttons */
3991 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3992 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3994 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3995 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3996 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3998 priv->cc_button = hildon_check_button_new (0);
3999 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4000 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4002 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4004 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4005 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4006 priv->bcc_button = hildon_check_button_new (0);
4007 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4008 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4010 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4012 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4013 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4015 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4016 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4017 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4018 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4019 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4020 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4021 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4022 APP_MENU_CALLBACK (on_message_settings),
4024 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4025 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),