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>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include <modest-utils.h>
79 #include "modest-maemo-utils.h"
82 #define DEFAULT_FONT_SIZE 3
83 #define DEFAULT_FONT 2
84 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
85 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
86 #define DEFAULT_MAIN_VBOX_SPACING 6
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #define DEFAULT_FONT_SCALE 1.5
91 static gboolean is_wp_text_buffer_started = FALSE;
93 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
94 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
95 static void modest_msg_edit_window_finalize (GObject *obj);
97 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
98 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
99 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
101 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
102 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
103 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
104 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
105 GtkTextIter *start, GtkTextIter *end,
107 static void text_buffer_insert_text (GtkTextBuffer *buffer,
108 GtkTextIter *location,
111 ModestMsgEditWindow *window);
112 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
113 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
114 static void subject_field_insert_text (GtkEditable *editable,
116 gint new_text_length,
118 ModestMsgEditWindow *window);
119 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
121 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
123 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
125 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
126 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
127 GdkEventWindowState *event,
129 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
130 ModestRecptEditor *editor);
131 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
132 ModestMsgEditWindow *window);
134 /* ModestWindow methods implementation */
135 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
136 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
137 gboolean show_toolbar);
138 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
140 ModestMsgEditWindow *window);
141 static void subject_field_move_cursor (GtkEntry *entry,
142 GtkMovementStep step,
146 static void update_window_title (ModestMsgEditWindow *window);
149 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
150 ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
152 ModestMsgEditWindow *window);
153 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
155 GtkTextIter *match_start,
156 GtkTextIter *match_end);
158 static void remove_tags (WPTextBuffer *buffer);
160 static void on_account_removed (TnyAccountStore *account_store,
164 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
165 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
166 static gdouble get_zoom_do_nothing (ModestWindow *window);
168 static void init_window (ModestMsgEditWindow *obj);
170 gboolean scroll_drag_timeout (gpointer userdata);
171 static void correct_scroll (ModestMsgEditWindow *w);
172 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w);
173 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
174 ModestMsgEditWindow *userdata);
175 static void text_buffer_mark_set (GtkTextBuffer *buffer,
178 ModestMsgEditWindow *userdata);
179 void vadj_changed (GtkAdjustment *adj,
180 ModestMsgEditWindow *window);
186 static void DEBUG_BUFFER (WPTextBuffer *buffer)
190 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
192 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
193 while (!gtk_text_iter_is_end (&iter)) {
194 GString *output = g_string_new ("");
195 GSList *toggled_tags;
198 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
199 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
200 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
201 GtkTextTag *tag = (GtkTextTag *) node->data;
203 g_object_get (G_OBJECT (tag), "name", &name, NULL);
204 output = g_string_append (output, name);
205 g_string_append (output, " ");
207 output = g_string_append (output, "] OPENED [ ");
208 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
209 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
210 GtkTextTag *tag = (GtkTextTag *) node->data;
212 g_object_get (G_OBJECT (tag), "name", &name, NULL);
213 output = g_string_append (output, name);
214 g_string_append (output, " ");
216 output = g_string_append (output, "]\n");
217 g_message ("%s", output->str);
218 g_string_free (output, TRUE);
219 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
221 g_message ("END BUFFER");
226 /* static gboolean */
227 /* on_key_pressed (GtkWidget *self, */
228 /* GdkEventKey *event, */
229 /* gpointer user_data); */
231 /* list my signals */
238 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
239 struct _ModestMsgEditWindowPrivate {
242 GtkWidget *header_box;
244 ModestPairList *from_field_protos;
245 GtkWidget *from_field;
249 GtkWidget *bcc_field;
250 GtkWidget *subject_field;
251 GtkWidget *attachments_view;
252 GtkWidget *priority_icon;
253 GtkWidget *add_attachment_button;
255 GtkWidget *cc_caption;
256 GtkWidget *bcc_caption;
257 gboolean update_caption_visibility;
258 GtkWidget *attachments_caption;
260 GtkTextBuffer *text_buffer;
262 GtkWidget *font_size_toolitem;
263 GtkWidget *font_face_toolitem;
264 GtkWidget *font_color_button;
265 GSList *font_items_group;
266 GtkWidget *font_tool_button_label;
267 GSList *size_items_group;
268 GtkWidget *size_tool_button_label;
270 GtkWidget *find_toolbar;
274 guint scroll_drag_timeout_id;
277 TnyList *attachments;
280 TnyHeaderFlags priority_flags;
282 gboolean can_undo, can_redo;
283 gulong clipboard_change_handler_id;
284 gulong default_clipboard_change_handler_id;
285 gulong account_removed_handler_id;
286 gchar *clipboard_text;
295 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
296 MODEST_TYPE_MSG_EDIT_WINDOW, \
297 ModestMsgEditWindowPrivate))
299 static GtkWindowClass *parent_class = NULL;
301 /* uncomment the following if you have defined any signals */
302 /* static guint signals[LAST_SIGNAL] = {0}; */
305 modest_msg_edit_window_get_type (void)
307 static GType my_type = 0;
309 static const GTypeInfo my_info = {
310 sizeof(ModestMsgEditWindowClass),
311 NULL, /* base init */
312 NULL, /* base finalize */
313 (GClassInitFunc) modest_msg_edit_window_class_init,
314 NULL, /* class finalize */
315 NULL, /* class data */
316 sizeof(ModestMsgEditWindow),
318 (GInstanceInitFunc) modest_msg_edit_window_init,
321 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
322 "ModestMsgEditWindow",
330 save_state (ModestWindow *self)
332 modest_widget_memory_save (modest_runtime_get_conf(),
333 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
338 restore_settings (ModestMsgEditWindow *self)
340 ModestConf *conf = NULL;
342 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
344 conf = modest_runtime_get_conf ();
345 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
346 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
347 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
348 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
349 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
350 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
351 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
352 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
354 /* set initial state of cc and bcc */
355 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
356 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
357 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
358 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
359 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
360 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
362 /* Dim at start clipboard actions */
363 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
364 gtk_action_set_sensitive (action, FALSE);
365 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
366 gtk_action_set_sensitive (action, FALSE);
367 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
368 gtk_action_set_sensitive (action, FALSE);
370 modest_widget_memory_restore (conf,
371 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
376 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
378 GObjectClass *gobject_class;
379 ModestWindowClass *modest_window_class;
380 gobject_class = (GObjectClass*) klass;
381 modest_window_class = (ModestWindowClass*) klass;
383 parent_class = g_type_class_peek_parent (klass);
384 gobject_class->finalize = modest_msg_edit_window_finalize;
386 modest_window_class->set_zoom_func = set_zoom_do_nothing;
387 modest_window_class->get_zoom_func = get_zoom_do_nothing;
388 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
389 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
390 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
391 modest_window_class->save_state_func = save_state;
392 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
394 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
398 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
400 ModestMsgEditWindowPrivate *priv;
401 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
403 priv->msg_body = NULL;
405 priv->from_field = NULL;
406 priv->to_field = NULL;
407 priv->cc_field = NULL;
408 priv->bcc_field = NULL;
409 priv->subject_field = NULL;
410 priv->attachments = TNY_LIST (tny_simple_list_new ());
411 priv->images = TNY_LIST (tny_simple_list_new ());
414 priv->cc_caption = NULL;
415 priv->bcc_caption = NULL;
416 priv->update_caption_visibility = FALSE;
418 priv->priority_flags = 0;
420 priv->find_toolbar = NULL;
421 priv->last_search = NULL;
423 priv->draft_msg = NULL;
424 priv->outbox_msg = NULL;
425 priv->msg_uid = NULL;
427 priv->can_undo = FALSE;
428 priv->can_redo = FALSE;
429 priv->clipboard_change_handler_id = 0;
430 priv->default_clipboard_change_handler_id = 0;
431 priv->account_removed_handler_id = 0;
432 priv->clipboard_text = NULL;
435 priv->scroll_drag_timeout_id = 0;
437 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
438 GTK_WINDOW(obj),"applications_email_editor");
440 if (!is_wp_text_buffer_started) {
441 is_wp_text_buffer_started = TRUE;
442 wp_text_buffer_library_init ();
447 hildon_program_add_window (hildon_program_get_instance(),
452 /* FIXME: this is a dup from the one in gtk/ */
455 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
457 static ModestPairList*
458 get_transports (void)
460 GSList *transports = NULL;
462 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
463 GSList *accounts = modest_account_mgr_account_names (account_mgr,
464 TRUE /* only enabled accounts. */);
466 GSList *cursor = accounts;
468 gchar *account_name = cursor->data;
469 gchar *from_string = NULL;
471 from_string = modest_account_mgr_get_from_string (account_mgr,
475 if (from_string && account_name) {
476 gchar *name = account_name;
477 ModestPair *pair = modest_pair_new ((gpointer) name,
478 (gpointer) from_string , TRUE);
479 transports = g_slist_prepend (transports, pair);
482 cursor = cursor->next;
484 g_slist_free (accounts); /* only free the accounts, not the elements,
485 * because they are used in the pairlist */
489 static void window_focus (GtkWindow *window,
493 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
497 scroll_drag_timeout (gpointer userdata)
499 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
500 ModestMsgEditWindowPrivate *priv;
502 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
504 correct_scroll_without_drag_check (win);
506 priv->scroll_drag_timeout_id = 0;
512 correct_scroll_without_drag_check (ModestMsgEditWindow *w)
514 ModestMsgEditWindowPrivate *priv;
517 GdkRectangle rectangle;
523 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
525 insert = gtk_text_buffer_get_insert (priv->text_buffer);
526 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
528 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
529 vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll));
530 offset = priv->msg_body->allocation.y;
532 new_value = vadj->value;
534 if ((offset + rectangle.y + rectangle.height) >
535 ((gint) (vadj->value +vadj->page_size))) {
536 new_value = (offset + rectangle.y) + vadj->page_size * 0.75;
537 if (new_value > vadj->upper - vadj->page_size)
538 new_value = vadj->upper - vadj->page_size;
539 } else if ((offset + rectangle.y) < ((gint) vadj->value)) {
540 new_value = (offset + rectangle.y - vadj->page_size * 0.75);
541 if (((gint) (new_value + vadj->page_size)) < (offset + rectangle.y + rectangle.height))
542 new_value = offset + rectangle.y + rectangle.height - (gint) vadj->page_size;
545 if (new_value > vadj->value)
546 new_value = vadj->value;
549 if (vadj->value != new_value) {
550 g_signal_emit_by_name (GTK_TEXT_VIEW(priv->msg_body)->layout,
552 vadj->value = new_value;
553 gtk_adjustment_value_changed (vadj);
554 /* invalidate body */
555 window = gtk_widget_get_parent_window (priv->msg_body);
557 gdk_window_invalidate_rect (window, NULL, TRUE);
563 correct_scroll (ModestMsgEditWindow *w)
565 ModestMsgEditWindowPrivate *priv;
567 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
568 if (gtk_grab_get_current () == priv->msg_body) {
569 if (priv->scroll_drag_timeout_id == 0) {
570 priv->scroll_drag_timeout_id = g_timeout_add (500, (GSourceFunc) scroll_drag_timeout,
576 correct_scroll_without_drag_check (w);
580 text_buffer_end_user_action (GtkTextBuffer *buffer,
581 ModestMsgEditWindow *userdata)
584 correct_scroll (userdata);
588 text_buffer_mark_set (GtkTextBuffer *buffer,
591 ModestMsgEditWindow *userdata)
593 gtk_text_buffer_begin_user_action (buffer);
594 gtk_text_buffer_end_user_action (buffer);
597 void vadj_changed (GtkAdjustment *adj,
598 ModestMsgEditWindow *window)
600 correct_scroll (window);
604 connect_signals (ModestMsgEditWindow *obj)
606 ModestMsgEditWindowPrivate *priv;
608 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
610 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
611 G_CALLBACK (text_buffer_refresh_attributes), obj);
612 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
613 G_CALLBACK (text_buffer_can_undo), obj);
614 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
615 G_CALLBACK (text_buffer_can_redo), obj);
616 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
617 G_CALLBACK (body_changed), obj);
618 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
619 G_CALLBACK (text_buffer_insert_text), obj);
620 g_signal_connect (G_OBJECT (obj), "window-state-event",
621 G_CALLBACK (modest_msg_edit_window_window_state_event),
623 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
624 G_CALLBACK (text_buffer_end_user_action), obj);
625 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
626 G_CALLBACK (text_buffer_mark_set), obj);
627 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
628 G_CALLBACK (text_buffer_apply_tag), obj);
629 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
630 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
631 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
632 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
633 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
634 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
636 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
637 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
639 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
640 G_CALLBACK (msg_body_focus), obj);
641 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
642 G_CALLBACK (msg_body_focus), obj);
643 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
644 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
645 "changed", G_CALLBACK (recpt_field_changed), obj);
646 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
647 "changed", G_CALLBACK (recpt_field_changed), obj);
648 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
649 "changed", G_CALLBACK (recpt_field_changed), obj);
650 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
651 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
652 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
654 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
655 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
657 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
659 G_CALLBACK (vadj_changed),
662 priv->clipboard_change_handler_id =
663 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
664 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
665 priv->default_clipboard_change_handler_id =
666 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
667 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
672 init_window (ModestMsgEditWindow *obj)
674 GtkWidget *from_caption, *to_caption, *subject_caption;
675 GtkWidget *main_vbox;
676 ModestMsgEditWindowPrivate *priv;
677 GtkActionGroup *action_group;
678 ModestWindowPrivate *parent_priv;
679 GdkPixbuf *window_icon = NULL;
680 GError *error = NULL;
682 GtkSizeGroup *size_group;
683 GtkWidget *subject_box;
684 GtkWidget *attachment_icon;
685 GtkWidget *window_box;
686 #if (GTK_MINOR_VERSION >= 10)
687 GdkAtom deserialize_type;
689 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
690 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
692 parent_priv->ui_manager = gtk_ui_manager_new();
693 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
694 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
696 /* Add common actions */
697 gtk_action_group_add_actions (action_group,
698 modest_msg_edit_action_entries,
699 G_N_ELEMENTS (modest_msg_edit_action_entries),
701 gtk_action_group_add_toggle_actions (action_group,
702 modest_msg_edit_toggle_action_entries,
703 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
705 gtk_action_group_add_radio_actions (action_group,
706 modest_msg_edit_alignment_radio_action_entries,
707 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
709 G_CALLBACK (modest_ui_actions_on_change_justify),
711 gtk_action_group_add_radio_actions (action_group,
712 modest_msg_edit_priority_action_entries,
713 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
715 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
717 gtk_action_group_add_radio_actions (action_group,
718 modest_msg_edit_file_format_action_entries,
719 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
720 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
721 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
723 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
724 g_object_unref (action_group);
726 /* Load the UI definition */
727 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
730 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
731 g_clear_error (&error);
734 /* Add accelerators */
735 gtk_window_add_accel_group (GTK_WINDOW (obj),
736 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
738 parent_priv->menubar = NULL;
740 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
742 /* Note: This ModestPairList* must exist for as long as the combo
743 * that uses it, because the ModestComboBox uses the ID opaquely,
744 * so it can't know how to manage its memory. */
745 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
747 priv->to_field = modest_recpt_editor_new ();
748 priv->cc_field = modest_recpt_editor_new ();
749 priv->bcc_field = modest_recpt_editor_new ();
750 subject_box = gtk_hbox_new (FALSE, 0);
751 priv->priority_icon = gtk_image_new ();
752 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
753 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
754 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
755 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
756 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
757 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
758 priv->add_attachment_button = gtk_button_new ();
759 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
760 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
761 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
762 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
763 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
764 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
765 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
766 priv->attachments_view = modest_attachments_view_new (NULL);
768 priv->header_box = gtk_vbox_new (FALSE, 0);
770 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
771 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
772 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
773 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
774 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
775 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
776 g_object_unref (size_group);
778 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
779 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
780 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
781 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
782 gtk_size_group_add_widget (size_group, priv->subject_field);
783 gtk_size_group_add_widget (size_group, priv->attachments_view);
784 g_object_unref (size_group);
786 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
787 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
788 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
789 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
790 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
791 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
792 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
795 priv->msg_body = wp_text_view_new ();
796 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
797 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
798 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
799 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
800 #if (GTK_MINOR_VERSION >= 10)
801 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
802 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
804 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
805 deserialize_type, TRUE);
807 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
809 priv->find_toolbar = hildon_find_toolbar_new (NULL);
810 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
812 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
814 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
815 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
816 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
817 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
819 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
821 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
822 priv->frame = gtk_frame_new (NULL);
823 gtk_box_pack_start (GTK_BOX(main_vbox), priv->frame, TRUE, TRUE, 0);
825 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
826 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
827 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
829 window_box = gtk_vbox_new (FALSE, 0);
830 gtk_container_add (GTK_CONTAINER(obj), window_box);
832 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
834 gtk_container_add (GTK_CONTAINER (priv->frame), priv->msg_body);
836 /* Set window icon */
837 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
839 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
840 g_object_unref (window_icon);
845 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
847 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
849 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
850 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
851 priv->clipboard_change_handler_id))
852 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
853 priv->clipboard_change_handler_id);
854 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
855 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
856 priv->default_clipboard_change_handler_id))
857 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
858 priv->default_clipboard_change_handler_id);
860 if (priv->account_removed_handler_id &&
861 g_signal_handler_is_connected (modest_runtime_get_account_store (),
862 priv->account_removed_handler_id))
863 g_signal_handler_disconnect(modest_runtime_get_account_store (),
864 priv->account_removed_handler_id);
868 modest_msg_edit_window_finalize (GObject *obj)
870 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
872 /* Sanity check: shouldn't be needed, the window mgr should
873 call this function before */
874 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
876 if (priv->clipboard_text != NULL) {
877 g_free (priv->clipboard_text);
878 priv->clipboard_text = NULL;
881 if (priv->draft_msg != NULL) {
882 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
883 if (TNY_IS_HEADER (header)) {
884 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
885 modest_window_mgr_unregister_header (mgr, header);
887 g_object_unref (priv->draft_msg);
888 priv->draft_msg = NULL;
890 if (priv->outbox_msg != NULL) {
891 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
892 if (TNY_IS_HEADER (header)) {
893 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
894 modest_window_mgr_unregister_header (mgr, header);
896 g_object_unref (priv->outbox_msg);
897 priv->outbox_msg = NULL;
899 if (priv->scroll_drag_timeout_id > 0) {
900 g_source_remove (priv->scroll_drag_timeout_id);
901 priv->scroll_drag_timeout_id = 0;
903 g_free (priv->msg_uid);
904 g_free (priv->last_search);
905 g_slist_free (priv->font_items_group);
906 g_slist_free (priv->size_items_group);
907 g_object_unref (priv->attachments);
908 g_object_unref (priv->images);
910 /* This had to stay alive for as long as the combobox that used it: */
911 modest_pair_list_free (priv->from_field_protos);
913 G_OBJECT_CLASS(parent_class)->finalize (obj);
917 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
919 GdkPixbufLoader *loader;
922 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
927 tny_stream_reset (TNY_STREAM (stream));
928 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
929 unsigned char read_buffer[128];
931 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
932 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
936 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
937 g_object_ref (pixbuf);
938 gdk_pixbuf_loader_close (loader, NULL);
939 g_object_unref (loader);
941 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
942 GdkPixbuf *new_pixbuf;
944 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
945 gdk_pixbuf_get_width (pixbuf);
946 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
947 g_object_unref (pixbuf);
955 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
957 ModestMsgEditWindowPrivate *priv;
960 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
962 for (iter = tny_list_create_iterator (attachments);
963 !tny_iterator_is_done (iter);
964 tny_iterator_next (iter)) {
965 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
966 const gchar *cid = tny_mime_part_get_content_id (part);
967 const gchar *mime_type = tny_mime_part_get_content_type (part);
968 if ((cid != NULL)&&(mime_type != NULL)) {
969 TnyStream *stream = tny_mime_part_get_stream (part);
970 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
971 g_object_unref (stream);
973 if (pixbuf != NULL) {
974 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
975 g_object_unref (pixbuf);
978 g_object_unref (part);
983 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
985 TnyMimePart *parent = NULL;
986 const gchar *content_type = NULL;
987 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
989 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
991 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
992 parent = g_object_ref (msg);
993 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
994 TnyList *parts = TNY_LIST (tny_simple_list_new ());
997 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
998 iter = tny_list_create_iterator (parts);
999 while (!tny_iterator_is_done (iter)) {
1001 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1002 content_type = tny_mime_part_get_content_type (part);
1003 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1007 g_object_unref (part);
1009 tny_iterator_next (iter);
1011 g_object_unref (iter);
1012 g_object_unref (parts);
1015 if (parent != NULL) {
1016 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1019 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1020 iter = tny_list_create_iterator (parts);
1021 while (!tny_iterator_is_done (iter)) {
1023 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1024 content_type = tny_mime_part_get_content_type (part);
1025 if (content_type && g_str_has_prefix (content_type, "image/")) {
1026 tny_list_prepend (priv->images, (GObject *) part);
1028 g_object_unref (part);
1029 tny_iterator_next (iter);
1031 g_object_unref (iter);
1032 g_object_unref (parts);
1033 g_object_unref (parent);
1038 update_last_cid (ModestMsgEditWindow *self, TnyList *attachments)
1041 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1043 for (iter = tny_list_create_iterator (attachments) ;
1044 !tny_iterator_is_done (iter);
1045 tny_iterator_next (iter)) {
1046 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1047 const gchar *cid = tny_mime_part_get_content_id (part);
1049 char *invalid = NULL;
1050 gint int_cid = strtol (cid, &invalid, 10);
1051 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
1052 priv->last_cid = int_cid;
1055 g_object_unref (part);
1060 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1063 const gchar *to, *cc, *bcc, *subject;
1065 ModestMsgEditWindowPrivate *priv;
1067 TnyHeaderFlags priority_flags;
1068 TnyFolder *msg_folder;
1069 gboolean is_html = FALSE;
1071 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1072 g_return_if_fail (TNY_IS_MSG (msg));
1074 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1076 header = tny_msg_get_header (msg);
1077 to = tny_header_get_to (header);
1078 cc = tny_header_get_cc (header);
1079 bcc = tny_header_get_bcc (header);
1080 subject = tny_header_get_subject (header);
1081 priority_flags = tny_header_get_priority (header);
1084 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1086 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1087 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1088 gtk_widget_show (priv->cc_caption);
1089 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1090 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1091 gtk_widget_hide (priv->cc_caption);
1094 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1095 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1096 gtk_widget_show (priv->bcc_caption);
1097 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1098 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1099 gtk_widget_hide (priv->bcc_caption);
1102 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1103 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1106 update_window_title (self);
1108 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1109 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1111 if ((body == NULL)||(body[0] == '\0')) {
1113 body = modest_text_utils_convert_to_html ("");
1116 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1117 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1120 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1123 /* Add attachments to the view */
1124 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1125 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1126 if (tny_list_get_length (priv->attachments) == 0) {
1127 gtk_widget_hide (priv->attachments_caption);
1129 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1130 gtk_widget_show_all (priv->attachments_caption);
1132 get_related_images (self, msg);
1133 update_last_cid (self, priv->attachments);
1134 update_last_cid (self, priv->images);
1135 replace_with_images (self, priv->images);
1137 if (preserve_is_rich && !is_html) {
1138 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1139 /* Get the default format required from configuration */
1140 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1141 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1144 /* Set the default focus depending on having already a To: field or not */
1145 if ((!to)||(*to == '\0')) {
1146 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1148 gtk_widget_grab_focus (priv->msg_body);
1151 /* TODO: lower priority, select in the From: combo to the
1152 value that comes from msg <- not sure, should it be
1155 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1157 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1158 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1160 modest_msg_edit_window_reset_modified (self);
1162 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1163 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1164 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1165 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1167 if (priv->msg_uid) {
1168 g_free (priv->msg_uid);
1169 priv->msg_uid = NULL;
1172 /* we should set a reference to the incoming message if it is a draft */
1173 msg_folder = tny_msg_get_folder (msg);
1175 if (modest_tny_folder_is_local_folder (msg_folder)) {
1176 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1177 if (type == TNY_FOLDER_TYPE_INVALID)
1178 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1180 if (type == TNY_FOLDER_TYPE_DRAFTS)
1181 priv->draft_msg = g_object_ref(msg);
1182 if (type == TNY_FOLDER_TYPE_OUTBOX)
1183 priv->outbox_msg = g_object_ref(msg);
1184 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1186 g_object_unref (msg_folder);
1191 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1194 GList *item_children, *node;
1195 GtkWidget *bin_child;
1197 bin_child = gtk_bin_get_child (GTK_BIN(item));
1199 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1201 for (node = item_children; node != NULL; node = g_list_next (node)) {
1202 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1203 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1206 g_list_free (item_children);
1210 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1213 GList *item_children, *node;
1215 box = gtk_bin_get_child (GTK_BIN (item));
1216 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1217 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1219 for (node = item_children; node != NULL; node = g_list_next (node)) {
1220 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1221 if (GTK_IS_TOGGLE_BUTTON (node->data))
1222 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1223 else if (GTK_IS_BUTTON (node->data))
1224 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1226 g_list_free (item_children);
1231 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1233 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1234 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1235 GtkWidget *placeholder;
1236 GtkWidget *tool_item;
1241 GtkWidget *sizes_menu;
1242 GtkWidget *fonts_menu;
1243 GSList *radio_group = NULL;
1244 GSList *node = NULL;
1248 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1249 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1251 /* Font color placeholder */
1252 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1253 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1256 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1257 priv->font_color_button = hildon_color_button_new ();
1258 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1259 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1260 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1261 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1262 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1263 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1264 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1266 G_CALLBACK (modest_msg_edit_window_color_button_change),
1269 /* Font size and face placeholder */
1270 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1271 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1273 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1274 priv->size_tool_button_label = gtk_label_new (NULL);
1275 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1276 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1277 size_text,"</span>", NULL);
1278 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1280 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1281 sizes_menu = gtk_menu_new ();
1282 priv->size_items_group = NULL;
1284 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1285 GtkWidget *size_menu_item;
1287 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1288 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1289 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1290 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1291 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1292 gtk_widget_show (size_menu_item);
1294 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1298 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1299 GtkWidget *item = (GtkWidget *) node->data;
1300 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1304 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1305 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1306 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1307 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1308 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1309 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1310 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1311 priv->font_size_toolitem = tool_item;
1314 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1315 priv->font_tool_button_label = gtk_label_new (NULL);
1316 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1317 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1319 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1320 fonts_menu = gtk_menu_new ();
1321 priv->font_items_group = NULL;
1323 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1324 GtkWidget *font_menu_item;
1325 GtkWidget *child_label;
1327 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1328 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1329 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1330 wp_get_font_name (font_index), "</span>", NULL);
1331 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1334 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1335 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1336 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1337 gtk_widget_show (font_menu_item);
1339 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1342 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1343 GtkWidget *item = (GtkWidget *) node->data;
1344 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1347 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1348 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1349 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1350 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1351 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1352 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1353 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1354 priv->font_face_toolitem = tool_item;
1356 /* Set expand and homogeneous for remaining items */
1357 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1358 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1359 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1360 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1361 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1362 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1363 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1364 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1365 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1367 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1368 will not show the tool items added to the placeholders) */
1369 gtk_widget_show_all (parent_priv->toolbar);
1371 /* Set the no show all *after* showing all items. We do not
1372 want the toolbar to be shown with a show all because it
1373 could go agains the gconf setting regarding showing or not
1374 the toolbar of the editor window */
1375 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1381 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1384 ModestWindowPrivate *parent_priv;
1385 ModestMsgEditWindowPrivate *priv;
1386 ModestPair *account_pair = NULL;
1387 ModestDimmingRulesGroup *menu_rules_group = NULL;
1388 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1389 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1390 ModestWindowMgr *mgr = NULL;
1392 g_return_val_if_fail (msg, NULL);
1393 g_return_val_if_fail (account_name, NULL);
1395 mgr = modest_runtime_get_window_mgr ();
1397 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1399 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1400 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1402 /* Menubar. Update the state of some toggles */
1403 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1404 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1405 priv->from_field_protos = get_transports ();
1406 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1407 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1408 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1411 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1413 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1415 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1417 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1418 if (account_pair != NULL)
1419 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1421 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1422 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1423 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1424 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1425 /* Add common dimming rules */
1426 modest_dimming_rules_group_add_rules (menu_rules_group,
1427 modest_msg_edit_window_menu_dimming_entries,
1428 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1429 MODEST_WINDOW (obj));
1430 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1431 modest_msg_edit_window_toolbar_dimming_entries,
1432 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1433 MODEST_WINDOW (obj));
1434 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1435 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1436 MODEST_WINDOW (obj));
1437 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1438 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1439 MODEST_WINDOW (obj));
1440 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1441 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1442 MODEST_WINDOW (obj));
1443 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1444 modest_msg_edit_window_clipboard_dimming_entries,
1445 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1446 MODEST_WINDOW (obj));
1447 /* Insert dimming rules group for this window */
1448 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1449 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1450 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1451 /* Checks the dimming rules */
1452 g_object_unref (menu_rules_group);
1453 g_object_unref (toolbar_rules_group);
1454 g_object_unref (clipboard_rules_group);
1455 gtk_widget_show_all (GTK_WIDGET (obj));
1457 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1459 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1461 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1462 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1463 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1464 priv->update_caption_visibility = TRUE;
1466 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1468 /* Track account-removed signal, this window should be closed
1469 in the case we're creating a mail associated to the account
1471 priv->account_removed_handler_id =
1472 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1474 G_CALLBACK(on_account_removed),
1477 return (ModestWindow*) obj;
1481 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1483 GString **string_buffer = (GString **) user_data;
1485 *string_buffer = g_string_append (*string_buffer, buffer);
1491 * @result: A new string which should be freed with g_free().
1494 get_formatted_data (ModestMsgEditWindow *edit_window)
1496 ModestMsgEditWindowPrivate *priv;
1497 GString *string_buffer = g_string_new ("");
1499 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1501 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1503 return g_string_free (string_buffer, FALSE);
1508 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1511 const gchar *account_name;
1512 ModestMsgEditWindowPrivate *priv;
1513 TnyIterator *att_iter;
1515 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1517 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1519 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1520 g_return_val_if_fail (account_name, NULL);
1523 /* don't free these (except from) */
1524 data = g_slice_new0 (MsgData);
1525 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1527 data->account_name = g_strdup (account_name);
1528 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1529 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1530 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1531 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1532 if (priv->draft_msg) {
1533 data->draft_msg = g_object_ref (priv->draft_msg);
1534 } else if (priv->outbox_msg) {
1535 data->draft_msg = g_object_ref (priv->outbox_msg);
1537 data->draft_msg = NULL;
1540 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1542 gtk_text_buffer_get_bounds (buf, &b, &e);
1543 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1545 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1546 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1548 data->html_body = NULL;
1550 /* deep-copy the data */
1551 att_iter = tny_list_create_iterator (priv->attachments);
1552 data->attachments = NULL;
1553 while (!tny_iterator_is_done (att_iter)) {
1554 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1555 if (!(TNY_IS_MIME_PART(part))) {
1556 g_warning ("strange data in attachment list");
1557 g_object_unref (part);
1558 tny_iterator_next (att_iter);
1561 data->attachments = g_list_append (data->attachments,
1563 tny_iterator_next (att_iter);
1565 g_object_unref (att_iter);
1567 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1568 att_iter = tny_list_create_iterator (priv->images);
1569 data->images = NULL;
1570 while (!tny_iterator_is_done (att_iter)) {
1571 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1573 if (!(TNY_IS_MIME_PART(part))) {
1574 g_warning ("strange data in attachment list");
1575 g_object_unref (part);
1576 tny_iterator_next (att_iter);
1579 cid = tny_mime_part_get_content_id (part);
1581 gchar *image_tag_id;
1582 GtkTextTag *image_tag;
1584 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1585 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1586 g_free (image_tag_id);
1588 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1590 ((gtk_text_iter_has_tag (&iter, image_tag))||
1591 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1592 data->images = g_list_append (data->images,
1593 g_object_ref (part));
1595 g_object_unref (part);
1596 tny_iterator_next (att_iter);
1599 data->priority_flags = priv->priority_flags;
1606 unref_gobject (GObject *obj, gpointer data)
1608 if (!G_IS_OBJECT(obj))
1610 g_object_unref (obj);
1614 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1617 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1625 g_free (data->from);
1626 g_free (data->subject);
1627 g_free (data->plain_body);
1628 g_free (data->html_body);
1629 g_free (data->account_name);
1631 if (data->draft_msg != NULL) {
1632 g_object_unref (data->draft_msg);
1633 data->draft_msg = NULL;
1636 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1637 g_list_free (data->attachments);
1638 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1639 g_list_free (data->images);
1641 g_slice_free (MsgData, data);
1645 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1648 ModestMsgEditWindowPrivate *priv = NULL;
1649 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1651 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1653 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1655 return MODEST_MSG_EDIT_FORMAT_HTML;
1657 return MODEST_MSG_EDIT_FORMAT_TEXT;
1661 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1662 ModestMsgEditFormat format)
1664 ModestMsgEditWindowPrivate *priv;
1666 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1667 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1670 case MODEST_MSG_EDIT_FORMAT_HTML:
1671 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1673 case MODEST_MSG_EDIT_FORMAT_TEXT:
1674 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1677 g_return_if_reached ();
1681 ModestMsgEditFormatState *
1682 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1684 ModestMsgEditFormatState *format_state = NULL;
1685 ModestMsgEditWindowPrivate *priv;
1686 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1688 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1689 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1691 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1693 format_state = g_new0 (ModestMsgEditFormatState, 1);
1694 format_state->bold = buffer_format->bold&0x1;
1695 format_state->italics = buffer_format->italic&0x1;
1696 format_state->bullet = buffer_format->bullet&0x1;
1697 format_state->color = buffer_format->color;
1698 format_state->font_size = buffer_format->font_size;
1699 format_state->font_family = wp_get_font_name (buffer_format->font);
1700 format_state->justification = buffer_format->justification;
1701 g_free (buffer_format);
1703 return format_state;
1708 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1709 const ModestMsgEditFormatState *format_state)
1711 ModestMsgEditWindowPrivate *priv;
1712 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1713 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1714 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1715 g_return_if_fail (format_state != NULL);
1717 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1718 gtk_widget_grab_focus (priv->msg_body);
1719 buffer_format->bold = (format_state->bold != FALSE);
1720 buffer_format->italic = (format_state->italics != FALSE);
1721 buffer_format->color = format_state->color;
1722 buffer_format->font_size = format_state->font_size;
1723 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1724 buffer_format->justification = format_state->justification;
1725 buffer_format->bullet = format_state->bullet;
1727 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1729 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1730 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1731 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1732 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1733 buffer_format->cs.font = (buffer_format->font != current_format->font);
1734 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1735 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1737 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1738 if (buffer_format->cs.bold) {
1739 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1740 GINT_TO_POINTER (buffer_format->bold&0x1));
1742 if (buffer_format->cs.italic) {
1743 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1744 GINT_TO_POINTER (buffer_format->italic&0x1));
1746 if (buffer_format->cs.color) {
1747 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1748 GINT_TO_POINTER (&(buffer_format->color)));
1750 if (buffer_format->cs.font_size) {
1751 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1752 GINT_TO_POINTER (buffer_format->font_size));
1754 if (buffer_format->cs.justification) {
1755 switch (buffer_format->justification) {
1756 case GTK_JUSTIFY_LEFT:
1757 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1758 GINT_TO_POINTER(TRUE));
1760 case GTK_JUSTIFY_CENTER:
1761 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1762 GINT_TO_POINTER(TRUE));
1764 case GTK_JUSTIFY_RIGHT:
1765 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1766 GINT_TO_POINTER(TRUE));
1773 if (buffer_format->cs.font) {
1774 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1775 GINT_TO_POINTER (buffer_format->font));
1777 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1778 if (buffer_format->cs.bullet) {
1779 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1780 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1782 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1784 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1786 g_free (current_format);
1791 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1793 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1795 ModestWindowPrivate *parent_priv;
1796 ModestMsgEditWindowPrivate *priv;
1797 GtkWidget *new_size_menuitem;
1798 GtkWidget *new_font_menuitem;
1800 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1801 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1803 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1804 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1805 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1806 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1808 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1809 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1810 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1813 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1815 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1816 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1818 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1819 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1821 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1822 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1825 switch (buffer_format->justification)
1827 case GTK_JUSTIFY_LEFT:
1828 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentLeftMenu");
1830 case GTK_JUSTIFY_CENTER:
1831 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentCenterMenu");
1833 case GTK_JUSTIFY_RIGHT:
1834 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentRightMenu");
1841 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1843 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1844 G_CALLBACK (modest_msg_edit_window_color_button_change),
1846 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1847 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1848 G_CALLBACK (modest_msg_edit_window_color_button_change),
1851 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1852 buffer_format->font_size))->data);
1853 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1857 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1858 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1859 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1861 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1862 G_CALLBACK (modest_msg_edit_window_size_change),
1864 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1865 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1866 G_CALLBACK (modest_msg_edit_window_size_change),
1870 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1871 buffer_format->font))->data);
1872 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1876 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1877 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1878 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1880 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1881 G_CALLBACK (modest_msg_edit_window_font_change),
1883 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1884 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1885 G_CALLBACK (modest_msg_edit_window_font_change),
1889 g_free (buffer_format);
1893 #ifdef MODEST_HILDON_VERSION_0
1895 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1898 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1899 ModestMsgEditWindowPrivate *priv;
1900 GtkWidget *dialog = NULL;
1902 GdkColor *new_color = NULL;
1904 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1905 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1907 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1908 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1909 g_free (buffer_format);
1911 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1912 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1913 if (new_color != NULL) {
1914 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1915 (gpointer) new_color);
1918 gtk_widget_destroy (dialog);
1923 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1926 ModestMsgEditWindowPrivate *priv;
1927 GtkWidget *dialog = NULL;
1929 GdkColor *old_color = NULL;
1930 const GdkColor *new_color = NULL;
1932 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1933 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1935 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1936 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1938 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1939 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1940 if (new_color != NULL)
1941 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1943 gtk_widget_destroy (dialog);
1949 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1952 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1953 ModestMsgEditWindowPrivate *priv;
1954 GtkWidget *dialog = NULL;
1956 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1957 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1959 dialog = hildon_color_chooser_new ();
1960 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1961 g_free (buffer_format);
1963 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1965 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1966 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1969 gtk_widget_destroy (dialog);
1974 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1977 ModestMsgEditWindowPrivate *priv;
1978 GtkWidget *dialog = NULL;
1979 GdkColor *old_color = NULL;
1981 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1982 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1984 dialog = hildon_color_chooser_new ();
1985 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1987 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1989 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1990 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1992 gtk_widget_destroy (dialog);
1995 #endif /*!MODEST_HILDON_VERSION_0*/
1999 static TnyStream* create_stream_for_uri (const gchar* uri)
2004 TnyStream *result = NULL;
2006 GnomeVFSHandle *handle = NULL;
2007 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2008 if (test == GNOME_VFS_OK) {
2009 /* Create the tinymail stream: */
2010 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
2011 result = TNY_STREAM (tny_vfs_stream_new (handle));
2018 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2021 ModestMsgEditWindowPrivate *priv;
2022 GtkWidget *dialog = NULL;
2024 GSList *uris = NULL;
2025 GSList *uri_node = NULL;
2027 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2029 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2030 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2031 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2033 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2035 response = gtk_dialog_run (GTK_DIALOG (dialog));
2037 case GTK_RESPONSE_OK:
2038 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2043 gtk_widget_destroy (dialog);
2045 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2047 GnomeVFSHandle *handle = NULL;
2048 GnomeVFSResult result;
2049 GtkTextIter position;
2050 GtkTextMark *insert_mark;
2052 uri = (const gchar *) uri_node->data;
2053 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2054 if (result == GNOME_VFS_OK) {
2056 GnomeVFSFileInfo info;
2057 gchar *filename, *basename, *escaped_filename;
2058 TnyMimePart *mime_part;
2060 const gchar *mime_type = NULL;
2061 GnomeVFSURI *vfs_uri;
2063 vfs_uri = gnome_vfs_uri_new (uri);
2065 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2066 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2067 g_free (escaped_filename);
2068 gnome_vfs_uri_unref (vfs_uri);
2070 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2071 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2073 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2075 mime_part = tny_platform_factory_new_mime_part
2076 (modest_runtime_get_platform_factory ());
2078 TnyStream *stream = create_stream_for_uri (uri);
2079 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2081 content_id = g_strdup_printf ("%d", priv->last_cid);
2082 tny_mime_part_set_content_id (mime_part, content_id);
2083 g_free (content_id);
2086 basename = g_path_get_basename (filename);
2087 tny_mime_part_set_filename (mime_part, basename);
2090 pixbuf = pixbuf_from_stream (stream, mime_type);
2092 if (pixbuf != NULL) {
2093 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2094 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2095 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2098 tny_list_prepend (priv->images, (GObject *) mime_part);
2099 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2101 g_object_unref (mime_part);
2110 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2112 GtkWidget *dialog = NULL;
2114 GSList *uris = NULL;
2117 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2118 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2119 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2121 response = gtk_dialog_run (GTK_DIALOG (dialog));
2123 case GTK_RESPONSE_OK:
2124 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2129 gtk_widget_destroy (dialog);
2131 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2132 const gchar *uri = (const gchar *) uri_node->data;
2133 modest_msg_edit_window_attach_file_one (window, uri);
2135 g_slist_foreach (uris, (GFunc) g_free, NULL);
2136 g_slist_free (uris);
2140 modest_msg_edit_window_attach_file_one (
2141 ModestMsgEditWindow *window,
2144 g_return_if_fail (window);
2145 g_return_if_fail (uri);
2147 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2150 GnomeVFSHandle *handle = NULL;
2151 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2152 if (result == GNOME_VFS_OK) {
2153 TnyMimePart *mime_part;
2155 const gchar *mime_type = NULL;
2157 gchar *escaped_filename;
2160 GnomeVFSFileInfo info;
2161 GnomeVFSURI *vfs_uri;
2163 vfs_uri = gnome_vfs_uri_new (uri);
2166 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2167 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2168 g_free (escaped_filename);
2169 gnome_vfs_uri_unref (vfs_uri);
2171 if (gnome_vfs_get_file_info (uri,
2173 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2175 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2176 mime_part = tny_platform_factory_new_mime_part
2177 (modest_runtime_get_platform_factory ());
2178 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2180 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2182 g_object_unref (stream);
2184 content_id = g_strdup_printf ("%d", priv->last_cid);
2185 tny_mime_part_set_content_id (mime_part, content_id);
2186 g_free (content_id);
2189 basename = g_path_get_basename (filename);
2190 tny_mime_part_set_filename (mime_part, basename);
2193 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2194 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2196 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2197 gtk_widget_show_all (priv->attachments_caption);
2198 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2200 g_object_unref (mime_part);
2205 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2208 ModestMsgEditWindowPrivate *priv;
2211 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2212 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2214 if (att_list == NULL) {
2215 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2217 g_object_ref (att_list);
2220 if (tny_list_get_length (att_list) == 0) {
2221 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2223 GtkWidget *confirmation_dialog = NULL;
2224 gboolean dialog_response;
2225 gchar *message = NULL;
2226 gchar *filename = NULL;
2228 if (tny_list_get_length (att_list) == 1) {
2230 iter = tny_list_create_iterator (att_list);
2231 part = (TnyMimePart *) tny_iterator_get_current (iter);
2232 g_object_unref (iter);
2233 if (TNY_IS_MSG (part)) {
2234 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2236 filename = g_strdup (tny_header_get_subject (header));
2237 g_object_unref (header);
2239 if (filename == NULL) {
2240 filename = g_strdup (_("mail_va_no_subject"));
2243 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2245 g_object_unref (part);
2247 filename = g_strdup ("");
2249 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2250 (tny_list_get_length (att_list) == 1)), filename);
2252 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2254 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2255 gtk_widget_destroy (confirmation_dialog);
2256 if (!dialog_response) {
2257 g_object_unref (att_list);
2260 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2262 for (iter = tny_list_create_iterator (att_list);
2263 !tny_iterator_is_done (iter);
2264 tny_iterator_next (iter)) {
2265 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2266 const gchar *att_id;
2267 tny_list_remove (priv->attachments, (GObject *) mime_part);
2269 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2271 if (tny_list_get_length (priv->attachments) == 0)
2272 gtk_widget_hide (priv->attachments_caption);
2273 att_id = tny_mime_part_get_content_id (mime_part);
2275 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2277 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2278 g_object_unref (mime_part);
2282 g_object_unref (att_list);
2284 /* if the last attachment has been removed, focus the Subject: field */
2285 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2286 gtk_widget_grab_focus (priv->subject_field);
2290 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2293 ModestMsgEditWindowPrivate *priv;
2294 GdkColor *new_color;
2295 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2297 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2298 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2301 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2303 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2305 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2307 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2312 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2315 ModestMsgEditWindowPrivate *priv;
2316 gint new_size_index;
2317 ModestMsgEditWindow *window;
2320 window = MODEST_MSG_EDIT_WINDOW (userdata);
2321 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2322 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2324 if (gtk_check_menu_item_get_active (menu_item)) {
2326 WPTextBufferFormat format;
2328 memset (&format, 0, sizeof (format));
2329 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2331 label = gtk_bin_get_child (GTK_BIN (menu_item));
2333 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2334 format.cs.font_size = TRUE;
2335 format.cs.text_position = TRUE;
2336 format.cs.font = TRUE;
2337 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2338 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2340 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2341 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2342 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2344 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2345 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2346 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2352 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2355 ModestMsgEditWindowPrivate *priv;
2356 gint new_font_index;
2357 ModestMsgEditWindow *window;
2360 window = MODEST_MSG_EDIT_WINDOW (userdata);
2361 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2362 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2364 if (gtk_check_menu_item_get_active (menu_item)) {
2367 label = gtk_bin_get_child (GTK_BIN (menu_item));
2369 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2371 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2372 GINT_TO_POINTER(new_font_index)))
2373 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2375 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2376 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2377 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2383 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2385 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2386 ModestWindowPrivate *parent_priv;
2387 ModestWindowMgr *mgr;
2388 gboolean is_fullscreen;
2389 GtkAction *fs_toggle_action;
2392 mgr = modest_runtime_get_window_mgr ();
2393 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2395 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2397 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2398 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2399 if (is_fullscreen != active)
2400 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2408 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2411 ModestMsgEditWindowPrivate *priv = NULL;
2412 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2414 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2415 if (!priv->update_caption_visibility)
2418 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2420 gtk_widget_show (priv->cc_caption);
2422 gtk_widget_hide (priv->cc_caption);
2424 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2428 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2431 ModestMsgEditWindowPrivate *priv = NULL;
2432 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2434 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2435 if (!priv->update_caption_visibility)
2438 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2440 gtk_widget_show (priv->bcc_caption);
2442 gtk_widget_hide (priv->bcc_caption);
2444 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2448 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2449 ModestRecptEditor *editor)
2451 ModestMsgEditWindowPrivate *priv;
2453 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2454 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2455 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2457 if (editor == NULL) {
2458 GtkWidget *view_focus;
2459 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2461 /* This code should be kept in sync with ModestRecptEditor. The
2462 textview inside the recpt editor is the one that really gets the
2463 focus. As it's inside a scrolled window, and this one inside the
2464 hbox recpt editor inherits from, we'll need to go up in the
2465 hierarchy to know if the text view is part of the recpt editor
2466 or if it's a different text entry */
2468 if (gtk_widget_get_parent (view_focus)) {
2469 GtkWidget *first_parent;
2471 first_parent = gtk_widget_get_parent (view_focus);
2472 if (gtk_widget_get_parent (first_parent) &&
2473 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2474 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2479 editor = MODEST_RECPT_EDITOR (priv->to_field);
2483 modest_address_book_select_addresses (editor);
2488 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2490 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2492 modest_msg_edit_window_open_addressbook (window, NULL);
2496 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2497 gboolean show_toolbar)
2499 ModestWindowPrivate *parent_priv;
2500 const gchar *action_name;
2503 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2504 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2506 /* We can not just use the code of
2507 modest_msg_edit_window_setup_toolbar because it has a
2508 mixture of both initialization and creation code. */
2510 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2512 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2514 /* Update also the actions (to update the toggles in the
2515 menus), we have to do it manually because some other window
2516 of the same time could have changed it (remember that the
2517 toolbar fullscreen mode is shared by all the windows of the
2519 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2520 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2522 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2524 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2525 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2531 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2532 TnyHeaderFlags priority_flags)
2534 ModestMsgEditWindowPrivate *priv;
2535 ModestWindowPrivate *parent_priv;
2537 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2539 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2540 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2542 if (priv->priority_flags != priority_flags) {
2543 GtkAction *priority_action = NULL;
2545 priv->priority_flags = priority_flags;
2547 switch (priority_flags) {
2548 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2549 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2550 gtk_widget_show (priv->priority_icon);
2551 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2552 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2554 case TNY_HEADER_FLAG_LOW_PRIORITY:
2555 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2556 gtk_widget_show (priv->priority_icon);
2557 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2558 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2561 gtk_widget_hide (priv->priority_icon);
2562 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2563 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2566 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2567 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2572 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2575 ModestMsgEditWindowPrivate *priv;
2576 ModestWindowPrivate *parent_priv;
2577 gint current_format;
2579 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2581 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2582 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2584 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2585 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2587 if (current_format != file_format) {
2588 switch (file_format) {
2589 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2590 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2591 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2593 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2597 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2598 response = gtk_dialog_run (GTK_DIALOG (dialog));
2599 gtk_widget_destroy (dialog);
2600 if (response == GTK_RESPONSE_OK) {
2601 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2603 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2604 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2609 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2614 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2617 ModestMsgEditWindowPrivate *priv;
2618 WPTextBufferFormat oldfmt, fmt;
2619 gint old_position = 0;
2623 GdkColor *color = NULL;
2624 gboolean bold, bold_set, italic, italic_set;
2625 gboolean underline, underline_set;
2626 gboolean strikethrough, strikethrough_set;
2627 gboolean position_set;
2628 gboolean font_size_set, font_set, color_set;
2631 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2632 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2634 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2636 /* First we get the currently selected font information */
2637 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2639 switch (oldfmt.text_position) {
2640 case TEXT_POSITION_NORMAL:
2643 case TEXT_POSITION_SUPERSCRIPT:
2651 g_object_set (G_OBJECT (dialog),
2652 "bold", oldfmt.bold != FALSE,
2653 "bold-set", !oldfmt.cs.bold,
2654 "underline", oldfmt.underline != FALSE,
2655 "underline-set", !oldfmt.cs.underline,
2656 "italic", oldfmt.italic != FALSE,
2657 "italic-set", !oldfmt.cs.italic,
2658 "strikethrough", oldfmt.strikethrough != FALSE,
2659 "strikethrough-set", !oldfmt.cs.strikethrough,
2660 "color", &oldfmt.color,
2661 "color-set", !oldfmt.cs.color,
2662 "size", wp_font_size[oldfmt.font_size],
2663 "size-set", !oldfmt.cs.font_size,
2664 "position", old_position,
2665 "position-set", !oldfmt.cs.text_position,
2666 "family", wp_get_font_name (oldfmt.font),
2667 "family-set", !oldfmt.cs.font,
2670 gtk_widget_show_all (dialog);
2671 response = gtk_dialog_run (GTK_DIALOG (dialog));
2672 if (response == GTK_RESPONSE_OK) {
2674 g_object_get( dialog,
2676 "bold-set", &bold_set,
2677 "underline", &underline,
2678 "underline-set", &underline_set,
2680 "italic-set", &italic_set,
2681 "strikethrough", &strikethrough,
2682 "strikethrough-set", &strikethrough_set,
2684 "color-set", &color_set,
2686 "size-set", &font_size_set,
2687 "family", &font_name,
2688 "family-set", &font_set,
2689 "position", &position,
2690 "position-set", &position_set,
2695 if (response == GTK_RESPONSE_OK) {
2696 memset(&fmt, 0, sizeof(fmt));
2702 fmt.italic = italic;
2703 fmt.cs.italic = TRUE;
2705 if (underline_set) {
2706 fmt.underline = underline;
2707 fmt.cs.underline = TRUE;
2709 if (strikethrough_set) {
2710 fmt.strikethrough = strikethrough;
2711 fmt.cs.strikethrough = TRUE;
2716 ? TEXT_POSITION_NORMAL
2717 : ( ( position == 1 )
2718 ? TEXT_POSITION_SUPERSCRIPT
2719 : TEXT_POSITION_SUBSCRIPT );
2720 fmt.cs.text_position = TRUE;
2721 fmt.font_size = oldfmt.font_size;
2725 fmt.cs.color = TRUE;
2728 fmt.font = wp_get_font_index(font_name,
2733 if (font_size_set) {
2734 fmt.cs.font_size = TRUE;
2735 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2737 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2738 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2740 gtk_widget_destroy (dialog);
2742 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2746 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2748 ModestMsgEditWindowPrivate *priv;
2750 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2751 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2753 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2755 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2756 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2761 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2763 ModestMsgEditWindowPrivate *priv;
2765 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2766 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2768 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2770 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2771 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2776 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2778 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2780 priv->can_undo = can_undo;
2784 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2786 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2788 priv->can_redo = can_redo;
2792 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2794 ModestMsgEditWindowPrivate *priv;
2795 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2796 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2798 return priv->can_undo;
2802 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2804 ModestMsgEditWindowPrivate *priv;
2805 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2806 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2808 return priv->can_redo;
2813 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2816 GtkTextIter match_start, match_end;
2818 if (image_id == NULL)
2821 gtk_text_buffer_get_start_iter (buffer, &iter);
2823 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2824 GSList *tags = gtk_text_iter_get_tags (&match_start);
2826 for (node = tags; node != NULL; node = g_slist_next (node)) {
2827 GtkTextTag *tag = (GtkTextTag *) node->data;
2828 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2829 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2830 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2832 offset = gtk_text_iter_get_offset (&match_start);
2833 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2834 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2838 gtk_text_iter_forward_char (&iter);
2843 message_is_empty (ModestMsgEditWindow *window)
2845 ModestMsgEditWindowPrivate *priv = NULL;
2847 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2848 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2850 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2851 * so we can ignore markup.
2853 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2856 count = gtk_text_buffer_get_char_count (buf);
2862 msg_body_focus (GtkWidget *focus,
2863 GdkEventFocus *event,
2867 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2868 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
2869 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
2874 recpt_field_changed (GtkTextBuffer *buffer,
2875 ModestMsgEditWindow *editor)
2877 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2878 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
2882 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2884 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2885 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
2889 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2891 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2892 GtkTextBuffer *buffer;
2894 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2895 gtk_text_buffer_set_modified (buffer, FALSE);
2896 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2897 gtk_text_buffer_set_modified (buffer, FALSE);
2898 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2899 gtk_text_buffer_set_modified (buffer, FALSE);
2900 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2904 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2906 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2907 GtkTextBuffer *buffer;
2909 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2910 if (gtk_text_buffer_get_modified (buffer))
2912 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2913 if (gtk_text_buffer_get_modified (buffer))
2915 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2916 if (gtk_text_buffer_get_modified (buffer))
2918 if (gtk_text_buffer_get_modified (priv->text_buffer))
2928 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2930 ModestMsgEditWindowPrivate *priv = NULL;
2932 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2933 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2935 /* check if there's no recipient added */
2936 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2937 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2938 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2939 /* no recipient contents, then select contacts */
2940 modest_msg_edit_window_open_addressbook (window, NULL);
2944 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2945 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2948 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2949 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2952 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2953 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2957 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2958 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2959 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2966 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2967 ModestMsgEditWindow *window)
2969 modest_msg_edit_window_offer_attach_file (window);
2973 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2975 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2977 return priv->clipboard_text;
2981 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2983 ModestMsgEditWindow *window)
2985 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2986 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2988 if (!GTK_WIDGET_VISIBLE (window))
2991 text = gtk_clipboard_wait_for_text (selection_clipboard);
2993 if (priv->clipboard_text != NULL) {
2994 g_free (priv->clipboard_text);
2996 priv->clipboard_text = text;
2998 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3001 subject_field_move_cursor (GtkEntry *entry,
3002 GtkMovementStep step,
3007 if (!GTK_WIDGET_VISIBLE (window))
3010 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3014 update_window_title (ModestMsgEditWindow *window)
3016 ModestMsgEditWindowPrivate *priv = NULL;
3017 const gchar *subject;
3019 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3020 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3021 if (subject == NULL || subject[0] == '\0')
3022 subject = _("mail_va_new_email");
3024 gtk_window_set_title (GTK_WINDOW (window), subject);
3029 subject_field_changed (GtkEditable *editable,
3030 ModestMsgEditWindow *window)
3032 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3033 update_window_title (window);
3034 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3035 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3036 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3040 subject_field_insert_text (GtkEditable *editable,
3042 gint new_text_length,
3044 ModestMsgEditWindow *window)
3046 GString *result = g_string_new ("");
3048 gint result_len = 0;
3049 const gchar *entry_text = NULL;
3052 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3053 old_length = g_utf8_strlen (entry_text, -1);
3055 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3056 gunichar c = g_utf8_get_char_validated (current, 8);
3057 /* Invalid unichar, stop */
3063 result = g_string_append_unichar (result, c);
3067 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3068 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3071 /* Prevent endless recursion */
3072 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3073 g_signal_emit_by_name (editable, "insert-text",
3074 (gpointer) result->str, (gpointer) result->len,
3075 (gpointer) position, (gpointer) window);
3076 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3080 if (result_len + old_length > 1000) {
3081 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3082 dgettext("hildon-common-strings",
3083 "ckdg_ib_maximum_characters_reached"));
3086 g_string_free (result, TRUE);
3090 text_buffer_insert_text (GtkTextBuffer *buffer,
3093 gint new_text_length,
3094 ModestMsgEditWindow *window)
3096 GString *result = g_string_new ("");
3098 gint result_len = 0;
3099 gboolean changed = FALSE;
3101 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3102 gunichar c = g_utf8_get_char_validated (current, 8);
3103 /* Invalid unichar, stop */
3109 result = g_string_append_c (result, ' ');
3113 result = g_string_append_unichar (result, c);
3119 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3120 g_signal_handlers_block_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3121 g_signal_emit_by_name (buffer, "insert-text",
3123 (gpointer) result->str, (gpointer) result->len,
3125 g_signal_handlers_unblock_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3128 g_string_free (result, TRUE);
3132 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3135 ModestMsgEditWindowPrivate *priv = NULL;
3137 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3138 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3140 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3143 gtk_widget_show_all (priv->find_toolbar);
3144 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3146 gtk_widget_hide_all (priv->find_toolbar);
3147 gtk_widget_grab_focus (priv->msg_body);
3153 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3155 GtkTextIter *match_start,
3156 GtkTextIter *match_end)
3158 GtkTextIter end_iter;
3159 gchar *str_casefold;
3162 gchar *range_casefold;
3165 gboolean result = FALSE;
3172 gtk_text_iter_forward_to_end (&end_iter);
3174 str_casefold = g_utf8_casefold (str, -1);
3175 str_chars_n = strlen (str);
3177 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3178 range_casefold = g_utf8_casefold (range_text, -1);
3179 range_chars_n = strlen (range_casefold);
3181 if (range_chars_n < str_chars_n) {
3182 g_free (str_casefold);
3183 g_free (range_text);
3184 g_free (range_casefold);
3188 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3189 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3190 if (!g_utf8_collate (range_subtext, str_casefold)) {
3191 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3193 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3194 match_start, match_end, NULL);
3195 g_free (found_text);
3197 g_free (range_subtext);
3201 g_free (str_casefold);
3202 g_free (range_text);
3203 g_free (range_casefold);
3210 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3211 ModestMsgEditWindow *window)
3213 gchar *current_search = NULL;
3214 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3216 GtkTextIter selection_start, selection_end;
3217 GtkTextIter match_start, match_end;
3218 gboolean continue_search = FALSE;
3220 if (message_is_empty (window)) {
3221 g_free (priv->last_search);
3222 priv->last_search = NULL;
3223 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3227 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3228 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3229 g_free (current_search);
3230 g_free (priv->last_search);
3231 priv->last_search = NULL;
3232 /* Information banner about empty search */
3233 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3237 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3238 continue_search = TRUE;
3240 g_free (priv->last_search);
3241 priv->last_search = g_strdup (current_search);
3244 if (continue_search) {
3245 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3246 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3247 &match_start, &match_end);
3249 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3251 GtkTextIter buffer_start;
3252 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3253 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3254 &match_start, &match_end);
3256 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3259 /* Mark as selected the string found in search */
3261 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3262 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3264 g_free (priv->last_search);
3265 priv->last_search = NULL;
3267 g_free (current_search);
3271 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3272 ModestMsgEditWindow *window)
3274 GtkToggleAction *toggle;
3275 ModestWindowPrivate *parent_priv;
3276 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3278 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3279 gtk_toggle_action_set_active (toggle, FALSE);
3283 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3285 ModestMsgEditWindowPrivate *priv;
3287 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3292 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3295 ModestMsgEditWindowPrivate *priv;
3297 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3303 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3306 ModestMsgEditWindowPrivate *priv;
3307 TnyHeader *header = NULL;
3309 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3310 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3312 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3313 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3315 if (priv->draft_msg != NULL) {
3316 g_object_unref (priv->draft_msg);
3319 if (draft != NULL) {
3320 g_object_ref (draft);
3321 header = tny_msg_get_header (draft);
3322 if (priv->msg_uid) {
3323 g_free (priv->msg_uid);
3324 priv->msg_uid = NULL;
3326 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3327 if (GTK_WIDGET_REALIZED (window))
3328 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3331 priv->draft_msg = draft;
3335 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3336 GtkTextIter *start, GtkTextIter *end,
3339 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3340 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3343 if (tag == NULL+13) return;
3344 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3345 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3346 replace_with_images (window, priv->images);
3351 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3354 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3356 g_return_if_fail (TNY_IS_MIME_PART (part));
3357 tny_list_prepend (priv->attachments, (GObject *) part);
3358 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3359 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3360 gtk_widget_show_all (priv->attachments_caption);
3361 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3365 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3367 ModestMsgEditWindowPrivate *priv;
3369 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3370 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3372 return priv->msg_uid;
3376 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3377 ModestMsgEditWindowWidgetType widget_type)
3379 ModestMsgEditWindowPrivate *priv;
3381 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3382 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3384 switch (widget_type) {
3385 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3386 return priv->msg_body;
3388 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3389 return priv->to_field;
3391 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3392 return priv->cc_field;
3394 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3395 return priv->bcc_field;
3397 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3398 return priv->subject_field;
3400 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3401 return priv->attachments_view;
3409 remove_tags (WPTextBuffer *buffer)
3411 GtkTextIter start, end;
3413 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3414 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3416 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3420 on_account_removed (TnyAccountStore *account_store,
3421 TnyAccount *account,
3424 /* Do nothing if it's a store account, because we use the
3425 transport to send the messages */
3426 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3427 const gchar *parent_acc = NULL;
3428 const gchar *our_acc = NULL;
3430 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3431 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3432 /* Close this window if I'm showing a message of the removed account */
3433 if (strcmp (parent_acc, our_acc) == 0)
3434 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3439 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3441 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3443 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3449 set_zoom_do_nothing (ModestWindow *window,
3455 get_zoom_do_nothing (ModestWindow *window)