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;
282 TnyHeaderFlags priority_flags;
284 gboolean can_undo, can_redo;
285 gulong clipboard_change_handler_id;
286 gulong default_clipboard_change_handler_id;
287 gulong account_removed_handler_id;
288 gchar *clipboard_text;
297 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
298 MODEST_TYPE_MSG_EDIT_WINDOW, \
299 ModestMsgEditWindowPrivate))
301 static GtkWindowClass *parent_class = NULL;
303 /* uncomment the following if you have defined any signals */
304 /* static guint signals[LAST_SIGNAL] = {0}; */
307 modest_msg_edit_window_get_type (void)
309 static GType my_type = 0;
311 static const GTypeInfo my_info = {
312 sizeof(ModestMsgEditWindowClass),
313 NULL, /* base init */
314 NULL, /* base finalize */
315 (GClassInitFunc) modest_msg_edit_window_class_init,
316 NULL, /* class finalize */
317 NULL, /* class data */
318 sizeof(ModestMsgEditWindow),
320 (GInstanceInitFunc) modest_msg_edit_window_init,
323 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
324 "ModestMsgEditWindow",
332 save_state (ModestWindow *self)
334 modest_widget_memory_save (modest_runtime_get_conf(),
335 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
340 restore_settings (ModestMsgEditWindow *self)
342 ModestConf *conf = NULL;
344 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
346 conf = modest_runtime_get_conf ();
347 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
348 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
349 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
350 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
351 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
352 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
353 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
354 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
356 /* set initial state of cc and bcc */
357 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
358 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
359 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
360 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
361 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
362 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
364 /* Dim at start clipboard actions */
365 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
366 gtk_action_set_sensitive (action, FALSE);
367 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
368 gtk_action_set_sensitive (action, FALSE);
369 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
370 gtk_action_set_sensitive (action, FALSE);
372 modest_widget_memory_restore (conf,
373 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
378 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
380 GObjectClass *gobject_class;
381 ModestWindowClass *modest_window_class;
382 gobject_class = (GObjectClass*) klass;
383 modest_window_class = (ModestWindowClass*) klass;
385 parent_class = g_type_class_peek_parent (klass);
386 gobject_class->finalize = modest_msg_edit_window_finalize;
388 modest_window_class->set_zoom_func = set_zoom_do_nothing;
389 modest_window_class->get_zoom_func = get_zoom_do_nothing;
390 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
391 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
392 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
393 modest_window_class->save_state_func = save_state;
394 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
396 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
400 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
402 ModestMsgEditWindowPrivate *priv;
403 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
405 priv->msg_body = NULL;
407 priv->from_field = NULL;
408 priv->to_field = NULL;
409 priv->cc_field = NULL;
410 priv->bcc_field = NULL;
411 priv->subject_field = NULL;
412 priv->attachments = TNY_LIST (tny_simple_list_new ());
413 priv->images = TNY_LIST (tny_simple_list_new ());
414 priv->images_size = 0;
415 priv->images_count = 0;
418 priv->cc_caption = NULL;
419 priv->bcc_caption = NULL;
420 priv->update_caption_visibility = FALSE;
422 priv->priority_flags = 0;
424 priv->find_toolbar = NULL;
425 priv->last_search = NULL;
427 priv->draft_msg = NULL;
428 priv->outbox_msg = NULL;
429 priv->msg_uid = NULL;
431 priv->can_undo = FALSE;
432 priv->can_redo = FALSE;
433 priv->clipboard_change_handler_id = 0;
434 priv->default_clipboard_change_handler_id = 0;
435 priv->account_removed_handler_id = 0;
436 priv->clipboard_text = NULL;
439 priv->scroll_drag_timeout_id = 0;
441 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
442 GTK_WINDOW(obj),"applications_email_editor");
444 if (!is_wp_text_buffer_started) {
445 is_wp_text_buffer_started = TRUE;
446 wp_text_buffer_library_init ();
451 hildon_program_add_window (hildon_program_get_instance(),
456 /* FIXME: this is a dup from the one in gtk/ */
459 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
461 static ModestPairList*
462 get_transports (void)
464 GSList *transports = NULL;
466 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
467 GSList *accounts = modest_account_mgr_account_names (account_mgr,
468 TRUE /* only enabled accounts. */);
470 GSList *cursor = accounts;
472 gchar *account_name = cursor->data;
473 gchar *from_string = NULL;
475 from_string = modest_account_mgr_get_from_string (account_mgr,
479 if (from_string && account_name) {
480 gchar *name = account_name;
481 ModestPair *pair = modest_pair_new ((gpointer) name,
482 (gpointer) from_string , TRUE);
483 transports = g_slist_prepend (transports, pair);
486 cursor = cursor->next;
488 g_slist_free (accounts); /* only free the accounts, not the elements,
489 * because they are used in the pairlist */
493 static void window_focus (GtkWindow *window,
497 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
501 scroll_drag_timeout (gpointer userdata)
503 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
504 ModestMsgEditWindowPrivate *priv;
506 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
508 correct_scroll_without_drag_check (win);
510 priv->scroll_drag_timeout_id = 0;
516 correct_scroll_without_drag_check (ModestMsgEditWindow *w)
518 ModestMsgEditWindowPrivate *priv;
521 GdkRectangle rectangle;
527 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
529 insert = gtk_text_buffer_get_insert (priv->text_buffer);
530 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
532 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
533 vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll));
534 offset = priv->msg_body->allocation.y;
536 new_value = vadj->value;
538 if ((offset + rectangle.y + rectangle.height) >
539 ((gint) (vadj->value +vadj->page_size))) {
540 new_value = (offset + rectangle.y) + vadj->page_size * 0.75;
541 if (new_value > vadj->upper - vadj->page_size)
542 new_value = vadj->upper - vadj->page_size;
543 } else if ((offset + rectangle.y) < ((gint) vadj->value)) {
544 new_value = (offset + rectangle.y - vadj->page_size * 0.75);
545 if (((gint) (new_value + vadj->page_size)) < (offset + rectangle.y + rectangle.height))
546 new_value = offset + rectangle.y + rectangle.height - (gint) vadj->page_size;
549 if (new_value > vadj->value)
550 new_value = vadj->value;
553 if (vadj->value != new_value) {
554 g_signal_emit_by_name (GTK_TEXT_VIEW(priv->msg_body)->layout,
556 vadj->value = new_value;
557 gtk_adjustment_value_changed (vadj);
558 /* invalidate body */
559 window = gtk_widget_get_parent_window (priv->msg_body);
561 gdk_window_invalidate_rect (window, NULL, TRUE);
567 correct_scroll (ModestMsgEditWindow *w)
569 ModestMsgEditWindowPrivate *priv;
571 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
572 if (gtk_grab_get_current () == priv->msg_body) {
573 if (priv->scroll_drag_timeout_id == 0) {
574 priv->scroll_drag_timeout_id = g_timeout_add (500, (GSourceFunc) scroll_drag_timeout,
580 correct_scroll_without_drag_check (w);
584 text_buffer_end_user_action (GtkTextBuffer *buffer,
585 ModestMsgEditWindow *userdata)
588 correct_scroll (userdata);
592 text_buffer_mark_set (GtkTextBuffer *buffer,
595 ModestMsgEditWindow *userdata)
597 gtk_text_buffer_begin_user_action (buffer);
598 gtk_text_buffer_end_user_action (buffer);
601 void vadj_changed (GtkAdjustment *adj,
602 ModestMsgEditWindow *window)
604 correct_scroll (window);
608 connect_signals (ModestMsgEditWindow *obj)
610 ModestMsgEditWindowPrivate *priv;
612 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
614 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
615 G_CALLBACK (text_buffer_refresh_attributes), obj);
616 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
617 G_CALLBACK (text_buffer_can_undo), obj);
618 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
619 G_CALLBACK (text_buffer_can_redo), obj);
620 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
621 G_CALLBACK (body_changed), obj);
622 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
623 G_CALLBACK (text_buffer_insert_text), obj);
624 g_signal_connect (G_OBJECT (obj), "window-state-event",
625 G_CALLBACK (modest_msg_edit_window_window_state_event),
627 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
628 G_CALLBACK (text_buffer_end_user_action), obj);
629 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
630 G_CALLBACK (text_buffer_mark_set), obj);
631 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
632 G_CALLBACK (text_buffer_apply_tag), obj);
633 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
634 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
635 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
636 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
637 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
638 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
640 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
641 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
643 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
644 G_CALLBACK (msg_body_focus), obj);
645 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
646 G_CALLBACK (msg_body_focus), obj);
647 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
648 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
649 "changed", G_CALLBACK (recpt_field_changed), obj);
650 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
651 "changed", G_CALLBACK (recpt_field_changed), obj);
652 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
653 "changed", G_CALLBACK (recpt_field_changed), obj);
654 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
655 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
656 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
658 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
659 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
661 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
663 G_CALLBACK (vadj_changed),
666 priv->clipboard_change_handler_id =
667 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
668 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
669 priv->default_clipboard_change_handler_id =
670 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
671 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
676 init_window (ModestMsgEditWindow *obj)
678 GtkWidget *from_caption, *to_caption, *subject_caption;
679 GtkWidget *main_vbox;
680 ModestMsgEditWindowPrivate *priv;
681 GtkActionGroup *action_group;
682 ModestWindowPrivate *parent_priv;
683 GdkPixbuf *window_icon = NULL;
684 GError *error = NULL;
686 GtkSizeGroup *size_group;
687 GtkWidget *subject_box;
688 GtkWidget *attachment_icon;
689 GtkWidget *window_box;
690 #if (GTK_MINOR_VERSION >= 10)
691 GdkAtom deserialize_type;
693 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
694 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
696 parent_priv->ui_manager = gtk_ui_manager_new();
697 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
698 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
700 /* Add common actions */
701 gtk_action_group_add_actions (action_group,
702 modest_msg_edit_action_entries,
703 G_N_ELEMENTS (modest_msg_edit_action_entries),
705 gtk_action_group_add_toggle_actions (action_group,
706 modest_msg_edit_toggle_action_entries,
707 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
709 gtk_action_group_add_radio_actions (action_group,
710 modest_msg_edit_alignment_radio_action_entries,
711 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
713 G_CALLBACK (modest_ui_actions_on_change_justify),
715 gtk_action_group_add_radio_actions (action_group,
716 modest_msg_edit_priority_action_entries,
717 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
719 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
721 gtk_action_group_add_radio_actions (action_group,
722 modest_msg_edit_file_format_action_entries,
723 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
724 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
725 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
727 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
728 g_object_unref (action_group);
730 /* Load the UI definition */
731 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
734 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
735 g_clear_error (&error);
738 /* Add accelerators */
739 gtk_window_add_accel_group (GTK_WINDOW (obj),
740 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
742 parent_priv->menubar = NULL;
744 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
746 /* Note: This ModestPairList* must exist for as long as the combo
747 * that uses it, because the ModestComboBox uses the ID opaquely,
748 * so it can't know how to manage its memory. */
749 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
751 priv->to_field = modest_recpt_editor_new ();
752 priv->cc_field = modest_recpt_editor_new ();
753 priv->bcc_field = modest_recpt_editor_new ();
754 subject_box = gtk_hbox_new (FALSE, 0);
755 priv->priority_icon = gtk_image_new ();
756 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
757 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
758 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
759 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
760 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
761 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
762 priv->add_attachment_button = gtk_button_new ();
763 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
764 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
765 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
766 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
767 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
768 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
769 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
770 priv->attachments_view = modest_attachments_view_new (NULL);
772 priv->header_box = gtk_vbox_new (FALSE, 0);
774 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
775 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
776 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
777 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
778 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
779 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
780 g_object_unref (size_group);
782 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
783 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
784 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
785 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
786 gtk_size_group_add_widget (size_group, priv->subject_field);
787 gtk_size_group_add_widget (size_group, priv->attachments_view);
788 g_object_unref (size_group);
790 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
791 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
792 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
793 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
794 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
795 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
796 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
799 priv->msg_body = wp_text_view_new ();
800 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
801 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
802 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
803 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
804 #if (GTK_MINOR_VERSION >= 10)
805 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
806 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
808 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
809 deserialize_type, TRUE);
811 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
813 priv->find_toolbar = hildon_find_toolbar_new (NULL);
814 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
816 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
818 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
819 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
820 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
821 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
823 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
825 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
826 priv->frame = gtk_frame_new (NULL);
827 gtk_box_pack_start (GTK_BOX(main_vbox), priv->frame, TRUE, TRUE, 0);
829 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
830 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
831 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
833 window_box = gtk_vbox_new (FALSE, 0);
834 gtk_container_add (GTK_CONTAINER(obj), window_box);
836 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
838 gtk_container_add (GTK_CONTAINER (priv->frame), priv->msg_body);
840 /* Set window icon */
841 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
843 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
844 g_object_unref (window_icon);
849 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
851 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
853 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
854 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
855 priv->clipboard_change_handler_id))
856 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
857 priv->clipboard_change_handler_id);
858 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
859 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
860 priv->default_clipboard_change_handler_id))
861 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
862 priv->default_clipboard_change_handler_id);
864 if (priv->account_removed_handler_id &&
865 g_signal_handler_is_connected (modest_runtime_get_account_store (),
866 priv->account_removed_handler_id))
867 g_signal_handler_disconnect(modest_runtime_get_account_store (),
868 priv->account_removed_handler_id);
872 modest_msg_edit_window_finalize (GObject *obj)
874 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
876 /* Sanity check: shouldn't be needed, the window mgr should
877 call this function before */
878 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
880 if (priv->clipboard_text != NULL) {
881 g_free (priv->clipboard_text);
882 priv->clipboard_text = NULL;
885 if (priv->draft_msg != NULL) {
886 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
887 if (TNY_IS_HEADER (header)) {
888 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
889 modest_window_mgr_unregister_header (mgr, header);
891 g_object_unref (priv->draft_msg);
892 priv->draft_msg = NULL;
894 if (priv->outbox_msg != NULL) {
895 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
896 if (TNY_IS_HEADER (header)) {
897 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
898 modest_window_mgr_unregister_header (mgr, header);
900 g_object_unref (priv->outbox_msg);
901 priv->outbox_msg = NULL;
903 if (priv->scroll_drag_timeout_id > 0) {
904 g_source_remove (priv->scroll_drag_timeout_id);
905 priv->scroll_drag_timeout_id = 0;
907 g_free (priv->msg_uid);
908 g_free (priv->last_search);
909 g_slist_free (priv->font_items_group);
910 g_slist_free (priv->size_items_group);
911 g_object_unref (priv->attachments);
912 g_object_unref (priv->images);
914 /* This had to stay alive for as long as the combobox that used it: */
915 modest_pair_list_free (priv->from_field_protos);
917 G_OBJECT_CLASS(parent_class)->finalize (obj);
921 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type, guint64 *stream_size)
923 GdkPixbufLoader *loader;
929 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
931 if (loader == NULL) {
937 tny_stream_reset (TNY_STREAM (stream));
938 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
939 unsigned char read_buffer[128];
941 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
943 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
947 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
948 g_object_ref (pixbuf);
949 gdk_pixbuf_loader_close (loader, NULL);
950 g_object_unref (loader);
952 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
953 GdkPixbuf *new_pixbuf;
955 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
956 gdk_pixbuf_get_width (pixbuf);
957 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
958 g_object_unref (pixbuf);
969 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
971 ModestMsgEditWindowPrivate *priv;
974 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
976 for (iter = tny_list_create_iterator (attachments);
977 !tny_iterator_is_done (iter);
978 tny_iterator_next (iter)) {
979 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
980 const gchar *cid = tny_mime_part_get_content_id (part);
981 const gchar *mime_type = tny_mime_part_get_content_type (part);
982 if ((cid != NULL)&&(mime_type != NULL)) {
984 TnyStream *stream = tny_mime_part_get_stream (part);
985 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
988 g_object_unref (stream);
990 if (pixbuf != NULL) {
991 priv->images_count ++;
992 priv->images_size += stream_size;
993 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
994 g_object_unref (pixbuf);
997 g_object_unref (part);
1002 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1004 TnyMimePart *parent = NULL;
1005 const gchar *content_type = NULL;
1006 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1008 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1010 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1011 parent = g_object_ref (msg);
1012 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1013 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1016 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1017 iter = tny_list_create_iterator (parts);
1018 while (!tny_iterator_is_done (iter)) {
1020 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1021 content_type = tny_mime_part_get_content_type (part);
1022 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1026 g_object_unref (part);
1028 tny_iterator_next (iter);
1030 g_object_unref (iter);
1031 g_object_unref (parts);
1034 if (parent != NULL) {
1035 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1038 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1039 iter = tny_list_create_iterator (parts);
1040 while (!tny_iterator_is_done (iter)) {
1042 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1043 content_type = tny_mime_part_get_content_type (part);
1044 if (content_type && g_str_has_prefix (content_type, "image/")) {
1045 tny_list_prepend (priv->images, (GObject *) part);
1047 g_object_unref (part);
1048 tny_iterator_next (iter);
1050 g_object_unref (iter);
1051 g_object_unref (parts);
1052 g_object_unref (parent);
1057 update_last_cid (ModestMsgEditWindow *self, TnyList *attachments)
1060 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1062 for (iter = tny_list_create_iterator (attachments) ;
1063 !tny_iterator_is_done (iter);
1064 tny_iterator_next (iter)) {
1065 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1066 const gchar *cid = tny_mime_part_get_content_id (part);
1068 char *invalid = NULL;
1069 gint int_cid = strtol (cid, &invalid, 10);
1070 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
1071 priv->last_cid = int_cid;
1074 g_object_unref (part);
1079 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1082 const gchar *to, *cc, *bcc, *subject;
1084 ModestMsgEditWindowPrivate *priv;
1086 TnyHeaderFlags priority_flags;
1087 TnyFolder *msg_folder;
1088 gboolean is_html = FALSE;
1090 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1091 g_return_if_fail (TNY_IS_MSG (msg));
1093 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1095 header = tny_msg_get_header (msg);
1096 to = tny_header_get_to (header);
1097 cc = tny_header_get_cc (header);
1098 bcc = tny_header_get_bcc (header);
1099 subject = tny_header_get_subject (header);
1100 priority_flags = tny_header_get_priority (header);
1103 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1105 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1106 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1107 gtk_widget_show (priv->cc_caption);
1108 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1109 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1110 gtk_widget_hide (priv->cc_caption);
1113 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1114 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1115 gtk_widget_show (priv->bcc_caption);
1116 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1117 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1118 gtk_widget_hide (priv->bcc_caption);
1121 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1122 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1125 update_window_title (self);
1127 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1128 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1130 if ((body == NULL)||(body[0] == '\0')) {
1132 body = modest_text_utils_convert_to_html ("");
1135 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1136 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1139 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1142 /* Add attachments to the view */
1143 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1144 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1145 if (tny_list_get_length (priv->attachments) == 0) {
1146 gtk_widget_hide (priv->attachments_caption);
1148 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1149 gtk_widget_show_all (priv->attachments_caption);
1151 get_related_images (self, msg);
1152 update_last_cid (self, priv->attachments);
1153 update_last_cid (self, priv->images);
1154 replace_with_images (self, priv->images);
1156 if (preserve_is_rich && !is_html) {
1157 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1158 /* Get the default format required from configuration */
1159 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1160 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1163 /* Set the default focus depending on having already a To: field or not */
1164 if ((!to)||(*to == '\0')) {
1165 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1167 gtk_widget_grab_focus (priv->msg_body);
1170 /* TODO: lower priority, select in the From: combo to the
1171 value that comes from msg <- not sure, should it be
1174 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1176 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1177 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1179 modest_msg_edit_window_reset_modified (self);
1181 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1182 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1183 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1184 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1186 if (priv->msg_uid) {
1187 g_free (priv->msg_uid);
1188 priv->msg_uid = NULL;
1191 /* we should set a reference to the incoming message if it is a draft */
1192 msg_folder = tny_msg_get_folder (msg);
1194 if (modest_tny_folder_is_local_folder (msg_folder)) {
1195 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1196 if (type == TNY_FOLDER_TYPE_INVALID)
1197 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1199 if (type == TNY_FOLDER_TYPE_DRAFTS)
1200 priv->draft_msg = g_object_ref(msg);
1201 if (type == TNY_FOLDER_TYPE_OUTBOX)
1202 priv->outbox_msg = g_object_ref(msg);
1203 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1205 g_object_unref (msg_folder);
1210 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1213 GList *item_children, *node;
1214 GtkWidget *bin_child;
1216 bin_child = gtk_bin_get_child (GTK_BIN(item));
1218 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1220 for (node = item_children; node != NULL; node = g_list_next (node)) {
1221 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1222 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1225 g_list_free (item_children);
1229 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1232 GList *item_children, *node;
1234 box = gtk_bin_get_child (GTK_BIN (item));
1235 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1236 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1238 for (node = item_children; node != NULL; node = g_list_next (node)) {
1239 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1240 if (GTK_IS_TOGGLE_BUTTON (node->data))
1241 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1242 else if (GTK_IS_BUTTON (node->data))
1243 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1245 g_list_free (item_children);
1250 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1252 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1253 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1254 GtkWidget *placeholder;
1255 GtkWidget *tool_item;
1260 GtkWidget *sizes_menu;
1261 GtkWidget *fonts_menu;
1262 GSList *radio_group = NULL;
1263 GSList *node = NULL;
1267 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1268 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1270 /* Font color placeholder */
1271 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1272 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1275 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1276 priv->font_color_button = hildon_color_button_new ();
1277 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1278 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1279 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1280 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1281 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1282 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1283 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1285 G_CALLBACK (modest_msg_edit_window_color_button_change),
1288 /* Font size and face placeholder */
1289 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1290 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1292 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1293 priv->size_tool_button_label = gtk_label_new (NULL);
1294 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1295 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1296 size_text,"</span>", NULL);
1297 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1299 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1300 sizes_menu = gtk_menu_new ();
1301 priv->size_items_group = NULL;
1303 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1304 GtkWidget *size_menu_item;
1306 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1307 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1308 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1309 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1310 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1311 gtk_widget_show (size_menu_item);
1313 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1317 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1318 GtkWidget *item = (GtkWidget *) node->data;
1319 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1323 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1324 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1325 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1326 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1327 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1328 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1329 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1330 priv->font_size_toolitem = tool_item;
1333 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1334 priv->font_tool_button_label = gtk_label_new (NULL);
1335 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1336 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1338 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1339 fonts_menu = gtk_menu_new ();
1340 priv->font_items_group = NULL;
1342 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1343 GtkWidget *font_menu_item;
1344 GtkWidget *child_label;
1346 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1347 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1348 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1349 wp_get_font_name (font_index), "</span>", NULL);
1350 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1353 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1354 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1355 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1356 gtk_widget_show (font_menu_item);
1358 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1361 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1362 GtkWidget *item = (GtkWidget *) node->data;
1363 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1366 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1367 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1368 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1369 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1370 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1371 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1372 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1373 priv->font_face_toolitem = tool_item;
1375 /* Set expand and homogeneous for remaining items */
1376 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1377 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1378 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1379 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1380 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1381 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1382 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1383 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1384 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1386 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1387 will not show the tool items added to the placeholders) */
1388 gtk_widget_show_all (parent_priv->toolbar);
1390 /* Set the no show all *after* showing all items. We do not
1391 want the toolbar to be shown with a show all because it
1392 could go agains the gconf setting regarding showing or not
1393 the toolbar of the editor window */
1394 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1400 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1403 ModestWindowPrivate *parent_priv;
1404 ModestMsgEditWindowPrivate *priv;
1405 ModestPair *account_pair = NULL;
1406 ModestDimmingRulesGroup *menu_rules_group = NULL;
1407 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1408 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1409 ModestWindowMgr *mgr = NULL;
1411 g_return_val_if_fail (msg, NULL);
1412 g_return_val_if_fail (account_name, NULL);
1414 mgr = modest_runtime_get_window_mgr ();
1416 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1418 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1419 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1421 /* Menubar. Update the state of some toggles */
1422 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1423 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1424 priv->from_field_protos = get_transports ();
1425 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1426 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1427 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1430 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1432 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1434 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1436 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1437 if (account_pair != NULL)
1438 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1440 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1441 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1442 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1443 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1444 /* Add common dimming rules */
1445 modest_dimming_rules_group_add_rules (menu_rules_group,
1446 modest_msg_edit_window_menu_dimming_entries,
1447 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1448 MODEST_WINDOW (obj));
1449 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1450 modest_msg_edit_window_toolbar_dimming_entries,
1451 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1452 MODEST_WINDOW (obj));
1453 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1454 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1455 MODEST_WINDOW (obj));
1456 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1457 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1458 MODEST_WINDOW (obj));
1459 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1460 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1461 MODEST_WINDOW (obj));
1462 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1463 modest_msg_edit_window_clipboard_dimming_entries,
1464 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1465 MODEST_WINDOW (obj));
1466 /* Insert dimming rules group for this window */
1467 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1468 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1469 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1470 /* Checks the dimming rules */
1471 g_object_unref (menu_rules_group);
1472 g_object_unref (toolbar_rules_group);
1473 g_object_unref (clipboard_rules_group);
1474 gtk_widget_show_all (GTK_WIDGET (obj));
1476 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1478 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1480 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1481 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1482 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1483 priv->update_caption_visibility = TRUE;
1485 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1487 /* Track account-removed signal, this window should be closed
1488 in the case we're creating a mail associated to the account
1490 priv->account_removed_handler_id =
1491 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1493 G_CALLBACK(on_account_removed),
1496 return (ModestWindow*) obj;
1500 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1502 GString **string_buffer = (GString **) user_data;
1504 *string_buffer = g_string_append (*string_buffer, buffer);
1510 * @result: A new string which should be freed with g_free().
1513 get_formatted_data (ModestMsgEditWindow *edit_window)
1515 ModestMsgEditWindowPrivate *priv;
1516 GString *string_buffer = g_string_new ("");
1518 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1520 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1522 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1524 return g_string_free (string_buffer, FALSE);
1529 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1532 const gchar *account_name;
1533 ModestMsgEditWindowPrivate *priv;
1534 TnyIterator *att_iter;
1536 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1538 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1540 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1541 g_return_val_if_fail (account_name, NULL);
1544 /* don't free these (except from) */
1545 data = g_slice_new0 (MsgData);
1546 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1548 data->account_name = g_strdup (account_name);
1549 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1550 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1551 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1552 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1553 if (priv->draft_msg) {
1554 data->draft_msg = g_object_ref (priv->draft_msg);
1555 } else if (priv->outbox_msg) {
1556 data->draft_msg = g_object_ref (priv->outbox_msg);
1558 data->draft_msg = NULL;
1561 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1563 gtk_text_buffer_get_bounds (buf, &b, &e);
1564 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1566 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1567 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1569 data->html_body = NULL;
1571 /* deep-copy the data */
1572 att_iter = tny_list_create_iterator (priv->attachments);
1573 data->attachments = NULL;
1574 while (!tny_iterator_is_done (att_iter)) {
1575 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1576 if (!(TNY_IS_MIME_PART(part))) {
1577 g_warning ("strange data in attachment list");
1578 g_object_unref (part);
1579 tny_iterator_next (att_iter);
1582 data->attachments = g_list_append (data->attachments,
1584 tny_iterator_next (att_iter);
1586 g_object_unref (att_iter);
1588 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1589 att_iter = tny_list_create_iterator (priv->images);
1590 data->images = NULL;
1591 while (!tny_iterator_is_done (att_iter)) {
1592 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1594 if (!(TNY_IS_MIME_PART(part))) {
1595 g_warning ("strange data in attachment list");
1596 g_object_unref (part);
1597 tny_iterator_next (att_iter);
1600 cid = tny_mime_part_get_content_id (part);
1602 gchar *image_tag_id;
1603 GtkTextTag *image_tag;
1605 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1606 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1607 g_free (image_tag_id);
1609 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1611 ((gtk_text_iter_has_tag (&iter, image_tag))||
1612 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1613 data->images = g_list_append (data->images,
1614 g_object_ref (part));
1616 g_object_unref (part);
1617 tny_iterator_next (att_iter);
1620 data->priority_flags = priv->priority_flags;
1627 unref_gobject (GObject *obj, gpointer data)
1629 if (!G_IS_OBJECT(obj))
1631 g_object_unref (obj);
1635 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1638 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1646 g_free (data->from);
1647 g_free (data->subject);
1648 g_free (data->plain_body);
1649 g_free (data->html_body);
1650 g_free (data->account_name);
1652 if (data->draft_msg != NULL) {
1653 g_object_unref (data->draft_msg);
1654 data->draft_msg = NULL;
1657 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1658 g_list_free (data->attachments);
1659 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1660 g_list_free (data->images);
1662 g_slice_free (MsgData, data);
1666 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1668 guint64 *parts_size)
1670 ModestMsgEditWindowPrivate *priv;
1672 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1674 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1676 /* TODO: add images */
1677 *parts_size += priv->images_size;
1678 *parts_count += priv->images_count;
1683 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1686 ModestMsgEditWindowPrivate *priv = NULL;
1687 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1689 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1691 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1693 return MODEST_MSG_EDIT_FORMAT_HTML;
1695 return MODEST_MSG_EDIT_FORMAT_TEXT;
1699 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1700 ModestMsgEditFormat format)
1702 ModestMsgEditWindowPrivate *priv;
1704 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1705 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1708 case MODEST_MSG_EDIT_FORMAT_HTML:
1709 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1711 case MODEST_MSG_EDIT_FORMAT_TEXT:
1712 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1715 g_return_if_reached ();
1719 ModestMsgEditFormatState *
1720 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1722 ModestMsgEditFormatState *format_state = NULL;
1723 ModestMsgEditWindowPrivate *priv;
1724 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1726 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1727 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1729 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1731 format_state = g_new0 (ModestMsgEditFormatState, 1);
1732 format_state->bold = buffer_format->bold&0x1;
1733 format_state->italics = buffer_format->italic&0x1;
1734 format_state->bullet = buffer_format->bullet&0x1;
1735 format_state->color = buffer_format->color;
1736 format_state->font_size = buffer_format->font_size;
1737 format_state->font_family = wp_get_font_name (buffer_format->font);
1738 format_state->justification = buffer_format->justification;
1739 g_free (buffer_format);
1741 return format_state;
1746 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1747 const ModestMsgEditFormatState *format_state)
1749 ModestMsgEditWindowPrivate *priv;
1750 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1751 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1752 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1753 g_return_if_fail (format_state != NULL);
1755 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1756 gtk_widget_grab_focus (priv->msg_body);
1757 buffer_format->bold = (format_state->bold != FALSE);
1758 buffer_format->italic = (format_state->italics != FALSE);
1759 buffer_format->color = format_state->color;
1760 buffer_format->font_size = format_state->font_size;
1761 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1762 buffer_format->justification = format_state->justification;
1763 buffer_format->bullet = format_state->bullet;
1765 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1767 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1768 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1769 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1770 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1771 buffer_format->cs.font = (buffer_format->font != current_format->font);
1772 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1773 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1775 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1776 if (buffer_format->cs.bold) {
1777 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1778 GINT_TO_POINTER (buffer_format->bold&0x1));
1780 if (buffer_format->cs.italic) {
1781 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1782 GINT_TO_POINTER (buffer_format->italic&0x1));
1784 if (buffer_format->cs.color) {
1785 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1786 GINT_TO_POINTER (&(buffer_format->color)));
1788 if (buffer_format->cs.font_size) {
1789 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1790 GINT_TO_POINTER (buffer_format->font_size));
1792 if (buffer_format->cs.justification) {
1793 switch (buffer_format->justification) {
1794 case GTK_JUSTIFY_LEFT:
1795 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1796 GINT_TO_POINTER(TRUE));
1798 case GTK_JUSTIFY_CENTER:
1799 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1800 GINT_TO_POINTER(TRUE));
1802 case GTK_JUSTIFY_RIGHT:
1803 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1804 GINT_TO_POINTER(TRUE));
1811 if (buffer_format->cs.font) {
1812 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1813 GINT_TO_POINTER (buffer_format->font));
1815 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1816 if (buffer_format->cs.bullet) {
1817 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1818 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1820 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1822 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1824 g_free (current_format);
1829 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1831 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1833 ModestWindowPrivate *parent_priv;
1834 ModestMsgEditWindowPrivate *priv;
1835 GtkWidget *new_size_menuitem;
1836 GtkWidget *new_font_menuitem;
1838 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1839 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1841 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1842 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1843 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1844 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1846 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1847 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1848 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1851 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1853 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1854 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1856 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1857 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1859 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1860 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1863 switch (buffer_format->justification)
1865 case GTK_JUSTIFY_LEFT:
1866 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentLeftMenu");
1868 case GTK_JUSTIFY_CENTER:
1869 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentCenterMenu");
1871 case GTK_JUSTIFY_RIGHT:
1872 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentRightMenu");
1879 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1881 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1882 G_CALLBACK (modest_msg_edit_window_color_button_change),
1884 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1885 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1886 G_CALLBACK (modest_msg_edit_window_color_button_change),
1889 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1890 buffer_format->font_size))->data);
1891 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1895 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1896 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1897 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1899 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1900 G_CALLBACK (modest_msg_edit_window_size_change),
1902 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1903 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1904 G_CALLBACK (modest_msg_edit_window_size_change),
1908 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1909 buffer_format->font))->data);
1910 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1914 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1915 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1916 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1918 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1919 G_CALLBACK (modest_msg_edit_window_font_change),
1921 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1922 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1923 G_CALLBACK (modest_msg_edit_window_font_change),
1927 g_free (buffer_format);
1931 #ifdef MODEST_HILDON_VERSION_0
1933 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1936 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1937 ModestMsgEditWindowPrivate *priv;
1938 GtkWidget *dialog = NULL;
1940 GdkColor *new_color = NULL;
1942 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1943 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1945 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1946 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1947 g_free (buffer_format);
1949 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1950 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1951 if (new_color != NULL) {
1952 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1953 (gpointer) new_color);
1956 gtk_widget_destroy (dialog);
1961 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1964 ModestMsgEditWindowPrivate *priv;
1965 GtkWidget *dialog = NULL;
1967 GdkColor *old_color = NULL;
1968 const GdkColor *new_color = NULL;
1970 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1971 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1973 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1974 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1976 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1977 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1978 if (new_color != NULL)
1979 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1981 gtk_widget_destroy (dialog);
1987 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1990 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1991 ModestMsgEditWindowPrivate *priv;
1992 GtkWidget *dialog = NULL;
1994 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1995 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1997 dialog = hildon_color_chooser_new ();
1998 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1999 g_free (buffer_format);
2001 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2003 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2004 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2007 gtk_widget_destroy (dialog);
2012 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2015 ModestMsgEditWindowPrivate *priv;
2016 GtkWidget *dialog = NULL;
2017 GdkColor *old_color = NULL;
2019 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2020 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2022 dialog = hildon_color_chooser_new ();
2023 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2025 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2027 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2028 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2030 gtk_widget_destroy (dialog);
2033 #endif /*!MODEST_HILDON_VERSION_0*/
2037 static TnyStream* create_stream_for_uri (const gchar* uri)
2042 TnyStream *result = NULL;
2044 GnomeVFSHandle *handle = NULL;
2045 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2046 if (test == GNOME_VFS_OK) {
2047 /* Create the tinymail stream: */
2048 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
2049 result = TNY_STREAM (tny_vfs_stream_new (handle));
2056 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2059 ModestMsgEditWindowPrivate *priv;
2060 GtkWidget *dialog = NULL;
2062 GSList *uris = NULL;
2063 GSList *uri_node = NULL;
2065 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2067 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2068 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2069 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2071 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2073 response = gtk_dialog_run (GTK_DIALOG (dialog));
2075 case GTK_RESPONSE_OK:
2076 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2081 gtk_widget_destroy (dialog);
2083 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2085 GnomeVFSHandle *handle = NULL;
2086 GnomeVFSResult result;
2087 GtkTextIter position;
2088 GtkTextMark *insert_mark;
2090 uri = (const gchar *) uri_node->data;
2091 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2092 if (result == GNOME_VFS_OK) {
2094 GnomeVFSFileInfo *info;
2095 gchar *filename, *basename, *escaped_filename;
2096 TnyMimePart *mime_part;
2098 const gchar *mime_type = NULL;
2099 GnomeVFSURI *vfs_uri;
2100 guint64 stream_size;
2102 vfs_uri = gnome_vfs_uri_new (uri);
2104 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2105 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2106 g_free (escaped_filename);
2107 gnome_vfs_uri_unref (vfs_uri);
2108 info = gnome_vfs_file_info_new ();
2110 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2111 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2113 mime_type = gnome_vfs_file_info_get_mime_type (info);
2115 mime_part = tny_platform_factory_new_mime_part
2116 (modest_runtime_get_platform_factory ());
2118 TnyStream *stream = create_stream_for_uri (uri);
2119 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2121 content_id = g_strdup_printf ("%d", priv->last_cid);
2122 tny_mime_part_set_content_id (mime_part, content_id);
2123 g_free (content_id);
2126 basename = g_path_get_basename (filename);
2127 tny_mime_part_set_filename (mime_part, basename);
2130 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2132 if (pixbuf != NULL) {
2133 priv->images_size += stream_size;
2134 priv->images_count ++;
2135 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2136 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2137 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2140 tny_list_prepend (priv->images, (GObject *) mime_part);
2141 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2143 g_object_unref (mime_part);
2144 gnome_vfs_file_info_unref (info);
2153 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2155 GtkWidget *dialog = NULL;
2157 GSList *uris = NULL;
2160 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2161 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2162 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2164 response = gtk_dialog_run (GTK_DIALOG (dialog));
2166 case GTK_RESPONSE_OK:
2167 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2172 gtk_widget_destroy (dialog);
2174 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2175 const gchar *uri = (const gchar *) uri_node->data;
2176 modest_msg_edit_window_attach_file_one (window, uri);
2178 g_slist_foreach (uris, (GFunc) g_free, NULL);
2179 g_slist_free (uris);
2183 modest_msg_edit_window_attach_file_one (
2184 ModestMsgEditWindow *window,
2187 g_return_if_fail (window);
2188 g_return_if_fail (uri);
2190 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2193 GnomeVFSHandle *handle = NULL;
2194 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2195 if (result == GNOME_VFS_OK) {
2196 TnyMimePart *mime_part;
2198 const gchar *mime_type = NULL;
2200 gchar *escaped_filename;
2203 GnomeVFSFileInfo *info;
2204 GnomeVFSURI *vfs_uri;
2206 vfs_uri = gnome_vfs_uri_new (uri);
2209 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2210 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2211 g_free (escaped_filename);
2212 gnome_vfs_uri_unref (vfs_uri);
2214 info = gnome_vfs_file_info_new ();
2216 if (gnome_vfs_get_file_info (uri,
2218 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2220 mime_type = gnome_vfs_file_info_get_mime_type (info);
2221 mime_part = tny_platform_factory_new_mime_part
2222 (modest_runtime_get_platform_factory ());
2223 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2225 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2227 g_object_unref (stream);
2229 content_id = g_strdup_printf ("%d", priv->last_cid);
2230 tny_mime_part_set_content_id (mime_part, content_id);
2231 g_free (content_id);
2234 basename = g_path_get_basename (filename);
2235 tny_mime_part_set_filename (mime_part, basename);
2238 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2239 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2241 info->size == 0, info->size);
2242 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2243 gtk_widget_show_all (priv->attachments_caption);
2244 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2246 g_object_unref (mime_part);
2247 gnome_vfs_file_info_unref (info);
2252 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2255 ModestMsgEditWindowPrivate *priv;
2258 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2259 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2261 if (att_list == NULL) {
2262 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2264 g_object_ref (att_list);
2267 if (tny_list_get_length (att_list) == 0) {
2268 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2270 GtkWidget *confirmation_dialog = NULL;
2271 gboolean dialog_response;
2272 gchar *message = NULL;
2273 gchar *filename = NULL;
2275 if (tny_list_get_length (att_list) == 1) {
2277 iter = tny_list_create_iterator (att_list);
2278 part = (TnyMimePart *) tny_iterator_get_current (iter);
2279 g_object_unref (iter);
2280 if (TNY_IS_MSG (part)) {
2281 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2283 filename = g_strdup (tny_header_get_subject (header));
2284 g_object_unref (header);
2286 if (filename == NULL) {
2287 filename = g_strdup (_("mail_va_no_subject"));
2290 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2292 g_object_unref (part);
2294 filename = g_strdup ("");
2296 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2297 (tny_list_get_length (att_list) == 1)), filename);
2299 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2301 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2302 gtk_widget_destroy (confirmation_dialog);
2303 if (!dialog_response) {
2304 g_object_unref (att_list);
2307 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2309 for (iter = tny_list_create_iterator (att_list);
2310 !tny_iterator_is_done (iter);
2311 tny_iterator_next (iter)) {
2312 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2313 const gchar *att_id;
2314 tny_list_remove (priv->attachments, (GObject *) mime_part);
2316 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2318 if (tny_list_get_length (priv->attachments) == 0)
2319 gtk_widget_hide (priv->attachments_caption);
2320 att_id = tny_mime_part_get_content_id (mime_part);
2322 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2324 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2325 g_object_unref (mime_part);
2329 g_object_unref (att_list);
2331 /* if the last attachment has been removed, focus the Subject: field */
2332 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2333 gtk_widget_grab_focus (priv->subject_field);
2337 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2340 ModestMsgEditWindowPrivate *priv;
2341 GdkColor *new_color;
2342 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2344 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2345 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2348 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2350 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2352 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2354 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2359 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2362 ModestMsgEditWindowPrivate *priv;
2363 gint new_size_index;
2364 ModestMsgEditWindow *window;
2367 window = MODEST_MSG_EDIT_WINDOW (userdata);
2368 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2369 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2371 if (gtk_check_menu_item_get_active (menu_item)) {
2373 WPTextBufferFormat format;
2375 memset (&format, 0, sizeof (format));
2376 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2378 label = gtk_bin_get_child (GTK_BIN (menu_item));
2380 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2381 format.cs.font_size = TRUE;
2382 format.cs.text_position = TRUE;
2383 format.cs.font = TRUE;
2384 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2385 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2387 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2388 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2389 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2391 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2392 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2393 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2399 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2402 ModestMsgEditWindowPrivate *priv;
2403 gint new_font_index;
2404 ModestMsgEditWindow *window;
2407 window = MODEST_MSG_EDIT_WINDOW (userdata);
2408 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2409 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2411 if (gtk_check_menu_item_get_active (menu_item)) {
2414 label = gtk_bin_get_child (GTK_BIN (menu_item));
2416 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2418 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2419 GINT_TO_POINTER(new_font_index)))
2420 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2422 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2423 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2424 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2430 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2432 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2433 ModestWindowPrivate *parent_priv;
2434 ModestWindowMgr *mgr;
2435 gboolean is_fullscreen;
2436 GtkAction *fs_toggle_action;
2439 mgr = modest_runtime_get_window_mgr ();
2440 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2442 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2444 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2445 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2446 if (is_fullscreen != active)
2447 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2455 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2458 ModestMsgEditWindowPrivate *priv = NULL;
2459 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2461 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2462 if (!priv->update_caption_visibility)
2465 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2467 gtk_widget_show (priv->cc_caption);
2469 gtk_widget_hide (priv->cc_caption);
2471 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2475 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2478 ModestMsgEditWindowPrivate *priv = NULL;
2479 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2481 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2482 if (!priv->update_caption_visibility)
2485 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2487 gtk_widget_show (priv->bcc_caption);
2489 gtk_widget_hide (priv->bcc_caption);
2491 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2495 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2496 ModestRecptEditor *editor)
2498 ModestMsgEditWindowPrivate *priv;
2500 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2501 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2502 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2504 if (editor == NULL) {
2505 GtkWidget *view_focus;
2506 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2508 /* This code should be kept in sync with ModestRecptEditor. The
2509 textview inside the recpt editor is the one that really gets the
2510 focus. As it's inside a scrolled window, and this one inside the
2511 hbox recpt editor inherits from, we'll need to go up in the
2512 hierarchy to know if the text view is part of the recpt editor
2513 or if it's a different text entry */
2515 if (gtk_widget_get_parent (view_focus)) {
2516 GtkWidget *first_parent;
2518 first_parent = gtk_widget_get_parent (view_focus);
2519 if (gtk_widget_get_parent (first_parent) &&
2520 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2521 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2526 editor = MODEST_RECPT_EDITOR (priv->to_field);
2530 modest_address_book_select_addresses (editor);
2535 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2537 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2539 modest_msg_edit_window_open_addressbook (window, NULL);
2543 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2544 gboolean show_toolbar)
2546 ModestWindowPrivate *parent_priv;
2547 const gchar *action_name;
2550 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2551 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2553 /* We can not just use the code of
2554 modest_msg_edit_window_setup_toolbar because it has a
2555 mixture of both initialization and creation code. */
2557 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2559 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2561 /* Update also the actions (to update the toggles in the
2562 menus), we have to do it manually because some other window
2563 of the same time could have changed it (remember that the
2564 toolbar fullscreen mode is shared by all the windows of the
2566 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2567 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2569 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2571 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2572 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2578 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2579 TnyHeaderFlags priority_flags)
2581 ModestMsgEditWindowPrivate *priv;
2582 ModestWindowPrivate *parent_priv;
2584 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2586 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2587 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2589 if (priv->priority_flags != priority_flags) {
2590 GtkAction *priority_action = NULL;
2592 priv->priority_flags = priority_flags;
2594 switch (priority_flags) {
2595 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2596 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2597 gtk_widget_show (priv->priority_icon);
2598 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2599 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2601 case TNY_HEADER_FLAG_LOW_PRIORITY:
2602 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2603 gtk_widget_show (priv->priority_icon);
2604 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2605 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2608 gtk_widget_hide (priv->priority_icon);
2609 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2610 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2613 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2614 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2619 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2622 ModestMsgEditWindowPrivate *priv;
2623 ModestWindowPrivate *parent_priv;
2624 gint current_format;
2626 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2628 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2629 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2631 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2632 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2634 if (current_format != file_format) {
2635 switch (file_format) {
2636 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2637 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2638 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2640 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2644 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2645 response = gtk_dialog_run (GTK_DIALOG (dialog));
2646 gtk_widget_destroy (dialog);
2647 if (response == GTK_RESPONSE_OK) {
2648 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2650 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2651 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2656 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2661 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2664 ModestMsgEditWindowPrivate *priv;
2665 WPTextBufferFormat oldfmt, fmt;
2666 gint old_position = 0;
2670 GdkColor *color = NULL;
2671 gboolean bold, bold_set, italic, italic_set;
2672 gboolean underline, underline_set;
2673 gboolean strikethrough, strikethrough_set;
2674 gboolean position_set;
2675 gboolean font_size_set, font_set, color_set;
2678 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2679 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2681 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2683 /* First we get the currently selected font information */
2684 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2686 switch (oldfmt.text_position) {
2687 case TEXT_POSITION_NORMAL:
2690 case TEXT_POSITION_SUPERSCRIPT:
2698 g_object_set (G_OBJECT (dialog),
2699 "bold", oldfmt.bold != FALSE,
2700 "bold-set", !oldfmt.cs.bold,
2701 "underline", oldfmt.underline != FALSE,
2702 "underline-set", !oldfmt.cs.underline,
2703 "italic", oldfmt.italic != FALSE,
2704 "italic-set", !oldfmt.cs.italic,
2705 "strikethrough", oldfmt.strikethrough != FALSE,
2706 "strikethrough-set", !oldfmt.cs.strikethrough,
2707 "color", &oldfmt.color,
2708 "color-set", !oldfmt.cs.color,
2709 "size", wp_font_size[oldfmt.font_size],
2710 "size-set", !oldfmt.cs.font_size,
2711 "position", old_position,
2712 "position-set", !oldfmt.cs.text_position,
2713 "family", wp_get_font_name (oldfmt.font),
2714 "family-set", !oldfmt.cs.font,
2717 gtk_widget_show_all (dialog);
2718 response = gtk_dialog_run (GTK_DIALOG (dialog));
2719 if (response == GTK_RESPONSE_OK) {
2721 g_object_get( dialog,
2723 "bold-set", &bold_set,
2724 "underline", &underline,
2725 "underline-set", &underline_set,
2727 "italic-set", &italic_set,
2728 "strikethrough", &strikethrough,
2729 "strikethrough-set", &strikethrough_set,
2731 "color-set", &color_set,
2733 "size-set", &font_size_set,
2734 "family", &font_name,
2735 "family-set", &font_set,
2736 "position", &position,
2737 "position-set", &position_set,
2742 if (response == GTK_RESPONSE_OK) {
2743 memset(&fmt, 0, sizeof(fmt));
2749 fmt.italic = italic;
2750 fmt.cs.italic = TRUE;
2752 if (underline_set) {
2753 fmt.underline = underline;
2754 fmt.cs.underline = TRUE;
2756 if (strikethrough_set) {
2757 fmt.strikethrough = strikethrough;
2758 fmt.cs.strikethrough = TRUE;
2763 ? TEXT_POSITION_NORMAL
2764 : ( ( position == 1 )
2765 ? TEXT_POSITION_SUPERSCRIPT
2766 : TEXT_POSITION_SUBSCRIPT );
2767 fmt.cs.text_position = TRUE;
2768 fmt.font_size = oldfmt.font_size;
2772 fmt.cs.color = TRUE;
2775 fmt.font = wp_get_font_index(font_name,
2780 if (font_size_set) {
2781 fmt.cs.font_size = TRUE;
2782 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2784 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2785 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2787 gtk_widget_destroy (dialog);
2789 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2793 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2795 ModestMsgEditWindowPrivate *priv;
2797 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2800 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2802 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2803 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2808 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2810 ModestMsgEditWindowPrivate *priv;
2812 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2813 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2815 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2817 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2818 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2823 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2825 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2827 priv->can_undo = can_undo;
2831 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2833 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2835 priv->can_redo = can_redo;
2839 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2841 ModestMsgEditWindowPrivate *priv;
2842 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2843 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2845 return priv->can_undo;
2849 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2851 ModestMsgEditWindowPrivate *priv;
2852 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2853 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2855 return priv->can_redo;
2860 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2863 GtkTextIter match_start, match_end;
2865 if (image_id == NULL)
2868 gtk_text_buffer_get_start_iter (buffer, &iter);
2870 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2871 GSList *tags = gtk_text_iter_get_tags (&match_start);
2873 for (node = tags; node != NULL; node = g_slist_next (node)) {
2874 GtkTextTag *tag = (GtkTextTag *) node->data;
2875 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2876 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2877 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2879 offset = gtk_text_iter_get_offset (&match_start);
2880 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2881 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2885 gtk_text_iter_forward_char (&iter);
2890 message_is_empty (ModestMsgEditWindow *window)
2892 ModestMsgEditWindowPrivate *priv = NULL;
2894 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2895 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2897 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2898 * so we can ignore markup.
2900 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2903 count = gtk_text_buffer_get_char_count (buf);
2909 msg_body_focus (GtkWidget *focus,
2910 GdkEventFocus *event,
2914 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2915 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
2916 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
2921 recpt_field_changed (GtkTextBuffer *buffer,
2922 ModestMsgEditWindow *editor)
2924 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2925 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
2929 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2931 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2932 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
2936 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2938 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2939 GtkTextBuffer *buffer;
2941 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2942 gtk_text_buffer_set_modified (buffer, FALSE);
2943 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2944 gtk_text_buffer_set_modified (buffer, FALSE);
2945 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2946 gtk_text_buffer_set_modified (buffer, FALSE);
2947 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2951 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2953 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2954 GtkTextBuffer *buffer;
2956 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2957 if (gtk_text_buffer_get_modified (buffer))
2959 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2960 if (gtk_text_buffer_get_modified (buffer))
2962 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2963 if (gtk_text_buffer_get_modified (buffer))
2965 if (gtk_text_buffer_get_modified (priv->text_buffer))
2975 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2977 ModestMsgEditWindowPrivate *priv = NULL;
2979 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2980 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2982 /* check if there's no recipient added */
2983 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2984 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2985 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2986 /* no recipient contents, then select contacts */
2987 modest_msg_edit_window_open_addressbook (window, NULL);
2991 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2992 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2995 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2996 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2999 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3000 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3004 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3005 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3006 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3013 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3014 ModestMsgEditWindow *window)
3016 modest_msg_edit_window_offer_attach_file (window);
3020 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3022 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3024 return priv->clipboard_text;
3028 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3030 ModestMsgEditWindow *window)
3032 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3033 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3035 if (!GTK_WIDGET_VISIBLE (window))
3038 text = gtk_clipboard_wait_for_text (selection_clipboard);
3040 if (priv->clipboard_text != NULL) {
3041 g_free (priv->clipboard_text);
3043 priv->clipboard_text = text;
3045 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3048 subject_field_move_cursor (GtkEntry *entry,
3049 GtkMovementStep step,
3054 if (!GTK_WIDGET_VISIBLE (window))
3057 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3061 update_window_title (ModestMsgEditWindow *window)
3063 ModestMsgEditWindowPrivate *priv = NULL;
3064 const gchar *subject;
3066 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3067 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3068 if (subject == NULL || subject[0] == '\0')
3069 subject = _("mail_va_new_email");
3071 gtk_window_set_title (GTK_WINDOW (window), subject);
3076 subject_field_changed (GtkEditable *editable,
3077 ModestMsgEditWindow *window)
3079 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3080 update_window_title (window);
3081 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3082 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3083 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3087 subject_field_insert_text (GtkEditable *editable,
3089 gint new_text_length,
3091 ModestMsgEditWindow *window)
3093 GString *result = g_string_new ("");
3095 gint result_len = 0;
3096 const gchar *entry_text = NULL;
3099 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3100 old_length = g_utf8_strlen (entry_text, -1);
3102 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3103 gunichar c = g_utf8_get_char_validated (current, 8);
3104 /* Invalid unichar, stop */
3110 result = g_string_append_unichar (result, c);
3114 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3115 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3118 /* Prevent endless recursion */
3119 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3120 g_signal_emit_by_name (editable, "insert-text",
3121 (gpointer) result->str, (gpointer) result->len,
3122 (gpointer) position, (gpointer) window);
3123 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3127 if (result_len + old_length > 1000) {
3128 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3129 dgettext("hildon-common-strings",
3130 "ckdg_ib_maximum_characters_reached"));
3133 g_string_free (result, TRUE);
3137 text_buffer_insert_text (GtkTextBuffer *buffer,
3140 gint new_text_length,
3141 ModestMsgEditWindow *window)
3143 GString *result = g_string_new ("");
3145 gint result_len = 0;
3146 gboolean changed = FALSE;
3148 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3149 gunichar c = g_utf8_get_char_validated (current, 8);
3150 /* Invalid unichar, stop */
3156 result = g_string_append_c (result, ' ');
3160 result = g_string_append_unichar (result, c);
3166 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3167 g_signal_handlers_block_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3168 g_signal_emit_by_name (buffer, "insert-text",
3170 (gpointer) result->str, (gpointer) result->len,
3172 g_signal_handlers_unblock_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3175 g_string_free (result, TRUE);
3179 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3182 ModestMsgEditWindowPrivate *priv = NULL;
3184 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3185 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3187 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3190 gtk_widget_show_all (priv->find_toolbar);
3191 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3193 gtk_widget_hide_all (priv->find_toolbar);
3194 gtk_widget_grab_focus (priv->msg_body);
3200 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3202 GtkTextIter *match_start,
3203 GtkTextIter *match_end)
3205 GtkTextIter end_iter;
3206 gchar *str_casefold;
3209 gchar *range_casefold;
3212 gboolean result = FALSE;
3219 gtk_text_iter_forward_to_end (&end_iter);
3221 str_casefold = g_utf8_casefold (str, -1);
3222 str_chars_n = strlen (str);
3224 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3225 range_casefold = g_utf8_casefold (range_text, -1);
3226 range_chars_n = strlen (range_casefold);
3228 if (range_chars_n < str_chars_n) {
3229 g_free (str_casefold);
3230 g_free (range_text);
3231 g_free (range_casefold);
3235 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3236 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3237 if (!g_utf8_collate (range_subtext, str_casefold)) {
3238 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3240 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3241 match_start, match_end, NULL);
3242 g_free (found_text);
3244 g_free (range_subtext);
3248 g_free (str_casefold);
3249 g_free (range_text);
3250 g_free (range_casefold);
3257 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3258 ModestMsgEditWindow *window)
3260 gchar *current_search = NULL;
3261 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3263 GtkTextIter selection_start, selection_end;
3264 GtkTextIter match_start, match_end;
3265 gboolean continue_search = FALSE;
3267 if (message_is_empty (window)) {
3268 g_free (priv->last_search);
3269 priv->last_search = NULL;
3270 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3274 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3275 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3276 g_free (current_search);
3277 g_free (priv->last_search);
3278 priv->last_search = NULL;
3279 /* Information banner about empty search */
3280 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3284 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3285 continue_search = TRUE;
3287 g_free (priv->last_search);
3288 priv->last_search = g_strdup (current_search);
3291 if (continue_search) {
3292 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3293 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3294 &match_start, &match_end);
3296 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3298 GtkTextIter buffer_start;
3299 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3300 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3301 &match_start, &match_end);
3303 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3306 /* Mark as selected the string found in search */
3308 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3309 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3311 g_free (priv->last_search);
3312 priv->last_search = NULL;
3314 g_free (current_search);
3318 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3319 ModestMsgEditWindow *window)
3321 GtkToggleAction *toggle;
3322 ModestWindowPrivate *parent_priv;
3323 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3325 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3326 gtk_toggle_action_set_active (toggle, FALSE);
3330 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3332 ModestMsgEditWindowPrivate *priv;
3334 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3339 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3342 ModestMsgEditWindowPrivate *priv;
3344 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3350 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3353 ModestMsgEditWindowPrivate *priv;
3354 TnyHeader *header = NULL;
3356 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3357 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3359 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3360 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3362 if (priv->draft_msg != NULL) {
3363 g_object_unref (priv->draft_msg);
3366 if (draft != NULL) {
3367 g_object_ref (draft);
3368 header = tny_msg_get_header (draft);
3369 if (priv->msg_uid) {
3370 g_free (priv->msg_uid);
3371 priv->msg_uid = NULL;
3373 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3374 if (GTK_WIDGET_REALIZED (window))
3375 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3378 priv->draft_msg = draft;
3382 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3383 GtkTextIter *start, GtkTextIter *end,
3386 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3387 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3390 if (tag == NULL+13) return;
3391 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3392 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3393 replace_with_images (window, priv->images);
3398 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3401 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3403 g_return_if_fail (TNY_IS_MIME_PART (part));
3404 tny_list_prepend (priv->attachments, (GObject *) part);
3405 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3406 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3407 gtk_widget_show_all (priv->attachments_caption);
3408 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3412 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3414 ModestMsgEditWindowPrivate *priv;
3416 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3417 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3419 return priv->msg_uid;
3423 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3424 ModestMsgEditWindowWidgetType widget_type)
3426 ModestMsgEditWindowPrivate *priv;
3428 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3429 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3431 switch (widget_type) {
3432 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3433 return priv->msg_body;
3435 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3436 return priv->to_field;
3438 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3439 return priv->cc_field;
3441 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3442 return priv->bcc_field;
3444 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3445 return priv->subject_field;
3447 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3448 return priv->attachments_view;
3456 remove_tags (WPTextBuffer *buffer)
3458 GtkTextIter start, end;
3460 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3461 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3463 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3467 on_account_removed (TnyAccountStore *account_store,
3468 TnyAccount *account,
3471 /* Do nothing if it's a store account, because we use the
3472 transport to send the messages */
3473 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3474 const gchar *parent_acc = NULL;
3475 const gchar *our_acc = NULL;
3477 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3478 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3479 /* Close this window if I'm showing a message of the removed account */
3480 if (strcmp (parent_acc, our_acc) == 0)
3481 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3486 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3488 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3490 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3496 set_zoom_do_nothing (ModestWindow *window,
3502 get_zoom_do_nothing (ModestWindow *window)