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_font_change (GtkCheckMenuItem *menu_item,
122 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
124 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
125 ModestRecptEditor *editor);
126 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
127 ModestMsgEditWindow *window);
129 /* ModestWindow methods implementation */
130 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
131 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
132 gboolean show_toolbar);
133 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
135 ModestMsgEditWindow *window);
136 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
137 static void subject_field_move_cursor (GtkEntry *entry,
138 GtkMovementStep step,
142 static void update_window_title (ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
148 ModestMsgEditWindow *window);
149 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
151 GtkTextIter *match_start,
152 GtkTextIter *match_end);
154 static void remove_tags (WPTextBuffer *buffer);
156 static void on_account_removed (TnyAccountStore *account_store,
160 static void init_window (ModestMsgEditWindow *obj);
162 gboolean scroll_drag_timeout (gpointer userdata);
163 static void correct_scroll (ModestMsgEditWindow *w);
164 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
165 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
166 ModestMsgEditWindow *userdata);
167 static void text_buffer_mark_set (GtkTextBuffer *buffer,
170 ModestMsgEditWindow *userdata);
171 static void on_message_settings (GtkAction *action,
172 ModestMsgEditWindow *window);
173 static void setup_menu (ModestMsgEditWindow *self);
175 static void from_field_changed (HildonPickerButton *button,
176 ModestMsgEditWindow *self);
177 static void font_size_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 GtkWidget *font_tool_button_label;
267 GtkTreeModel *sizes_model;
268 gint current_size_index;
269 GtkWidget *size_tool_button_label;
271 GtkWidget *find_toolbar;
274 GtkWidget *font_dialog;
277 guint correct_scroll_idle;
278 guint scroll_drag_timeout_id;
282 TnyList *attachments;
287 TnyHeaderFlags priority_flags;
289 gboolean can_undo, can_redo;
290 gulong clipboard_change_handler_id;
291 gulong default_clipboard_change_handler_id;
292 gulong account_removed_handler_id;
293 guint clipboard_owner_idle;
294 gchar *clipboard_text;
303 GtkWidget *cc_button;
304 GtkWidget *bcc_button;
307 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
308 MODEST_TYPE_MSG_EDIT_WINDOW, \
309 ModestMsgEditWindowPrivate))
311 static GtkWindowClass *parent_class = NULL;
313 /* uncomment the following if you have defined any signals */
314 /* static guint signals[LAST_SIGNAL] = {0}; */
317 modest_msg_edit_window_get_type (void)
319 static GType my_type = 0;
321 static const GTypeInfo my_info = {
322 sizeof(ModestMsgEditWindowClass),
323 NULL, /* base init */
324 NULL, /* base finalize */
325 (GClassInitFunc) modest_msg_edit_window_class_init,
326 NULL, /* class finalize */
327 NULL, /* class data */
328 sizeof(ModestMsgEditWindow),
330 (GInstanceInitFunc) modest_msg_edit_window_init,
333 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
334 "ModestMsgEditWindow",
342 save_state (ModestWindow *self)
344 modest_widget_memory_save (modest_runtime_get_conf(),
345 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
350 restore_settings (ModestMsgEditWindow *self)
352 ModestConf *conf = NULL;
354 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
356 conf = modest_runtime_get_conf ();
358 /* Dim at start clipboard actions */
359 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
360 gtk_action_set_sensitive (action, FALSE);
361 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
362 gtk_action_set_sensitive (action, FALSE);
363 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
364 gtk_action_set_sensitive (action, FALSE);
366 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
371 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
373 GObjectClass *gobject_class;
374 ModestWindowClass *modest_window_class;
375 gobject_class = (GObjectClass*) klass;
376 modest_window_class = (ModestWindowClass*) klass;
378 parent_class = g_type_class_peek_parent (klass);
379 gobject_class->finalize = modest_msg_edit_window_finalize;
381 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
382 modest_window_class->save_state_func = save_state;
383 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
385 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
389 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
391 ModestMsgEditWindowPrivate *priv;
392 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
394 priv->msg_body = NULL;
395 priv->from_field = NULL;
396 priv->to_field = NULL;
397 priv->cc_field = NULL;
398 priv->bcc_field = NULL;
399 priv->subject_field = NULL;
400 priv->attachments = TNY_LIST (tny_simple_list_new ());
401 priv->images = TNY_LIST (tny_simple_list_new ());
402 priv->images_size = 0;
403 priv->images_count = 0;
406 priv->cc_caption = NULL;
407 priv->bcc_caption = NULL;
408 priv->update_caption_visibility = FALSE;
410 priv->priority_flags = 0;
412 priv->find_toolbar = NULL;
413 priv->last_search = NULL;
415 priv->draft_msg = NULL;
416 priv->outbox_msg = NULL;
417 priv->msg_uid = NULL;
419 priv->can_undo = FALSE;
420 priv->can_redo = FALSE;
421 priv->clipboard_change_handler_id = 0;
422 priv->default_clipboard_change_handler_id = 0;
423 priv->account_removed_handler_id = 0;
424 priv->clipboard_owner_idle = 0;
425 priv->clipboard_text = NULL;
428 priv->scroll_drag_timeout_id = 0;
429 priv->correct_scroll_idle = 0;
430 priv->last_upper = 0.0;
432 priv->font_dialog = NULL;
433 priv->app_menu = NULL;
435 if (!is_wp_text_buffer_started) {
436 is_wp_text_buffer_started = TRUE;
437 wp_text_buffer_library_init ();
442 hildon_program_add_window (hildon_program_get_instance(),
448 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
450 static ModestPairList*
451 get_transports (void)
453 GSList *transports = NULL;
455 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
456 GSList *accounts = modest_account_mgr_account_names (account_mgr,
457 TRUE /* only enabled accounts. */);
459 GSList *cursor = accounts;
461 gchar *account_name = cursor->data;
462 gchar *from_string = NULL;
464 from_string = modest_account_mgr_get_from_string (account_mgr,
468 if (from_string && account_name) {
469 gchar *name = account_name;
470 ModestPair *pair = modest_pair_new ((gpointer) name,
471 (gpointer) from_string , TRUE);
472 transports = g_slist_prepend (transports, pair);
475 cursor = cursor->next;
477 g_slist_free (accounts); /* only free the accounts, not the elements,
478 * because they are used in the pairlist */
482 static void window_focus (GtkWindow *window,
486 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
490 scroll_drag_timeout (gpointer userdata)
492 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
493 ModestMsgEditWindowPrivate *priv;
495 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
497 correct_scroll_without_drag_check (win, TRUE);
499 priv->scroll_drag_timeout_id = 0;
505 correct_scroll_without_drag_check_idle (gpointer userdata)
507 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
508 ModestMsgEditWindowPrivate *priv;
510 GdkRectangle rectangle;
511 gint offset_min, offset_max;
515 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
517 insert = gtk_text_buffer_get_insert (priv->text_buffer);
518 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
520 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
521 offset_min = priv->msg_body->allocation.y + rectangle.y;
522 offset_max = offset_min + rectangle.height;
524 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
525 offset_min = MAX (offset_min - 48, 0);
526 offset_max = MIN (offset_max + 48, vadj->upper);
528 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
530 priv->correct_scroll_idle = 0;
535 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
537 ModestMsgEditWindowPrivate *priv;
539 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
541 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
544 if (priv->correct_scroll_idle > 0) {
548 priv->correct_scroll_idle = g_idle_add ((GSourceFunc) correct_scroll_without_drag_check_idle,
553 correct_scroll (ModestMsgEditWindow *w)
555 ModestMsgEditWindowPrivate *priv;
557 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
558 if (gtk_grab_get_current () == priv->msg_body) {
559 if (priv->scroll_drag_timeout_id == 0) {
560 priv->scroll_drag_timeout_id = g_timeout_add (500, (GSourceFunc) scroll_drag_timeout,
566 correct_scroll_without_drag_check (w, TRUE);
570 text_buffer_end_user_action (GtkTextBuffer *buffer,
571 ModestMsgEditWindow *userdata)
574 correct_scroll (userdata);
578 text_buffer_mark_set (GtkTextBuffer *buffer,
581 ModestMsgEditWindow *userdata)
583 gtk_text_buffer_begin_user_action (buffer);
584 gtk_text_buffer_end_user_action (buffer);
588 cut_clipboard_check (GtkTextView *text_view,
591 GtkTextBuffer *buffer;
593 buffer = gtk_text_view_get_buffer (text_view);
594 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
595 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
600 copy_clipboard_check (GtkTextView *text_view,
603 GtkTextBuffer *buffer;
605 buffer = gtk_text_view_get_buffer (text_view);
606 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
607 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
612 attachment_deleted (ModestAttachmentsView *attachments_view,
615 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
620 connect_signals (ModestMsgEditWindow *obj)
622 ModestMsgEditWindowPrivate *priv;
624 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
626 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
627 G_CALLBACK (text_buffer_refresh_attributes), obj);
628 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
629 G_CALLBACK (text_buffer_can_undo), obj);
630 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
631 G_CALLBACK (text_buffer_can_redo), obj);
632 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
633 G_CALLBACK (body_changed), obj);
634 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
635 G_CALLBACK (body_changed), obj);
636 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
637 G_CALLBACK (text_buffer_end_user_action), obj);
638 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
639 G_CALLBACK (text_buffer_mark_set), obj);
640 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
641 G_CALLBACK (text_buffer_apply_tag), obj);
642 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
643 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
644 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
645 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
646 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
647 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
649 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
650 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
651 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
652 G_CALLBACK (from_field_changed), obj);
654 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
655 G_CALLBACK (msg_body_focus), obj);
656 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
657 G_CALLBACK (msg_body_focus), obj);
658 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
659 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
660 "changed", G_CALLBACK (recpt_field_changed), obj);
661 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
662 "changed", G_CALLBACK (recpt_field_changed), obj);
663 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
664 "changed", G_CALLBACK (recpt_field_changed), obj);
665 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
666 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
667 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
669 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
670 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
672 priv->clipboard_change_handler_id =
673 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
674 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
675 priv->default_clipboard_change_handler_id =
676 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
677 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
679 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
680 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
681 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
685 init_wp_text_view_style ()
687 static gboolean initialized = FALSE;
690 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
696 init_window (ModestMsgEditWindow *obj)
698 GtkWidget *to_caption, *subject_caption;
699 GtkWidget *main_vbox;
700 GtkWidget *add_attachment_align;
701 ModestMsgEditWindowPrivate *priv;
702 GtkActionGroup *action_group;
703 ModestWindowPrivate *parent_priv;
704 GdkPixbuf *window_icon = NULL;
705 GError *error = NULL;
707 GtkSizeGroup *title_size_group;
708 GtkSizeGroup *value_size_group;
709 GtkWidget *attachment_icon;
710 GtkWidget *window_box;
711 GtkWidget *window_align;
712 #if (GTK_MINOR_VERSION >= 10)
713 GdkAtom deserialize_type;
716 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
717 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
719 parent_priv->ui_manager = gtk_ui_manager_new();
720 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
721 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
723 /* Add common actions */
724 gtk_action_group_add_actions (action_group,
725 modest_msg_edit_action_entries,
726 G_N_ELEMENTS (modest_msg_edit_action_entries),
728 gtk_action_group_add_actions (action_group,
729 hildon2_msg_edit_action_entries,
730 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
732 gtk_action_group_add_toggle_actions (action_group,
733 modest_msg_edit_toggle_action_entries,
734 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
736 gtk_action_group_add_radio_actions (action_group,
737 modest_msg_edit_alignment_radio_action_entries,
738 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
740 G_CALLBACK (modest_ui_actions_on_change_justify),
742 gtk_action_group_add_radio_actions (action_group,
743 modest_msg_edit_priority_action_entries,
744 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
746 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
748 gtk_action_group_add_radio_actions (action_group,
749 modest_msg_edit_file_format_action_entries,
750 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
751 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
752 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
754 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
755 g_object_unref (action_group);
757 /* Load the UI definition */
758 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
761 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
762 g_clear_error (&error);
765 /* Add accelerators */
766 gtk_window_add_accel_group (GTK_WINDOW (obj),
767 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
769 parent_priv->menubar = NULL;
771 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
772 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
774 /* Note: This ModestPairList* must exist for as long as the picker
775 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
776 * so it can't know how to manage its memory. */
777 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
778 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
780 modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group,
781 _("mail_va_from"), priv->from_field);
783 priv->to_field = modest_recpt_editor_new ();
784 priv->cc_field = modest_recpt_editor_new ();
785 priv->bcc_field = modest_recpt_editor_new ();
786 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
787 priv->priority_icon = gtk_image_new ();
788 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
789 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
790 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
791 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
792 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
793 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
794 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
795 priv->add_attachment_button = hildon_button_new (MODEST_EDITABLE_SIZE, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
796 gtk_widget_set_size_request (priv->add_attachment_button, ATTACHMENT_BUTTON_WIDTH, -1);
797 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
798 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
799 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
800 hildon_button_set_image (HILDON_BUTTON (priv->add_attachment_button), attachment_icon);
801 add_attachment_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
802 gtk_alignment_set_padding (GTK_ALIGNMENT (add_attachment_align), 0, 0, MODEST_MARGIN_DEFAULT, 0);
803 gtk_container_add (GTK_CONTAINER (add_attachment_align), priv->add_attachment_button);
804 gtk_box_pack_start (GTK_BOX (priv->subject_box), add_attachment_align, FALSE, FALSE, 0);
805 priv->attachments_view = modest_attachments_view_new (NULL);
806 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
807 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
809 priv->header_box = gtk_vbox_new (FALSE, 0);
811 to_caption = modest_maemo_utils_create_captioned_with_size_type
812 (title_size_group, value_size_group,
813 _("mail_va_to"), FALSE, priv->to_field,
814 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
815 priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type
816 (title_size_group, value_size_group,
817 _("mail_va_cc"), FALSE, priv->cc_field,
818 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
819 priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
820 (title_size_group, value_size_group,
821 _("mail_va_hotfix1"), FALSE, priv->bcc_field,
822 HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
823 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
824 _("mail_va_subject"), FALSE, priv->subject_box);
825 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
826 _("mail_va_attachment"),
828 priv->attachments_view,
829 HILDON_SIZE_AUTO_WIDTH |
830 HILDON_SIZE_AUTO_HEIGHT);
831 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
832 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
833 /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
834 g_object_unref (title_size_group);
835 g_object_unref (value_size_group);
837 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
838 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
839 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
840 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
841 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
842 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
843 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
845 init_wp_text_view_style ();
847 priv->msg_body = modest_wp_text_view_new ();
850 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
851 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
852 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
853 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
854 #if (GTK_MINOR_VERSION >= 10)
855 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
856 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
858 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
859 deserialize_type, TRUE);
861 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
863 priv->find_toolbar = hildon_find_toolbar_new (NULL);
864 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
866 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
868 priv->pannable = hildon_pannable_area_new ();
870 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
871 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
872 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
874 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
875 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
876 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
878 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
879 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox),
880 hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable)));
881 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
883 window_box = gtk_vbox_new (FALSE, 0);
884 gtk_container_add (GTK_CONTAINER(obj), window_box);
886 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
888 /* Set window icon */
889 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
891 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
892 g_object_unref (window_icon);
897 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
899 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
901 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
902 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
903 priv->clipboard_change_handler_id))
904 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
905 priv->clipboard_change_handler_id);
906 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
907 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
908 priv->default_clipboard_change_handler_id))
909 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
910 priv->default_clipboard_change_handler_id);
912 if (priv->account_removed_handler_id &&
913 g_signal_handler_is_connected (modest_runtime_get_account_store (),
914 priv->account_removed_handler_id))
915 g_signal_handler_disconnect(modest_runtime_get_account_store (),
916 priv->account_removed_handler_id);
920 modest_msg_edit_window_finalize (GObject *obj)
922 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
924 /* Sanity check: shouldn't be needed, the window mgr should
925 call this function before */
926 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
928 if (priv->font_dialog != NULL) {
929 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
932 if (priv->clipboard_text != NULL) {
933 g_free (priv->clipboard_text);
934 priv->clipboard_text = NULL;
937 if (priv->draft_msg != NULL) {
938 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
939 if (TNY_IS_HEADER (header)) {
940 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
941 modest_window_mgr_unregister_header (mgr, header);
943 g_object_unref (priv->draft_msg);
944 priv->draft_msg = NULL;
946 if (priv->outbox_msg != NULL) {
947 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
948 if (TNY_IS_HEADER (header)) {
949 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
950 modest_window_mgr_unregister_header (mgr, header);
952 g_object_unref (priv->outbox_msg);
953 priv->outbox_msg = NULL;
955 if (priv->correct_scroll_idle > 0) {
956 g_source_remove (priv->correct_scroll_idle);
957 priv->correct_scroll_idle = 0;
959 if (priv->scroll_drag_timeout_id > 0) {
960 g_source_remove (priv->scroll_drag_timeout_id);
961 priv->scroll_drag_timeout_id = 0;
963 if (priv->clipboard_owner_idle > 0) {
964 g_source_remove (priv->clipboard_owner_idle);
965 priv->clipboard_owner_idle = 0;
967 if (priv->original_account_name)
968 g_free (priv->original_account_name);
969 g_free (priv->msg_uid);
970 g_free (priv->last_search);
971 g_slist_free (priv->font_items_group);
972 g_object_unref (priv->sizes_model);
973 g_object_unref (priv->attachments);
974 g_object_unref (priv->images);
976 /* This had to stay alive for as long as the picker that used it: */
977 modest_pair_list_free (priv->from_field_protos);
979 G_OBJECT_CLASS(parent_class)->finalize (obj);
983 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type, guint64 *stream_size)
985 GdkPixbufLoader *loader;
991 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
993 if (loader == NULL) {
999 tny_stream_reset (TNY_STREAM (stream));
1000 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1001 GError *error = NULL;
1002 unsigned char read_buffer[128];
1004 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1006 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1008 g_error_free (error);
1013 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1015 g_object_ref (pixbuf);
1016 gdk_pixbuf_loader_close (loader, NULL);
1017 g_object_unref (loader);
1022 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1023 GdkPixbuf *new_pixbuf;
1025 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1026 gdk_pixbuf_get_width (pixbuf);
1027 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1028 g_object_unref (pixbuf);
1029 pixbuf = new_pixbuf;
1033 *stream_size = size;
1039 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1041 ModestMsgEditWindowPrivate *priv;
1044 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1046 for (iter = tny_list_create_iterator (attachments);
1047 !tny_iterator_is_done (iter);
1048 tny_iterator_next (iter)) {
1049 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1050 const gchar *cid = tny_mime_part_get_content_id (part);
1051 const gchar *mime_type = tny_mime_part_get_content_type (part);
1052 if ((cid != NULL)&&(mime_type != NULL)) {
1053 guint64 stream_size;
1054 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1055 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
1058 g_object_unref (stream);
1060 if (pixbuf != NULL) {
1061 priv->images_count ++;
1062 priv->images_size += stream_size;
1063 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1064 g_object_unref (pixbuf);
1067 g_object_unref (part);
1069 g_object_unref (iter);
1073 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1075 TnyMimePart *parent = NULL;
1076 const gchar *content_type = NULL;
1077 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1079 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1081 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1082 parent = g_object_ref (msg);
1083 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1084 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1087 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1088 iter = tny_list_create_iterator (parts);
1089 while (!tny_iterator_is_done (iter)) {
1091 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1092 content_type = tny_mime_part_get_content_type (part);
1093 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1097 g_object_unref (part);
1099 tny_iterator_next (iter);
1101 g_object_unref (iter);
1102 g_object_unref (parts);
1105 if (parent != NULL) {
1106 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1109 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1110 iter = tny_list_create_iterator (parts);
1111 while (!tny_iterator_is_done (iter)) {
1113 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1114 content_type = tny_mime_part_get_content_type (part);
1115 if (content_type && g_str_has_prefix (content_type, "image/")) {
1116 tny_list_prepend (priv->images, (GObject *) part);
1118 g_object_unref (part);
1119 tny_iterator_next (iter);
1121 g_object_unref (iter);
1122 g_object_unref (parts);
1123 g_object_unref (parent);
1128 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1131 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1133 for (iter = tny_list_create_iterator (attachments) ;
1134 !tny_iterator_is_done (iter);
1135 tny_iterator_next (iter)) {
1136 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1137 const gchar *cid = tny_mime_part_get_content_id (part);
1139 char *invalid = NULL;
1140 gint int_cid = strtol (cid, &invalid, 10);
1141 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1142 priv->next_cid = int_cid + 1;
1145 g_object_unref (part);
1147 g_object_unref (iter);
1151 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1154 gchar *to, *cc, *bcc, *subject;
1156 ModestMsgEditWindowPrivate *priv;
1157 ModestWindowPrivate *parent_priv;
1159 TnyHeaderFlags priority_flags;
1160 TnyFolder *msg_folder;
1161 gboolean is_html = FALSE;
1162 gboolean field_view_set;
1164 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1165 g_return_if_fail (TNY_IS_MSG (msg));
1167 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1168 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1170 header = tny_msg_get_header (msg);
1171 to = tny_header_dup_to (header);
1172 cc = tny_header_dup_cc (header);
1173 bcc = tny_header_dup_bcc (header);
1174 subject = tny_header_dup_subject (header);
1175 priority_flags = tny_header_get_priority (header);
1178 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1180 field_view_set = TRUE;
1182 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1183 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1184 gtk_widget_show (priv->cc_caption);
1185 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1186 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1187 gtk_widget_hide (priv->cc_caption);
1188 field_view_set = FALSE;
1190 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1192 field_view_set = TRUE;
1194 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1195 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1196 gtk_widget_show (priv->bcc_caption);
1197 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1198 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1199 gtk_widget_hide (priv->bcc_caption);
1200 field_view_set = FALSE;
1202 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1206 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1207 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1210 update_window_title (self);
1212 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1213 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1215 if ((body == NULL)||(body[0] == '\0')) {
1217 body = modest_text_utils_convert_to_html ("");
1220 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1221 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1224 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1227 /* Add attachments to the view */
1228 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1229 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1230 if (tny_list_get_length (priv->attachments) == 0) {
1231 gtk_widget_hide (priv->attachments_caption);
1233 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1234 gtk_widget_show_all (priv->attachments_caption);
1236 get_related_images (self, msg);
1237 update_next_cid (self, priv->attachments);
1238 update_next_cid (self, priv->images);
1239 replace_with_images (self, priv->images);
1241 if (preserve_is_rich && !is_html) {
1242 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1243 /* Get the default format required from configuration */
1244 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1245 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1248 /* Set the default focus depending on having already a To: field or not */
1249 if ((!to)||(*to == '\0')) {
1250 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1252 gtk_widget_grab_focus (priv->msg_body);
1255 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1257 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1258 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1260 modest_msg_edit_window_set_modified (self, FALSE);
1262 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1263 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1264 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1265 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1267 if (priv->msg_uid) {
1268 g_free (priv->msg_uid);
1269 priv->msg_uid = NULL;
1272 /* we should set a reference to the incoming message if it is a draft */
1273 msg_folder = tny_msg_get_folder (msg);
1275 if (modest_tny_folder_is_local_folder (msg_folder)) {
1276 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1277 if (type == TNY_FOLDER_TYPE_INVALID)
1278 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1280 if (type == TNY_FOLDER_TYPE_DRAFTS)
1281 priv->draft_msg = g_object_ref(msg);
1282 if (type == TNY_FOLDER_TYPE_OUTBOX)
1283 priv->outbox_msg = g_object_ref(msg);
1284 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1286 g_object_unref (msg_folder);
1296 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1299 GList *item_children, *node;
1300 GtkWidget *bin_child;
1302 bin_child = gtk_bin_get_child (GTK_BIN(item));
1304 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1306 for (node = item_children; node != NULL; node = g_list_next (node)) {
1307 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1308 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1311 g_list_free (item_children);
1315 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1318 GList *item_children, *node;
1320 box = gtk_bin_get_child (GTK_BIN (item));
1321 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1322 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1324 for (node = item_children; node != NULL; node = g_list_next (node)) {
1325 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1326 if (GTK_IS_TOGGLE_BUTTON (node->data))
1327 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1328 else if (GTK_IS_BUTTON (node->data))
1329 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1331 g_list_free (item_children);
1336 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1338 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1339 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1340 GtkWidget *placeholder;
1341 GtkWidget *tool_item;
1346 GtkWidget *sizes_menu;
1347 GtkWidget *fonts_menu;
1348 GSList *radio_group = NULL;
1349 GSList *node = NULL;
1355 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1356 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1357 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1358 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1360 /* Font color placeholder */
1361 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1362 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1365 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1366 priv->font_color_button = hildon_color_button_new ();
1367 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1368 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1369 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1370 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1371 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1372 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1373 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1374 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1376 G_CALLBACK (modest_msg_edit_window_color_button_change),
1379 /* Font size and face placeholder */
1380 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1381 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1383 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1384 priv->size_tool_button_label = gtk_label_new (NULL);
1385 hildon_helper_set_logical_color (GTK_WIDGET (priv->size_tool_button_label), GTK_RC_TEXT,
1386 GTK_STATE_INSENSITIVE, "SecondaryTextColor");
1387 hildon_helper_set_logical_color (GTK_WIDGET (priv->size_tool_button_label), GTK_RC_FG,
1388 GTK_STATE_INSENSITIVE, "SecondaryTextColor");
1389 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1390 ldots_len = g_unichar_to_utf8 (0x2026, ldots);
1391 ldots[ldots_len] = '\0';
1392 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1393 size_text, ldots, "</span>", NULL);
1394 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1396 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1397 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1398 sizes_menu = gtk_menu_new ();
1399 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1400 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1403 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1404 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1406 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1410 if (wp_font_size[size_index] == 12)
1411 priv->current_size_index = size_index;
1415 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1416 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1417 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), FALSE);
1418 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), FALSE);
1419 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1420 priv->font_size_toolitem = tool_item;
1423 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1424 priv->font_tool_button_label = gtk_label_new (NULL);
1425 hildon_helper_set_logical_color (GTK_WIDGET (priv->font_tool_button_label), GTK_RC_TEXT,
1426 GTK_STATE_INSENSITIVE, "SecondaryTextColor");
1427 hildon_helper_set_logical_color (GTK_WIDGET (priv->font_tool_button_label), GTK_RC_FG,
1428 GTK_STATE_INSENSITIVE, "SecondaryTextColor");
1429 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1430 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1432 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1433 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1434 fonts_menu = gtk_menu_new ();
1435 priv->font_items_group = NULL;
1437 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1438 GtkWidget *font_menu_item;
1439 GtkWidget *child_label;
1441 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1442 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1443 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1444 wp_get_font_name (font_index), "</span>", NULL);
1445 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1448 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1449 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1450 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1451 gtk_widget_show (font_menu_item);
1453 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1456 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1457 GtkWidget *item = (GtkWidget *) node->data;
1458 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1461 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1462 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1463 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1464 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1465 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), FALSE);
1466 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), FALSE);
1467 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1468 priv->font_face_toolitem = tool_item;
1470 /* Set expand and homogeneous for remaining items */
1471 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1472 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1473 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1474 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1475 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1476 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1477 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1478 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1479 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1481 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1482 will not show the tool items added to the placeholders) */
1483 gtk_widget_show_all (parent_priv->toolbar);
1485 /* Set the no show all *after* showing all items. We do not
1486 want the toolbar to be shown with a show all because it
1487 could go agains the gconf setting regarding showing or not
1488 the toolbar of the editor window */
1489 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1495 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1498 ModestWindowPrivate *parent_priv;
1499 ModestMsgEditWindowPrivate *priv;
1500 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1501 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1502 ModestWindowMgr *mgr = NULL;
1504 g_return_val_if_fail (msg, NULL);
1505 g_return_val_if_fail (account_name, NULL);
1507 mgr = modest_runtime_get_window_mgr ();
1509 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1511 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1512 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1514 /* Menubar. Update the state of some toggles */
1515 priv->from_field_protos = get_transports ();
1516 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1517 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1518 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1519 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1521 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1522 hildon_touch_selector_get_current_text
1523 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1524 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1525 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1528 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1530 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1532 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1534 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1536 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1537 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1538 /* Add common dimming rules */
1539 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1540 modest_msg_edit_window_toolbar_dimming_entries,
1541 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1542 MODEST_WINDOW (obj));
1543 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1544 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1545 MODEST_WINDOW (obj));
1546 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1547 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1548 MODEST_WINDOW (obj));
1549 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1550 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1551 MODEST_WINDOW (obj));
1552 /* Insert dimming rules group for this window */
1553 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1554 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1556 /* Setup app menu */
1557 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1559 /* Checks the dimming rules */
1560 g_object_unref (toolbar_rules_group);
1561 g_object_unref (clipboard_rules_group);
1562 gtk_widget_hide (priv->priority_icon);
1563 gtk_widget_queue_resize (priv->subject_box);
1564 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1566 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1568 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1569 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1570 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1571 priv->update_caption_visibility = TRUE;
1573 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1575 /* Track account-removed signal, this window should be closed
1576 in the case we're creating a mail associated to the account
1578 priv->account_removed_handler_id =
1579 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1581 G_CALLBACK(on_account_removed),
1584 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1586 return (ModestWindow*) obj;
1590 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1592 GString **string_buffer = (GString **) user_data;
1594 *string_buffer = g_string_append (*string_buffer, buffer);
1600 * @result: A new string which should be freed with g_free().
1603 get_formatted_data (ModestMsgEditWindow *edit_window)
1605 ModestMsgEditWindowPrivate *priv;
1606 GString *string_buffer = g_string_new ("");
1608 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1610 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1612 modest_text_utils_hyperlinkify (string_buffer);
1614 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1616 return g_string_free (string_buffer, FALSE);
1621 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1624 const gchar *account_name;
1625 ModestMsgEditWindowPrivate *priv;
1626 TnyIterator *att_iter;
1628 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1630 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1632 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1633 g_return_val_if_fail (account_name, NULL);
1636 /* don't free these (except from) */
1637 data = g_slice_new0 (MsgData);
1638 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1640 data->account_name = g_strdup (account_name);
1641 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1642 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1643 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1644 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1645 if (priv->draft_msg) {
1646 data->draft_msg = g_object_ref (priv->draft_msg);
1647 } else if (priv->outbox_msg) {
1648 data->draft_msg = g_object_ref (priv->outbox_msg);
1650 data->draft_msg = NULL;
1653 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1655 gtk_text_buffer_get_bounds (buf, &b, &e);
1656 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1658 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1659 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1661 data->html_body = NULL;
1663 /* deep-copy the data */
1664 att_iter = tny_list_create_iterator (priv->attachments);
1665 data->attachments = NULL;
1666 while (!tny_iterator_is_done (att_iter)) {
1667 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1668 if (!(TNY_IS_MIME_PART(part))) {
1669 g_warning ("strange data in attachment list");
1670 g_object_unref (part);
1671 tny_iterator_next (att_iter);
1674 data->attachments = g_list_append (data->attachments,
1676 tny_iterator_next (att_iter);
1678 g_object_unref (att_iter);
1680 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1681 att_iter = tny_list_create_iterator (priv->images);
1682 data->images = NULL;
1683 while (!tny_iterator_is_done (att_iter)) {
1684 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1686 if (!(TNY_IS_MIME_PART(part))) {
1687 g_warning ("strange data in attachment list");
1688 g_object_unref (part);
1689 tny_iterator_next (att_iter);
1692 cid = tny_mime_part_get_content_id (part);
1694 gchar *image_tag_id;
1695 GtkTextTag *image_tag;
1697 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1698 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1699 g_free (image_tag_id);
1701 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1703 ((gtk_text_iter_has_tag (&iter, image_tag))||
1704 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1705 data->images = g_list_append (data->images,
1706 g_object_ref (part));
1708 g_object_unref (part);
1709 tny_iterator_next (att_iter);
1711 g_object_unref (att_iter);
1713 data->priority_flags = priv->priority_flags;
1720 unref_gobject (GObject *obj, gpointer data)
1722 if (!G_IS_OBJECT(obj))
1724 g_object_unref (obj);
1728 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1731 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1739 g_free (data->from);
1740 g_free (data->subject);
1741 g_free (data->plain_body);
1742 g_free (data->html_body);
1743 g_free (data->account_name);
1745 if (data->draft_msg != NULL) {
1746 g_object_unref (data->draft_msg);
1747 data->draft_msg = NULL;
1750 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1751 g_list_free (data->attachments);
1752 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1753 g_list_free (data->images);
1755 g_slice_free (MsgData, data);
1759 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1761 guint64 *parts_size)
1763 ModestMsgEditWindowPrivate *priv;
1765 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1767 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1769 /* TODO: add images */
1770 *parts_size += priv->images_size;
1771 *parts_count += priv->images_count;
1776 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1779 ModestMsgEditWindowPrivate *priv = NULL;
1780 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1782 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1784 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1786 return MODEST_MSG_EDIT_FORMAT_HTML;
1788 return MODEST_MSG_EDIT_FORMAT_TEXT;
1792 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1793 ModestMsgEditFormat format)
1795 ModestMsgEditWindowPrivate *priv;
1797 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1801 case MODEST_MSG_EDIT_FORMAT_HTML:
1802 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1804 case MODEST_MSG_EDIT_FORMAT_TEXT:
1805 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1808 g_return_if_reached ();
1812 ModestMsgEditFormatState *
1813 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1815 ModestMsgEditFormatState *format_state = NULL;
1816 ModestMsgEditWindowPrivate *priv;
1817 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1819 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1820 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1822 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1824 format_state = g_new0 (ModestMsgEditFormatState, 1);
1825 format_state->bold = buffer_format->bold&0x1;
1826 format_state->italics = buffer_format->italic&0x1;
1827 format_state->bullet = buffer_format->bullet&0x1;
1828 format_state->color = buffer_format->color;
1829 format_state->font_size = buffer_format->font_size;
1830 format_state->font_family = wp_get_font_name (buffer_format->font);
1831 format_state->justification = buffer_format->justification;
1832 g_free (buffer_format);
1834 return format_state;
1839 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1840 const ModestMsgEditFormatState *format_state)
1842 ModestMsgEditWindowPrivate *priv;
1843 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1844 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1845 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1846 g_return_if_fail (format_state != NULL);
1848 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1849 gtk_widget_grab_focus (priv->msg_body);
1850 buffer_format->bold = (format_state->bold != FALSE);
1851 buffer_format->italic = (format_state->italics != FALSE);
1852 buffer_format->color = format_state->color;
1853 buffer_format->font_size = format_state->font_size;
1854 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1855 buffer_format->justification = format_state->justification;
1856 buffer_format->bullet = format_state->bullet;
1858 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1860 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1861 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1862 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1863 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1864 buffer_format->cs.font = (buffer_format->font != current_format->font);
1865 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1866 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1868 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1869 if (buffer_format->cs.bold) {
1870 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1871 GINT_TO_POINTER (buffer_format->bold&0x1));
1873 if (buffer_format->cs.italic) {
1874 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1875 GINT_TO_POINTER (buffer_format->italic&0x1));
1877 if (buffer_format->cs.color) {
1878 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1879 GINT_TO_POINTER (&(buffer_format->color)));
1881 if (buffer_format->cs.font_size) {
1882 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1883 GINT_TO_POINTER (buffer_format->font_size));
1885 if (buffer_format->cs.justification) {
1886 switch (buffer_format->justification) {
1887 case GTK_JUSTIFY_LEFT:
1888 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1889 GINT_TO_POINTER(TRUE));
1891 case GTK_JUSTIFY_CENTER:
1892 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1893 GINT_TO_POINTER(TRUE));
1895 case GTK_JUSTIFY_RIGHT:
1896 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1897 GINT_TO_POINTER(TRUE));
1904 if (buffer_format->cs.font) {
1905 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1906 GINT_TO_POINTER (buffer_format->font));
1908 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1909 if (buffer_format->cs.bullet) {
1910 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1911 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1913 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1915 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1917 g_free (buffer_format);
1918 g_free (current_format);
1920 /* Check dimming rules */
1921 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1922 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1926 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1928 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1930 ModestWindowPrivate *parent_priv;
1931 ModestMsgEditWindowPrivate *priv;
1932 GtkWidget *new_font_menuitem;
1934 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1935 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1937 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1938 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1939 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1940 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1942 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1943 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1944 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1947 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1949 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1950 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1952 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1953 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1955 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1956 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1959 switch (buffer_format->justification)
1961 case GTK_JUSTIFY_LEFT:
1962 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1964 case GTK_JUSTIFY_CENTER:
1965 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1967 case GTK_JUSTIFY_RIGHT:
1968 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1975 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1977 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1978 G_CALLBACK (modest_msg_edit_window_color_button_change),
1980 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1981 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1982 G_CALLBACK (modest_msg_edit_window_color_button_change),
1985 if (priv->current_size_index != buffer_format->font_size) {
1989 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1990 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1996 priv->current_size_index = buffer_format->font_size;
1998 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
1999 ldots_len = g_unichar_to_utf8 (0x2026, ldots);
2000 ldots[ldots_len] = '\0';
2001 markup = g_strconcat ("<span font_family='Sans'>",
2002 size_text, ldots, "</span>", NULL);
2004 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2008 gtk_tree_path_free (path);
2011 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
2012 buffer_format->font))->data);
2013 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
2017 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
2018 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2019 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2021 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
2022 G_CALLBACK (modest_msg_edit_window_font_change),
2024 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
2025 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
2026 G_CALLBACK (modest_msg_edit_window_font_change),
2030 g_free (buffer_format);
2034 #ifdef MODEST_HILDON_VERSION_0
2036 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2039 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2040 ModestMsgEditWindowPrivate *priv;
2041 GtkWidget *dialog = NULL;
2043 GdkColor *new_color = NULL;
2045 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2046 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2048 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2049 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2050 g_free (buffer_format);
2052 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2053 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2054 if (new_color != NULL) {
2055 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2056 (gpointer) new_color);
2059 gtk_widget_destroy (dialog);
2064 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2067 ModestMsgEditWindowPrivate *priv;
2068 GtkWidget *dialog = NULL;
2070 GdkColor *old_color = NULL;
2071 const GdkColor *new_color = NULL;
2073 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2074 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2076 dialog = hildon_color_selector_new (GTK_WINDOW (window));
2077 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2079 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2080 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2081 if (new_color != NULL)
2082 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2084 gtk_widget_destroy (dialog);
2090 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2093 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2094 ModestMsgEditWindowPrivate *priv;
2095 GtkWidget *dialog = NULL;
2097 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2098 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2100 dialog = hildon_color_chooser_new ();
2101 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2102 g_free (buffer_format);
2104 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2106 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2107 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2110 gtk_widget_destroy (dialog);
2115 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2118 ModestMsgEditWindowPrivate *priv;
2119 GtkWidget *dialog = NULL;
2120 GdkColor *old_color = NULL;
2122 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2123 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2125 dialog = hildon_color_chooser_new ();
2126 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2128 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2130 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2131 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2133 gtk_widget_destroy (dialog);
2136 #endif /*!MODEST_HILDON_VERSION_0*/
2141 create_stream_for_uri (const gchar* uri)
2146 TnyStream *result = NULL;
2148 GnomeVFSHandle *handle = NULL;
2149 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2150 if (test == GNOME_VFS_OK) {
2151 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2152 /* Streams over OBEX (Bluetooth) are not seekable but
2153 * we expect them to be (we might need to read them
2154 * several times). So if this is a Bluetooth URI just
2155 * read the whole file into memory (this is not a fast
2156 * protocol so we can assume that these files are not
2157 * going to be very big) */
2158 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2159 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2160 TnyStream *memstream = tny_camel_mem_stream_new ();
2161 tny_stream_write_to_stream (vfssstream, memstream);
2162 g_object_unref (vfssstream);
2165 result = vfssstream;
2173 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2176 ModestMsgEditWindowPrivate *priv;
2177 GtkWidget *dialog = NULL;
2179 GSList *uris = NULL;
2180 GSList *uri_node = NULL;
2182 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2184 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2185 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2186 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2188 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2190 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2191 GTK_WINDOW (dialog), GTK_WINDOW (window));
2193 response = gtk_dialog_run (GTK_DIALOG (dialog));
2195 case GTK_RESPONSE_OK:
2196 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2201 gtk_widget_destroy (dialog);
2203 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2205 GnomeVFSHandle *handle = NULL;
2206 GnomeVFSResult result;
2207 GtkTextIter position;
2208 GtkTextMark *insert_mark;
2210 uri = (const gchar *) uri_node->data;
2211 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2212 if (result == GNOME_VFS_OK) {
2214 GnomeVFSFileInfo *info;
2215 gchar *filename, *basename, *escaped_filename;
2216 TnyMimePart *mime_part;
2218 const gchar *mime_type = NULL;
2219 GnomeVFSURI *vfs_uri;
2220 guint64 stream_size;
2222 gnome_vfs_close (handle);
2223 vfs_uri = gnome_vfs_uri_new (uri);
2225 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2226 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2227 g_free (escaped_filename);
2228 gnome_vfs_uri_unref (vfs_uri);
2229 info = gnome_vfs_file_info_new ();
2231 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2232 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2234 mime_type = gnome_vfs_file_info_get_mime_type (info);
2236 mime_part = tny_platform_factory_new_mime_part
2237 (modest_runtime_get_platform_factory ());
2239 TnyStream *stream = create_stream_for_uri (uri);
2241 if (stream == NULL) {
2243 modest_platform_information_banner (NULL, NULL,
2244 _FM("sfil_ib_opening_not_allowed"));
2246 g_object_unref (mime_part);
2247 gnome_vfs_file_info_unref (info);
2251 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2253 content_id = g_strdup_printf ("%d", priv->next_cid);
2254 tny_mime_part_set_content_id (mime_part, content_id);
2255 g_free (content_id);
2258 basename = g_path_get_basename (filename);
2259 tny_mime_part_set_filename (mime_part, basename);
2262 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2264 if (pixbuf != NULL) {
2265 priv->images_size += stream_size;
2266 priv->images_count ++;
2267 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2268 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2269 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2270 g_object_unref (pixbuf);
2273 tny_list_prepend (priv->images, (GObject *) mime_part);
2274 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2276 g_object_unref (mime_part);
2277 gnome_vfs_file_info_unref (info);
2286 on_attach_file_response (GtkDialog *dialog,
2290 GSList *uris = NULL;
2292 GnomeVFSFileSize total_size, allowed_size;
2293 ModestMsgEditWindow *window;
2294 ModestMsgEditWindowPrivate *priv;
2299 case GTK_RESPONSE_OK:
2300 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2306 window = MODEST_MSG_EDIT_WINDOW (user_data);
2307 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2309 /* allowed size is the maximum size - what's already there */
2310 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2311 &att_num, &att_size);
2312 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2315 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2317 const gchar *uri = (const gchar *) uri_node->data;
2320 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2322 if (total_size > allowed_size) {
2323 g_warning ("%s: total size: %u",
2324 __FUNCTION__, (unsigned int)total_size);
2327 allowed_size -= total_size;
2329 g_slist_foreach (uris, (GFunc) g_free, NULL);
2330 g_slist_free (uris);
2332 gtk_widget_destroy (GTK_WIDGET (dialog));
2336 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2338 GtkWidget *dialog = NULL;
2339 ModestMsgEditWindowPrivate *priv;
2341 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2343 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2345 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2348 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2349 GTK_FILE_CHOOSER_ACTION_OPEN);
2350 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2351 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2352 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2353 GTK_WINDOW (dialog), GTK_WINDOW (window));
2355 /* Connect to response & show */
2356 g_signal_connect (dialog, "response",
2357 G_CALLBACK (on_attach_file_response), window);
2358 gtk_widget_show (dialog);
2363 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2365 GnomeVFSFileSize allowed_size)
2368 GnomeVFSHandle *handle = NULL;
2369 ModestMsgEditWindowPrivate *priv;
2370 GnomeVFSResult result;
2371 GnomeVFSFileSize size = 0;
2372 g_return_val_if_fail (window, 0);
2373 g_return_val_if_fail (uri, 0);
2375 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2377 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2378 if (result == GNOME_VFS_OK) {
2379 TnyMimePart *mime_part;
2381 const gchar *mime_type = NULL;
2383 gchar *escaped_filename;
2386 GnomeVFSFileInfo *info;
2387 GnomeVFSURI *vfs_uri;
2389 gnome_vfs_close (handle);
2390 vfs_uri = gnome_vfs_uri_new (uri);
2393 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2394 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2395 g_free (escaped_filename);
2396 gnome_vfs_uri_unref (vfs_uri);
2398 info = gnome_vfs_file_info_new ();
2400 if (gnome_vfs_get_file_info (uri,
2402 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2404 mime_type = gnome_vfs_file_info_get_mime_type (info);
2405 mime_part = tny_platform_factory_new_mime_part
2406 (modest_runtime_get_platform_factory ());
2408 /* try to get the attachment's size; this may fail for weird
2409 * file systems, like obex, upnp... */
2410 if (allowed_size != 0 &&
2411 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2413 if (size > allowed_size) {
2414 modest_platform_information_banner (NULL, NULL,
2415 _FM("sfil_ib_opening_not_allowed"));
2419 g_warning ("%s: could not get attachment size", __FUNCTION__);
2421 stream = create_stream_for_uri (uri);
2423 if (stream == NULL) {
2425 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2427 g_object_unref (mime_part);
2428 gnome_vfs_file_info_unref (info);
2432 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2433 g_object_unref (stream);
2435 content_id = g_strdup_printf ("%d", priv->next_cid);
2436 tny_mime_part_set_content_id (mime_part, content_id);
2437 g_free (content_id);
2440 basename = g_path_get_basename (filename);
2441 tny_mime_part_set_filename (mime_part, basename);
2444 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2445 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2447 info->size == 0, info->size);
2448 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2449 gtk_widget_show_all (priv->attachments_caption);
2450 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2452 g_object_unref (mime_part);
2453 gnome_vfs_file_info_unref (info);
2460 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2463 ModestMsgEditWindowPrivate *priv;
2466 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2467 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2469 if (att_list == NULL) {
2470 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2471 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2472 g_object_unref (att_list);
2477 g_object_ref (att_list);
2480 if (tny_list_get_length (att_list) == 0) {
2481 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2483 gboolean dialog_response;
2484 gchar *message = NULL;
2485 gchar *filename = NULL;
2487 if (tny_list_get_length (att_list) == 1) {
2489 iter = tny_list_create_iterator (att_list);
2490 part = (TnyMimePart *) tny_iterator_get_current (iter);
2491 g_object_unref (iter);
2492 if (TNY_IS_MSG (part)) {
2493 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2495 filename = tny_header_dup_subject (header);
2496 g_object_unref (header);
2498 if (filename == NULL) {
2499 filename = g_strdup (_("mail_va_no_subject"));
2502 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2504 g_object_unref (part);
2506 filename = g_strdup ("");
2508 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2509 "emev_nc_delete_attachments",
2510 tny_list_get_length (att_list)), filename);
2513 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2517 if (dialog_response != GTK_RESPONSE_OK) {
2518 g_object_unref (att_list);
2522 for (iter = tny_list_create_iterator (att_list);
2523 !tny_iterator_is_done (iter);
2524 tny_iterator_next (iter)) {
2525 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2526 const gchar *att_id;
2527 tny_list_remove (priv->attachments, (GObject *) mime_part);
2529 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2531 if (tny_list_get_length (priv->attachments) == 0)
2532 gtk_widget_hide (priv->attachments_caption);
2533 att_id = tny_mime_part_get_content_id (mime_part);
2535 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2537 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2538 g_object_unref (mime_part);
2540 g_object_unref (iter);
2543 g_object_unref (att_list);
2545 /* if the last attachment has been removed, focus the Subject: field */
2546 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2547 gtk_widget_grab_focus (priv->subject_field);
2551 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2554 ModestMsgEditWindowPrivate *priv;
2555 GdkColor *new_color;
2556 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2558 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2559 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2562 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2564 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2566 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2568 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2573 font_size_clicked (GtkToolButton *button,
2574 ModestMsgEditWindow *window)
2576 ModestMsgEditWindowPrivate *priv;
2577 GtkWidget *selector, *dialog;
2579 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2581 selector = hildon_touch_selector_new ();
2582 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2583 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2585 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2586 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2588 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2592 WPTextBufferFormat format;
2596 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2598 memset (&format, 0, sizeof (format));
2599 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2601 format.cs.font_size = TRUE;
2602 format.cs.text_position = TRUE;
2603 format.cs.font = TRUE;
2604 format.font_size = new_index;
2605 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2607 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2608 GINT_TO_POINTER (new_index)))
2609 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2611 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2612 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2613 ldots_len = g_unichar_to_utf8 (0x2026, ldots);
2614 ldots[ldots_len] = '\0';
2615 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2616 size_text, ldots, "</span>", NULL);
2618 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2622 gtk_widget_destroy (dialog);
2624 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2629 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2632 ModestMsgEditWindowPrivate *priv;
2633 gint new_font_index;
2634 ModestMsgEditWindow *window;
2637 window = MODEST_MSG_EDIT_WINDOW (userdata);
2638 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2639 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2641 if (gtk_check_menu_item_get_active (menu_item)) {
2644 label = gtk_bin_get_child (GTK_BIN (menu_item));
2646 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2648 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2649 GINT_TO_POINTER(new_font_index)))
2650 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2652 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2653 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2654 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2660 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2663 ModestMsgEditWindowPrivate *priv = NULL;
2664 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2666 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2667 if (!priv->update_caption_visibility)
2670 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2672 gtk_widget_show (priv->cc_caption);
2674 gtk_widget_hide (priv->cc_caption);
2676 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2680 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2683 ModestMsgEditWindowPrivate *priv = NULL;
2684 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2686 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2687 if (!priv->update_caption_visibility)
2690 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2692 gtk_widget_show (priv->bcc_caption);
2694 gtk_widget_hide (priv->bcc_caption);
2696 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2700 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2701 ModestRecptEditor *editor)
2703 ModestMsgEditWindowPrivate *priv;
2705 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2706 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2708 /* we check for low-mem; in that case, show a warning, and don't allow
2709 * for the addressbook
2711 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2714 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2716 if (editor == NULL) {
2717 GtkWidget *view_focus;
2718 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2720 /* This code should be kept in sync with ModestRecptEditor. The
2721 textview inside the recpt editor is the one that really gets the
2722 focus. As it's inside a scrolled window, and this one inside the
2723 hbox recpt editor inherits from, we'll need to go up in the
2724 hierarchy to know if the text view is part of the recpt editor
2725 or if it's a different text entry */
2727 if (gtk_widget_get_parent (view_focus)) {
2728 GtkWidget *first_parent;
2730 first_parent = gtk_widget_get_parent (view_focus);
2731 if (gtk_widget_get_parent (first_parent) &&
2732 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2733 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2738 editor = MODEST_RECPT_EDITOR (priv->to_field);
2742 modest_address_book_select_addresses (editor);
2747 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2749 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2751 modest_msg_edit_window_open_addressbook (window, NULL);
2755 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2756 gboolean show_toolbar)
2758 ModestWindowPrivate *parent_priv;
2760 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2761 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2763 /* We can not just use the code of
2764 modest_msg_edit_window_setup_toolbar because it has a
2765 mixture of both initialization and creation code. */
2767 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2769 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2773 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2774 TnyHeaderFlags priority_flags)
2776 ModestMsgEditWindowPrivate *priv;
2777 ModestWindowPrivate *parent_priv;
2779 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2781 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2782 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2784 if (priv->priority_flags != priority_flags) {
2785 GtkAction *priority_action = NULL;
2787 priv->priority_flags = priority_flags;
2789 switch (priority_flags) {
2790 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2791 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2792 MODEST_HEADER_ICON_HIGH,
2793 HILDON_ICON_SIZE_SMALL);
2794 gtk_widget_show (priv->priority_icon);
2795 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2796 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2798 case TNY_HEADER_FLAG_LOW_PRIORITY:
2799 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2800 MODEST_HEADER_ICON_LOW,
2801 HILDON_ICON_SIZE_SMALL);
2802 gtk_widget_show (priv->priority_icon);
2803 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2804 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2807 gtk_widget_hide (priv->priority_icon);
2808 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2809 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2812 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2813 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2815 gtk_widget_queue_resize (priv->subject_box);
2819 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2822 ModestMsgEditWindowPrivate *priv;
2823 ModestWindowPrivate *parent_priv;
2824 gint current_format;
2826 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2828 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2829 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2831 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2832 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2834 if (current_format != file_format) {
2835 switch (file_format) {
2836 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2837 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2838 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2840 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2844 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2845 response = gtk_dialog_run (GTK_DIALOG (dialog));
2846 gtk_widget_destroy (dialog);
2847 if (response == GTK_RESPONSE_OK) {
2848 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2850 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2851 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2856 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2857 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2858 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2863 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2866 ModestMsgEditWindowPrivate *priv;
2867 WPTextBufferFormat oldfmt, fmt;
2868 gint old_position = 0;
2872 GdkColor *color = NULL;
2873 gboolean bold, bold_set, italic, italic_set;
2874 gboolean underline, underline_set;
2875 gboolean strikethrough, strikethrough_set;
2876 gboolean position_set;
2877 gboolean font_size_set, font_set, color_set;
2880 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2881 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2883 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2884 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2885 GTK_WINDOW(dialog), GTK_WINDOW (window));
2887 /* First we get the currently selected font information */
2888 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2890 switch (oldfmt.text_position) {
2891 case TEXT_POSITION_NORMAL:
2894 case TEXT_POSITION_SUPERSCRIPT:
2902 g_object_set (G_OBJECT (dialog),
2903 "bold", oldfmt.bold != FALSE,
2904 "bold-set", !oldfmt.cs.bold,
2905 "underline", oldfmt.underline != FALSE,
2906 "underline-set", !oldfmt.cs.underline,
2907 "italic", oldfmt.italic != FALSE,
2908 "italic-set", !oldfmt.cs.italic,
2909 "strikethrough", oldfmt.strikethrough != FALSE,
2910 "strikethrough-set", !oldfmt.cs.strikethrough,
2911 "color", &oldfmt.color,
2912 "color-set", !oldfmt.cs.color,
2913 "size", wp_font_size[oldfmt.font_size],
2914 "size-set", !oldfmt.cs.font_size,
2915 "position", old_position,
2916 "position-set", !oldfmt.cs.text_position,
2917 "family", wp_get_font_name (oldfmt.font),
2918 "family-set", !oldfmt.cs.font,
2921 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2922 GTK_WINDOW (dialog), GTK_WINDOW (window));
2923 gtk_widget_show_all (dialog);
2924 priv->font_dialog = dialog;
2925 response = gtk_dialog_run (GTK_DIALOG (dialog));
2926 priv->font_dialog = NULL;
2927 if (response == GTK_RESPONSE_OK) {
2929 g_object_get( dialog,
2931 "bold-set", &bold_set,
2932 "underline", &underline,
2933 "underline-set", &underline_set,
2935 "italic-set", &italic_set,
2936 "strikethrough", &strikethrough,
2937 "strikethrough-set", &strikethrough_set,
2939 "color-set", &color_set,
2941 "size-set", &font_size_set,
2942 "family", &font_name,
2943 "family-set", &font_set,
2944 "position", &position,
2945 "position-set", &position_set,
2950 if (response == GTK_RESPONSE_OK) {
2951 memset(&fmt, 0, sizeof(fmt));
2957 fmt.italic = italic;
2958 fmt.cs.italic = TRUE;
2960 if (underline_set) {
2961 fmt.underline = underline;
2962 fmt.cs.underline = TRUE;
2964 if (strikethrough_set) {
2965 fmt.strikethrough = strikethrough;
2966 fmt.cs.strikethrough = TRUE;
2971 ? TEXT_POSITION_NORMAL
2972 : ( ( position == 1 )
2973 ? TEXT_POSITION_SUPERSCRIPT
2974 : TEXT_POSITION_SUBSCRIPT );
2975 fmt.cs.text_position = TRUE;
2976 fmt.font_size = oldfmt.font_size;
2980 fmt.cs.color = TRUE;
2983 fmt.font = wp_get_font_index(font_name,
2988 if (font_size_set) {
2989 fmt.cs.font_size = TRUE;
2990 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2992 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2993 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2995 gtk_widget_destroy (dialog);
2997 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3001 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3003 ModestMsgEditWindowPrivate *priv;
3005 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3006 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3008 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3010 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3011 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3015 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3017 ModestMsgEditWindowPrivate *priv;
3019 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3020 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3022 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3024 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3025 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3030 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3032 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3034 priv->can_undo = can_undo;
3038 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3040 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3042 priv->can_redo = can_redo;
3046 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3048 ModestMsgEditWindowPrivate *priv;
3049 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3050 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3052 return priv->can_undo;
3056 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3058 ModestMsgEditWindowPrivate *priv;
3059 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3060 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3062 return priv->can_redo;
3067 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3070 GtkTextIter match_start, match_end;
3072 if (image_id == NULL)
3075 gtk_text_buffer_get_start_iter (buffer, &iter);
3077 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3078 GSList *tags = gtk_text_iter_get_tags (&match_start);
3080 for (node = tags; node != NULL; node = g_slist_next (node)) {
3081 GtkTextTag *tag = (GtkTextTag *) node->data;
3082 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3083 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3084 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3086 offset = gtk_text_iter_get_offset (&match_start);
3087 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3088 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3092 gtk_text_iter_forward_char (&iter);
3097 message_is_empty (ModestMsgEditWindow *window)
3099 ModestMsgEditWindowPrivate *priv = NULL;
3101 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3102 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3104 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3105 * so we can ignore markup.
3107 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3110 count = gtk_text_buffer_get_char_count (buf);
3116 msg_body_focus (GtkWidget *focus,
3117 GdkEventFocus *event,
3121 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3122 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3123 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3128 recpt_field_changed (GtkTextBuffer *buffer,
3129 ModestMsgEditWindow *editor)
3131 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3132 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3136 body_changed (GtkTextBuffer *buffer, 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 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3146 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3147 GtkTextBuffer *buffer;
3149 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3150 gtk_text_buffer_set_modified (buffer, modified);
3151 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3152 gtk_text_buffer_set_modified (buffer, modified);
3153 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3154 gtk_text_buffer_set_modified (buffer, modified);
3155 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3159 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3161 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3162 const char *account_name;
3163 GtkTextBuffer *buffer;
3165 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3166 if (gtk_text_buffer_get_modified (buffer))
3168 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3169 if (gtk_text_buffer_get_modified (buffer))
3171 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3172 if (gtk_text_buffer_get_modified (buffer))
3174 if (gtk_text_buffer_get_modified (priv->text_buffer))
3176 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3177 if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3188 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3190 ModestMsgEditWindowPrivate *priv = NULL;
3192 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3193 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3195 /* check if there's no recipient added */
3196 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3197 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3198 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3199 /* no recipient contents, then select contacts */
3200 modest_msg_edit_window_open_addressbook (window, NULL);
3204 g_object_ref (window);
3205 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
3206 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3207 g_object_unref (window);
3210 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
3211 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3212 g_object_unref (window);
3215 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3216 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3217 g_object_unref (window);
3221 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3222 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3223 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3224 g_object_unref (window);
3231 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3232 ModestMsgEditWindow *window)
3234 modest_msg_edit_window_offer_attach_file (window);
3238 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3240 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3242 return priv->clipboard_text;
3246 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3248 ModestMsgEditWindow *window)
3250 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3251 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3253 if (!GTK_WIDGET_VISIBLE (window))
3256 g_object_ref (window);
3257 text = gtk_clipboard_wait_for_text (selection_clipboard);
3259 if (priv->clipboard_text != NULL) {
3260 g_free (priv->clipboard_text);
3262 priv->clipboard_text = text;
3264 if (GTK_WIDGET_VISIBLE (window)) {
3265 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3267 g_object_unref (window);
3270 static gboolean clipboard_owner_change_idle (gpointer userdata)
3272 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3273 ModestMsgEditWindowPrivate *priv;
3275 gdk_threads_enter ();
3276 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3277 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3279 priv->clipboard_owner_idle = 0;
3280 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3281 gdk_threads_leave ();
3287 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3289 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3290 if (priv->clipboard_owner_idle == 0) {
3291 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3296 subject_field_move_cursor (GtkEntry *entry,
3297 GtkMovementStep step,
3302 if (!GTK_WIDGET_VISIBLE (window))
3305 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3309 update_window_title (ModestMsgEditWindow *window)
3311 ModestMsgEditWindowPrivate *priv = NULL;
3312 const gchar *subject;
3314 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3315 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3316 if (subject == NULL || subject[0] == '\0')
3317 subject = _("mail_va_new_email");
3319 gtk_window_set_title (GTK_WINDOW (window), subject);
3324 subject_field_changed (GtkEditable *editable,
3325 ModestMsgEditWindow *window)
3327 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3328 update_window_title (window);
3329 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3330 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3331 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3335 subject_field_insert_text (GtkEditable *editable,
3337 gint new_text_length,
3339 ModestMsgEditWindow *window)
3341 GString *result = g_string_new ("");
3343 gint result_len = 0;
3344 const gchar *entry_text = NULL;
3347 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3348 old_length = g_utf8_strlen (entry_text, -1);
3350 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3351 gunichar c = g_utf8_get_char_validated (current, 8);
3352 /* Invalid unichar, stop */
3358 result = g_string_append_unichar (result, c);
3362 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3363 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3366 /* Prevent endless recursion */
3367 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3368 g_signal_emit_by_name (editable, "insert-text",
3369 (gpointer) result->str, (gpointer) result->len,
3370 (gpointer) position, (gpointer) window);
3371 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3375 if (result_len + old_length > 1000) {
3376 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3377 _CS("ckdg_ib_maximum_characters_reached"));
3379 g_string_free (result, TRUE);
3383 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3386 ModestMsgEditWindowPrivate *priv = NULL;
3388 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3389 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3391 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3394 gtk_widget_show_all (priv->find_toolbar);
3395 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3397 gtk_widget_hide_all (priv->find_toolbar);
3398 gtk_widget_grab_focus (priv->msg_body);
3403 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3405 GtkTextIter *match_start,
3406 GtkTextIter *match_end)
3408 GtkTextIter end_iter;
3409 gchar *str_casefold;
3412 gchar *range_casefold;
3415 gboolean result = FALSE;
3422 gtk_text_iter_forward_to_end (&end_iter);
3424 str_casefold = g_utf8_casefold (str, -1);
3425 str_chars_n = strlen (str);
3427 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3428 range_casefold = g_utf8_casefold (range_text, -1);
3429 range_chars_n = strlen (range_casefold);
3431 if (range_chars_n < str_chars_n) {
3432 g_free (str_casefold);
3433 g_free (range_text);
3434 g_free (range_casefold);
3438 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3439 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3440 if (!g_utf8_collate (range_subtext, str_casefold)) {
3441 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3443 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3444 match_start, match_end, NULL);
3445 g_free (found_text);
3447 g_free (range_subtext);
3451 g_free (str_casefold);
3452 g_free (range_text);
3453 g_free (range_casefold);
3460 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3461 ModestMsgEditWindow *window)
3463 gchar *current_search = NULL;
3464 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3466 GtkTextIter selection_start, selection_end;
3467 GtkTextIter match_start, match_end;
3468 gboolean continue_search = FALSE;
3470 if (message_is_empty (window)) {
3471 g_free (priv->last_search);
3472 priv->last_search = NULL;
3473 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3477 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3478 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3479 g_free (current_search);
3480 g_free (priv->last_search);
3481 priv->last_search = NULL;
3482 /* Information banner about empty search */
3483 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3487 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3488 continue_search = TRUE;
3490 g_free (priv->last_search);
3491 priv->last_search = g_strdup (current_search);
3494 if (continue_search) {
3495 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3496 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3497 &match_start, &match_end);
3499 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3501 GtkTextIter buffer_start;
3502 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3503 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3504 &match_start, &match_end);
3506 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3509 /* Mark as selected the string found in search */
3511 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3512 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3513 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3515 g_free (priv->last_search);
3516 priv->last_search = NULL;
3518 g_free (current_search);
3522 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3524 ModestMsgEditWindowPrivate *priv;
3526 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3531 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3534 ModestMsgEditWindowPrivate *priv;
3536 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3541 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3542 ModestMsgEditWindow *window)
3544 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3548 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3551 ModestMsgEditWindowPrivate *priv;
3552 TnyHeader *header = NULL;
3554 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3555 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3557 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3558 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3560 if (priv->draft_msg != NULL) {
3561 g_object_unref (priv->draft_msg);
3564 if (draft != NULL) {
3565 g_object_ref (draft);
3566 header = tny_msg_get_header (draft);
3567 if (priv->msg_uid) {
3568 g_free (priv->msg_uid);
3569 priv->msg_uid = NULL;
3571 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3572 if (GTK_WIDGET_REALIZED (window)) {
3573 if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3574 gtk_widget_destroy (GTK_WIDGET (window));
3580 priv->draft_msg = draft;
3584 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3585 GtkTextIter *start, GtkTextIter *end,
3588 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3589 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3592 if (tag == NULL) return;
3593 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3594 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3595 replace_with_images (window, priv->images);
3600 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3603 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3605 g_return_if_fail (TNY_IS_MIME_PART (part));
3606 tny_list_prepend (priv->attachments, (GObject *) part);
3607 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3608 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3609 gtk_widget_show_all (priv->attachments_caption);
3610 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3614 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3616 ModestMsgEditWindowPrivate *priv;
3618 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3619 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3621 return priv->msg_uid;
3625 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3626 ModestMsgEditWindowWidgetType widget_type)
3628 ModestMsgEditWindowPrivate *priv;
3630 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3631 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3633 switch (widget_type) {
3634 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3635 return priv->msg_body;
3637 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3638 return priv->to_field;
3640 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3641 return priv->cc_field;
3643 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3644 return priv->bcc_field;
3646 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3647 return priv->subject_field;
3649 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3650 return priv->attachments_view;
3658 remove_tags (WPTextBuffer *buffer)
3660 GtkTextIter start, end;
3662 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3663 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3665 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3669 on_account_removed (TnyAccountStore *account_store,
3670 TnyAccount *account,
3673 /* Do nothing if it's a store account, because we use the
3674 transport to send the messages */
3675 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3676 const gchar *parent_acc = NULL;
3677 const gchar *our_acc = NULL;
3679 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3680 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3681 /* Close this window if I'm showing a message of the removed account */
3682 if (strcmp (parent_acc, our_acc) == 0)
3683 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3688 from_field_changed (HildonPickerButton *button,
3689 ModestMsgEditWindow *self)
3691 ModestMsgEditWindowPrivate *priv;
3692 gboolean has_old_signature, has_new_signature;
3694 GtkTextIter match_start, match_end;
3695 ModestAccountMgr *mgr;
3697 gchar *full_signature;
3699 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3701 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3702 mgr = modest_runtime_get_account_mgr ();
3703 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3704 if (has_old_signature) {
3705 full_signature = g_strconcat ("\n--\n", signature, NULL);
3706 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3707 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3709 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3710 &match_start, &match_end, NULL)) {
3713 g_free (full_signature);
3717 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3718 signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3719 if (has_new_signature) {
3720 full_signature = g_strconcat ("\n--\n", signature, NULL);
3721 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3722 g_free (full_signature);
3727 typedef struct _MessageSettingsHelper {
3728 ModestMsgEditWindow *window;
3729 GSList *priority_group;
3730 GSList *format_group;
3731 GtkToggleButton *current_priority;
3732 GtkToggleButton *current_format;
3733 } MessageSettingsHelper;
3736 on_priority_toggle (GtkToggleButton *button,
3737 MessageSettingsHelper *helper)
3740 ModestMsgEditWindowPrivate *priv;
3742 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3743 if (gtk_toggle_button_get_active (button)) {
3745 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3746 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3747 if ((node_button != button) &&
3748 gtk_toggle_button_get_active (node_button)) {
3749 gtk_toggle_button_set_active (node_button, FALSE);
3752 helper->current_priority = button;
3754 gboolean found = FALSE;
3755 /* If no one is active, activate it again */
3756 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3757 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3758 if (gtk_toggle_button_get_active (node_button)) {
3764 gtk_toggle_button_set_active (button, TRUE);
3770 on_format_toggle (GtkToggleButton *button,
3771 MessageSettingsHelper *helper)
3774 ModestMsgEditWindowPrivate *priv;
3776 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3777 if (gtk_toggle_button_get_active (button)) {
3779 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3780 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3781 if ((node_button != button) &&
3782 gtk_toggle_button_get_active (node_button)) {
3783 gtk_toggle_button_set_active (node_button, FALSE);
3786 helper->current_format = button;
3788 gboolean found = FALSE;
3789 /* If no one is active, activate it again */
3790 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3791 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3792 if (gtk_toggle_button_get_active (node_button)) {
3798 gtk_toggle_button_set_active (button, TRUE);
3805 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3810 GtkWidget *priority_hbox;
3811 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3812 GtkWidget *captioned;
3813 GtkSizeGroup *title_sizegroup, *value_sizegroup;
3814 GtkWidget *format_hbox;
3815 GtkWidget *html_toggle, *text_toggle;
3816 ModestMsgEditWindowPrivate *priv;
3817 MessageSettingsHelper helper = {0,};
3819 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3820 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3821 helper.window = window;
3822 helper.priority_group = NULL;
3823 helper.format_group = NULL;
3825 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3826 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3828 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3829 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3830 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3831 vbox = gtk_vbox_new (FALSE, 0);
3832 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3833 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3834 gtk_container_add (GTK_CONTAINER (align), vbox);
3835 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3836 gtk_widget_show (align);
3837 gtk_widget_show (vbox);
3839 /* Priority toggles */
3840 priority_hbox = gtk_hbox_new (TRUE, 0);
3841 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3842 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3843 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3844 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3845 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3846 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3847 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3848 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3849 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3850 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3851 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3852 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3853 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3854 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3855 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3856 gtk_widget_show_all (priority_hbox);
3857 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3858 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3859 gtk_widget_show (captioned);
3860 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3862 /* format toggles */
3863 format_hbox = gtk_hbox_new (TRUE, 0);
3864 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3865 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3866 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3867 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3868 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3869 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3870 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3871 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3872 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3873 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3874 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3875 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3876 gtk_widget_show_all (format_hbox);
3877 gtk_widget_show (format_hbox);
3878 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3881 g_object_unref (title_sizegroup);
3882 g_object_unref (value_sizegroup);
3884 /* Set current values */
3885 switch (priv->priority_flags) {
3886 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3887 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3888 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3890 case TNY_HEADER_FLAG_LOW_PRIORITY:
3891 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3892 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3895 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3896 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3900 switch (modest_msg_edit_window_get_format (window)) {
3901 case MODEST_MSG_EDIT_FORMAT_TEXT:
3902 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3903 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3905 case MODEST_MSG_EDIT_FORMAT_HTML:
3907 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3908 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3912 /* Signal connects */
3913 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3914 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3915 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3916 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3917 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3919 /* Save settings if the user clicked on done */
3920 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3921 TnyHeaderFlags flags;
3922 ModestMsgEditFormat old_format, new_format;
3924 /* Set priority flags */
3925 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3926 if (priv->priority_flags != flags)
3927 modest_msg_edit_window_set_priority_flags (window, flags);
3929 /* Set edit format */
3930 old_format = modest_msg_edit_window_get_format (window);
3931 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3932 if (old_format != new_format) {
3933 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3934 modest_msg_edit_window_set_file_format (window, file_format);
3938 gtk_widget_destroy (dialog);
3939 g_slist_free (helper.priority_group);
3943 on_message_settings (GtkAction *action,
3944 ModestMsgEditWindow *window)
3946 modest_msg_edit_window_show_msg_settings_dialog (window);
3950 on_cc_button_toggled (HildonCheckButton *button,
3951 ModestMsgEditWindow *window)
3953 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3955 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3956 hildon_check_button_get_active (button));
3960 on_bcc_button_toggled (HildonCheckButton *button,
3961 ModestMsgEditWindow *window)
3963 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3965 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3966 hildon_check_button_get_active (button));
3970 setup_menu (ModestMsgEditWindow *self)
3972 ModestMsgEditWindowPrivate *priv = NULL;
3974 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3976 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3978 /* Settings menu buttons */
3979 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3980 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3982 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3983 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3984 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3986 priv->cc_button = hildon_check_button_new (0);
3987 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
3988 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
3990 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
3992 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
3993 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
3994 priv->bcc_button = hildon_check_button_new (0);
3995 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
3996 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
3998 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4000 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4001 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4003 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4004 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4005 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4006 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4007 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4008 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4009 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4010 APP_MENU_CALLBACK (on_message_settings),
4012 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4013 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),