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_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
108 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
109 static void subject_field_insert_text (GtkEditable *editable,
111 gint new_text_length,
113 ModestMsgEditWindow *window);
114 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
116 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
118 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
121 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
122 GdkEventWindowState *event,
124 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
125 ModestRecptEditor *editor);
126 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
127 ModestMsgEditWindow *window);
129 /* ModestWindow methods implementation */
130 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
131 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
132 gboolean show_toolbar);
133 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
135 ModestMsgEditWindow *window);
136 static void subject_field_move_cursor (GtkEntry *entry,
137 GtkMovementStep step,
141 static void update_window_title (ModestMsgEditWindow *window);
144 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
145 ModestMsgEditWindow *window);
146 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
147 ModestMsgEditWindow *window);
148 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
150 GtkTextIter *match_start,
151 GtkTextIter *match_end);
153 static void remove_tags (WPTextBuffer *buffer);
155 static void on_account_removed (TnyAccountStore *account_store,
159 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
161 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
163 static gdouble get_zoom_do_nothing (ModestWindow *window);
165 static void init_window (ModestMsgEditWindow *obj);
167 static void DEBUG_BUFFER (WPTextBuffer *buffer)
171 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
173 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
174 while (!gtk_text_iter_is_end (&iter)) {
175 GString *output = g_string_new ("");
176 GSList *toggled_tags;
179 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
180 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
181 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
182 GtkTextTag *tag = (GtkTextTag *) node->data;
184 g_object_get (G_OBJECT (tag), "name", &name, NULL);
185 output = g_string_append (output, name);
186 g_string_append (output, " ");
188 output = g_string_append (output, "] OPENED [ ");
189 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
190 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
191 GtkTextTag *tag = (GtkTextTag *) node->data;
193 g_object_get (G_OBJECT (tag), "name", &name, NULL);
194 output = g_string_append (output, name);
195 g_string_append (output, " ");
197 output = g_string_append (output, "]\n");
198 g_message ("%s", output->str);
199 g_string_free (output, TRUE);
200 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
202 g_message ("END BUFFER");
207 /* static gboolean */
208 /* on_key_pressed (GtkWidget *self, */
209 /* GdkEventKey *event, */
210 /* gpointer user_data); */
212 /* list my signals */
219 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
220 struct _ModestMsgEditWindowPrivate {
222 GtkWidget *header_box;
224 ModestPairList *from_field_protos;
225 GtkWidget *from_field;
229 GtkWidget *bcc_field;
230 GtkWidget *subject_field;
231 GtkWidget *attachments_view;
232 GtkWidget *priority_icon;
233 GtkWidget *add_attachment_button;
235 GtkWidget *cc_caption;
236 GtkWidget *bcc_caption;
237 gboolean update_caption_visibility;
238 GtkWidget *attachments_caption;
240 GtkTextBuffer *text_buffer;
242 GtkWidget *font_size_toolitem;
243 GtkWidget *font_face_toolitem;
244 GtkWidget *font_color_button;
245 GSList *font_items_group;
246 GtkWidget *font_tool_button_label;
247 GSList *size_items_group;
248 GtkWidget *size_tool_button_label;
250 GtkWidget *find_toolbar;
254 GtkWidget *scroll_area;
255 gint last_vadj_upper;
261 TnyHeaderFlags priority_flags;
263 gboolean can_undo, can_redo;
264 gulong clipboard_change_handler_id;
265 gulong default_clipboard_change_handler_id;
266 gulong account_removed_handler_id;
267 gchar *clipboard_text;
276 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
277 MODEST_TYPE_MSG_EDIT_WINDOW, \
278 ModestMsgEditWindowPrivate))
280 static GtkWindowClass *parent_class = NULL;
282 /* uncomment the following if you have defined any signals */
283 /* static guint signals[LAST_SIGNAL] = {0}; */
286 modest_msg_edit_window_get_type (void)
288 static GType my_type = 0;
290 static const GTypeInfo my_info = {
291 sizeof(ModestMsgEditWindowClass),
292 NULL, /* base init */
293 NULL, /* base finalize */
294 (GClassInitFunc) modest_msg_edit_window_class_init,
295 NULL, /* class finalize */
296 NULL, /* class data */
297 sizeof(ModestMsgEditWindow),
299 (GInstanceInitFunc) modest_msg_edit_window_init,
302 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
303 "ModestMsgEditWindow",
311 save_state (ModestWindow *self)
313 modest_widget_memory_save (modest_runtime_get_conf(),
314 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
319 restore_settings (ModestMsgEditWindow *self)
321 ModestConf *conf = NULL;
323 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
325 conf = modest_runtime_get_conf ();
326 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
327 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
328 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
329 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
330 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
331 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
332 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
333 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
335 /* set initial state of cc and bcc */
336 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
337 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
338 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
339 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
340 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
341 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
343 /* Dim at start clipboard actions */
344 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
345 gtk_action_set_sensitive (action, FALSE);
346 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
347 gtk_action_set_sensitive (action, FALSE);
348 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
349 gtk_action_set_sensitive (action, FALSE);
351 modest_widget_memory_restore (conf,
352 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
357 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
359 GObjectClass *gobject_class;
360 ModestWindowClass *modest_window_class;
361 gobject_class = (GObjectClass*) klass;
362 modest_window_class = (ModestWindowClass*) klass;
364 parent_class = g_type_class_peek_parent (klass);
365 gobject_class->finalize = modest_msg_edit_window_finalize;
367 modest_window_class->set_zoom_func = set_zoom_do_nothing;
368 modest_window_class->get_zoom_func = get_zoom_do_nothing;
369 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
370 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
371 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
372 modest_window_class->save_state_func = save_state;
373 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
375 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
379 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
381 ModestMsgEditWindowPrivate *priv;
382 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
384 priv->msg_body = NULL;
385 priv->from_field = NULL;
386 priv->to_field = NULL;
387 priv->cc_field = NULL;
388 priv->bcc_field = NULL;
389 priv->subject_field = NULL;
390 priv->attachments = NULL;
394 priv->cc_caption = NULL;
395 priv->bcc_caption = NULL;
396 priv->update_caption_visibility = FALSE;
398 priv->priority_flags = 0;
400 priv->find_toolbar = NULL;
401 priv->last_search = NULL;
403 priv->draft_msg = NULL;
404 priv->outbox_msg = NULL;
405 priv->msg_uid = NULL;
407 priv->can_undo = FALSE;
408 priv->can_redo = FALSE;
409 priv->clipboard_change_handler_id = 0;
410 priv->default_clipboard_change_handler_id = 0;
411 priv->account_removed_handler_id = 0;
412 priv->clipboard_text = NULL;
415 priv->last_vadj_upper = 0;
417 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
418 GTK_WINDOW(obj),"applications_email_editor");
420 if (!is_wp_text_buffer_started) {
421 is_wp_text_buffer_started = TRUE;
422 wp_text_buffer_library_init ();
427 hildon_program_add_window (hildon_program_get_instance(),
432 /* FIXME: this is a dup from the one in gtk/ */
435 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
437 static ModestPairList*
438 get_transports (void)
440 GSList *transports = NULL;
442 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
443 GSList *accounts = modest_account_mgr_account_names (account_mgr,
444 TRUE /* only enabled accounts. */);
446 GSList *cursor = accounts;
448 gchar *account_name = cursor->data;
449 gchar *from_string = NULL;
451 from_string = modest_account_mgr_get_from_string (account_mgr,
455 if (from_string && account_name) {
456 gchar *name = account_name;
457 ModestPair *pair = modest_pair_new ((gpointer) name,
458 (gpointer) from_string , TRUE);
459 transports = g_slist_prepend (transports, pair);
462 cursor = cursor->next;
464 g_slist_free (accounts); /* only free the accounts, not the elements,
465 * because they are used in the pairlist */
469 void vadj_changed (GtkAdjustment *adj,
470 ModestMsgEditWindow *window)
472 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
474 GdkRectangle rectangle, cursor_rectangle;
475 GtkTextIter position;
479 /* We detect if cursor is visible using the full height, not only the center. This
481 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
482 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
484 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
485 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
487 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
488 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
490 if (gtk_widget_is_focus (priv->msg_body) &&
492 if (priv->last_vadj_upper != adj->upper) {
495 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
496 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
497 insert, 0.1, FALSE, 0.0, 0.0);
500 priv->last_vadj_upper = adj->upper;
505 connect_signals (ModestMsgEditWindow *obj)
507 ModestMsgEditWindowPrivate *priv;
509 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
511 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
512 G_CALLBACK (text_buffer_refresh_attributes), obj);
513 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
514 G_CALLBACK (text_buffer_can_undo), obj);
515 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
516 G_CALLBACK (text_buffer_can_redo), obj);
517 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
518 G_CALLBACK (body_changed), obj);
519 g_signal_connect (G_OBJECT (obj), "window-state-event",
520 G_CALLBACK (modest_msg_edit_window_window_state_event),
522 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
523 G_CALLBACK (text_buffer_apply_tag), obj);
524 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
525 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
526 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
527 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
528 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
529 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
531 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
532 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
534 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
535 G_CALLBACK (msg_body_focus), obj);
536 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
537 G_CALLBACK (msg_body_focus), obj);
538 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
539 "changed", G_CALLBACK (recpt_field_changed), obj);
540 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
541 "changed", G_CALLBACK (recpt_field_changed), obj);
542 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
543 "changed", G_CALLBACK (recpt_field_changed), obj);
544 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
545 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
546 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
548 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
549 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
551 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
553 G_CALLBACK (vadj_changed),
556 priv->clipboard_change_handler_id =
557 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
558 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
559 priv->default_clipboard_change_handler_id =
560 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
561 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
566 menubar_to_menu (GtkUIManager *ui_manager)
568 GtkWidget *main_menu;
570 /* Get the menubar from the UI manager */
571 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
577 init_window (ModestMsgEditWindow *obj)
579 GtkWidget *from_caption, *to_caption, *subject_caption;
580 GtkWidget *main_vbox;
581 ModestMsgEditWindowPrivate *priv;
582 GtkActionGroup *action_group;
583 ModestWindowPrivate *parent_priv;
584 GdkPixbuf *window_icon = NULL;
585 GError *error = NULL;
587 GtkSizeGroup *size_group;
589 GtkWidget *subject_box;
590 GtkWidget *attachment_icon;
591 GtkWidget *window_box;
592 #if (GTK_MINOR_VERSION >= 10)
593 GdkAtom deserialize_type;
595 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
596 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
598 parent_priv->ui_manager = gtk_ui_manager_new();
599 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
600 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
602 /* Add common actions */
603 gtk_action_group_add_actions (action_group,
604 modest_msg_edit_action_entries,
605 G_N_ELEMENTS (modest_msg_edit_action_entries),
607 gtk_action_group_add_toggle_actions (action_group,
608 modest_msg_edit_toggle_action_entries,
609 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
611 gtk_action_group_add_radio_actions (action_group,
612 modest_msg_edit_alignment_radio_action_entries,
613 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
615 G_CALLBACK (modest_ui_actions_on_change_justify),
617 gtk_action_group_add_radio_actions (action_group,
618 modest_msg_edit_priority_action_entries,
619 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
621 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
623 gtk_action_group_add_radio_actions (action_group,
624 modest_msg_edit_file_format_action_entries,
625 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
626 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
627 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
629 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
630 g_object_unref (action_group);
632 /* Load the UI definition */
633 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
636 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
637 g_clear_error (&error);
640 /* Add accelerators */
641 gtk_window_add_accel_group (GTK_WINDOW (obj),
642 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
644 parent_priv->menubar = NULL;
646 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
648 /* Note: This ModestPairList* must exist for as long as the combo
649 * that uses it, because the ModestComboBox uses the ID opaquely,
650 * so it can't know how to manage its memory. */
651 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
653 priv->to_field = modest_recpt_editor_new ();
654 priv->cc_field = modest_recpt_editor_new ();
655 priv->bcc_field = modest_recpt_editor_new ();
656 subject_box = gtk_hbox_new (FALSE, 0);
657 priv->priority_icon = gtk_image_new ();
658 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
659 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
660 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
661 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
662 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
663 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
664 priv->add_attachment_button = gtk_button_new ();
665 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
666 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
667 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
668 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
669 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
670 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
671 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
672 priv->attachments_view = modest_attachments_view_new (NULL);
674 priv->header_box = gtk_vbox_new (FALSE, 0);
676 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
677 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
678 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
679 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
680 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
681 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
682 g_object_unref (size_group);
684 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
685 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
686 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
687 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
688 gtk_size_group_add_widget (size_group, priv->subject_field);
689 gtk_size_group_add_widget (size_group, priv->attachments_view);
690 g_object_unref (size_group);
692 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
694 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
695 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
696 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
697 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
698 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
701 priv->msg_body = wp_text_view_new ();
702 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
703 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
704 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
705 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
706 #if (GTK_MINOR_VERSION >= 10)
707 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
708 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
710 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
711 deserialize_type, TRUE);
713 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
715 priv->find_toolbar = hildon_find_toolbar_new (NULL);
716 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
718 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
720 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
721 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
722 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
723 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
725 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
727 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
728 frame = gtk_frame_new (NULL);
729 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
731 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
732 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
733 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
735 G_CALLBACK (vadj_changed),
737 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
739 window_box = gtk_vbox_new (FALSE, 0);
740 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
741 gtk_container_add (GTK_CONTAINER(obj), window_box);
742 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
743 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
745 /* Set window icon */
746 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
748 /* scale the icon, because it won't be shown unless it's
749 * 64 x 54 -- hildon quirk. this looks a bit ugly now,
750 * so waiting for correctly sized icons, then this scaling
751 * code can disappear -- djcb
754 gdk_pixbuf_scale_simple (window_icon, 64, 54, GDK_INTERP_BILINEAR);
756 g_warning ("setting scaled icon");
757 gtk_window_set_icon (GTK_WINDOW (obj), scaled);
758 g_object_unref (scaled);
760 g_object_unref (window_icon);
765 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
767 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
769 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
770 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
771 priv->clipboard_change_handler_id))
772 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
773 priv->clipboard_change_handler_id);
774 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
775 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
776 priv->default_clipboard_change_handler_id))
777 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
778 priv->default_clipboard_change_handler_id);
780 if (priv->account_removed_handler_id &&
781 g_signal_handler_is_connected (modest_runtime_get_account_store (),
782 priv->account_removed_handler_id))
783 g_signal_handler_disconnect(modest_runtime_get_account_store (),
784 priv->account_removed_handler_id);
788 modest_msg_edit_window_finalize (GObject *obj)
790 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
792 /* Sanity check: shouldn't be needed, the window mgr should
793 call this function before */
794 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
796 if (priv->clipboard_text != NULL) {
797 g_free (priv->clipboard_text);
798 priv->clipboard_text = NULL;
801 if (priv->draft_msg != NULL) {
802 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
803 if (TNY_IS_HEADER (header)) {
804 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
805 modest_window_mgr_unregister_header (mgr, header);
807 g_object_unref (priv->draft_msg);
808 priv->draft_msg = NULL;
810 if (priv->outbox_msg != NULL) {
811 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
812 if (TNY_IS_HEADER (header)) {
813 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
814 modest_window_mgr_unregister_header (mgr, header);
816 g_object_unref (priv->outbox_msg);
817 priv->outbox_msg = NULL;
819 g_free (priv->msg_uid);
820 g_free (priv->last_search);
821 g_slist_free (priv->font_items_group);
822 g_slist_free (priv->size_items_group);
823 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
824 g_list_free (priv->attachments);
825 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
826 g_list_free (priv->images);
828 /* This had to stay alive for as long as the combobox that used it: */
829 modest_pair_list_free (priv->from_field_protos);
831 G_OBJECT_CLASS(parent_class)->finalize (obj);
835 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
837 GdkPixbufLoader *loader;
840 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
845 tny_stream_reset (TNY_STREAM (stream));
846 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
847 unsigned char read_buffer[128];
849 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
850 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
854 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
855 g_object_ref (pixbuf);
856 gdk_pixbuf_loader_close (loader, NULL);
857 g_object_unref (loader);
859 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
860 GdkPixbuf *new_pixbuf;
862 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
863 gdk_pixbuf_get_width (pixbuf);
864 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
865 g_object_unref (pixbuf);
873 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
875 ModestMsgEditWindowPrivate *priv;
878 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
880 for (node = attachments; node != NULL; node = g_list_next (node)) {
881 TnyMimePart *part = (TnyMimePart *) node->data;
882 const gchar *cid = tny_mime_part_get_content_id (part);
883 const gchar *mime_type = tny_mime_part_get_content_type (part);
884 if ((cid != NULL)&&(mime_type != NULL)) {
885 TnyStream *stream = tny_mime_part_get_stream (part);
886 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
887 g_object_unref (stream);
889 if (pixbuf != NULL) {
890 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
891 g_object_unref (pixbuf);
898 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
900 TnyMimePart *parent = NULL;
901 const gchar *content_type = NULL;
902 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
904 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
906 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
907 parent = g_object_ref (msg);
908 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
909 TnyList *parts = TNY_LIST (tny_simple_list_new ());
912 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
913 iter = tny_list_create_iterator (parts);
914 while (!tny_iterator_is_done (iter)) {
916 part = TNY_MIME_PART (tny_iterator_get_current (iter));
917 content_type = tny_mime_part_get_content_type (part);
918 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
922 g_object_unref (part);
924 tny_iterator_next (iter);
926 g_object_unref (iter);
927 g_object_unref (parts);
930 if (parent != NULL) {
931 TnyList *parts = TNY_LIST (tny_simple_list_new ());
934 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
935 iter = tny_list_create_iterator (parts);
936 while (!tny_iterator_is_done (iter)) {
938 part = TNY_MIME_PART (tny_iterator_get_current (iter));
939 content_type = tny_mime_part_get_content_type (part);
940 if (content_type && g_str_has_prefix (content_type, "image/")) {
941 priv->images = g_list_prepend (priv->images, part);
943 g_object_unref (part);
945 tny_iterator_next (iter);
947 g_object_unref (iter);
948 g_object_unref (parts);
949 g_object_unref (parent);
954 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
957 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
959 for (node = attachments; node != NULL; node = g_list_next (node)) {
960 TnyMimePart *part = (TnyMimePart *) node->data;
961 const gchar *cid = tny_mime_part_get_content_id (part);
963 char *invalid = NULL;
964 gint int_cid = strtol (cid, &invalid, 10);
965 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
966 priv->last_cid = int_cid;
974 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
977 const gchar *to, *cc, *bcc, *subject;
979 ModestMsgEditWindowPrivate *priv;
981 TnyHeaderFlags priority_flags;
982 TnyFolder *msg_folder;
983 gboolean is_html = FALSE;
985 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
986 g_return_if_fail (TNY_IS_MSG (msg));
988 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
990 header = tny_msg_get_header (msg);
991 to = tny_header_get_to (header);
992 cc = tny_header_get_cc (header);
993 bcc = tny_header_get_bcc (header);
994 subject = tny_header_get_subject (header);
995 priority_flags = tny_header_get_priority (header);
998 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
1000 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1001 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1002 gtk_widget_show (priv->cc_caption);
1003 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1004 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1005 gtk_widget_hide (priv->cc_caption);
1008 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1009 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1010 gtk_widget_show (priv->bcc_caption);
1011 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1012 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1013 gtk_widget_hide (priv->bcc_caption);
1016 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1017 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1020 update_window_title (self);
1022 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1023 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1025 if ((body == NULL)||(body[0] == '\0')) {
1027 body = modest_text_utils_convert_to_html ("");
1030 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1031 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1034 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1037 /* Add attachments to the view */
1038 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1039 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1040 if (priv->attachments == NULL) {
1041 gtk_widget_hide (priv->attachments_caption);
1043 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1044 gtk_widget_show_all (priv->attachments_caption);
1046 get_related_images (self, msg);
1047 update_last_cid (self, priv->attachments);
1048 update_last_cid (self, priv->images);
1049 replace_with_images (self, priv->images);
1051 if (preserve_is_rich && !is_html) {
1052 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1053 /* Get the default format required from configuration */
1054 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1055 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1058 /* Set the default focus depending on having already a To: field or not */
1059 if ((!to)||(*to == '\0')) {
1060 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1062 gtk_widget_grab_focus (priv->msg_body);
1065 /* TODO: lower priority, select in the From: combo to the
1066 value that comes from msg <- not sure, should it be
1069 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1071 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1072 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1074 modest_msg_edit_window_reset_modified (self);
1076 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1077 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1078 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1080 if (priv->msg_uid) {
1081 g_free (priv->msg_uid);
1082 priv->msg_uid = NULL;
1085 /* we should set a reference to the incoming message if it is a draft */
1086 msg_folder = tny_msg_get_folder (msg);
1088 if (modest_tny_folder_is_local_folder (msg_folder)) {
1089 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1090 if (type == TNY_FOLDER_TYPE_INVALID)
1091 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1093 if (type == TNY_FOLDER_TYPE_DRAFTS)
1094 priv->draft_msg = g_object_ref(msg);
1095 if (type == TNY_FOLDER_TYPE_OUTBOX)
1096 priv->outbox_msg = g_object_ref(msg);
1097 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1099 g_object_unref (msg_folder);
1104 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1107 GList *item_children, *node;
1108 GtkWidget *bin_child;
1110 bin_child = gtk_bin_get_child (GTK_BIN(item));
1112 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1114 for (node = item_children; node != NULL; node = g_list_next (node)) {
1115 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1116 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1119 g_list_free (item_children);
1123 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1126 GList *item_children, *node;
1128 box = gtk_bin_get_child (GTK_BIN (item));
1129 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1130 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1132 for (node = item_children; node != NULL; node = g_list_next (node)) {
1133 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1134 if (GTK_IS_TOGGLE_BUTTON (node->data))
1135 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1136 else if (GTK_IS_BUTTON (node->data))
1137 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1139 g_list_free (item_children);
1144 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1146 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1147 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1148 GtkWidget *placeholder;
1149 GtkWidget *tool_item;
1154 GtkWidget *sizes_menu;
1155 GtkWidget *fonts_menu;
1156 GSList *radio_group = NULL;
1157 GSList *node = NULL;
1161 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1162 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1164 /* Font color placeholder */
1165 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1166 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1169 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1170 priv->font_color_button = hildon_color_button_new ();
1171 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1172 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1173 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1174 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1175 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1176 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1177 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1179 G_CALLBACK (modest_msg_edit_window_color_button_change),
1182 /* Font size and face placeholder */
1183 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1184 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1186 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1187 priv->size_tool_button_label = gtk_label_new (NULL);
1188 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1189 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1190 size_text,"</span>", NULL);
1191 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1193 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1194 sizes_menu = gtk_menu_new ();
1195 priv->size_items_group = NULL;
1197 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1198 GtkWidget *size_menu_item;
1200 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1201 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1202 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1203 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1204 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1205 gtk_widget_show (size_menu_item);
1207 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1211 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1212 GtkWidget *item = (GtkWidget *) node->data;
1213 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1217 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1218 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1219 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1220 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1221 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1222 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1223 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1224 priv->font_size_toolitem = tool_item;
1227 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1228 priv->font_tool_button_label = gtk_label_new (NULL);
1229 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1230 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1232 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1233 fonts_menu = gtk_menu_new ();
1234 priv->font_items_group = NULL;
1236 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1237 GtkWidget *font_menu_item;
1238 GtkWidget *child_label;
1240 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1241 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1242 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1243 wp_get_font_name (font_index), "</span>", NULL);
1244 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1247 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1248 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1249 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1250 gtk_widget_show (font_menu_item);
1252 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1255 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1256 GtkWidget *item = (GtkWidget *) node->data;
1257 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1260 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1261 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1262 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1263 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1264 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1265 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1266 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1267 priv->font_face_toolitem = tool_item;
1269 /* Set expand and homogeneous for remaining items */
1270 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1271 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1272 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1273 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1274 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1275 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1276 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1277 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1278 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1280 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1281 will not show the tool items added to the placeholders) */
1282 gtk_widget_show_all (parent_priv->toolbar);
1284 /* Set the no show all *after* showing all items. We do not
1285 want the toolbar to be shown with a show all because it
1286 could go agains the gconf setting regarding showing or not
1287 the toolbar of the editor window */
1288 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1294 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1297 ModestWindowPrivate *parent_priv;
1298 ModestMsgEditWindowPrivate *priv;
1299 ModestPair *account_pair = NULL;
1300 ModestDimmingRulesGroup *menu_rules_group = NULL;
1301 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1302 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1303 ModestWindowMgr *mgr = NULL;
1305 g_return_val_if_fail (msg, NULL);
1306 g_return_val_if_fail (account_name, NULL);
1308 mgr = modest_runtime_get_window_mgr ();
1310 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1312 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1313 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1315 /* Menubar. Update the state of some toggles */
1316 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1317 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1318 priv->from_field_protos = get_transports ();
1319 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1320 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1321 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1324 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1326 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1328 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1330 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1331 if (account_pair != NULL)
1332 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1334 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1335 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1336 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1337 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1338 /* Add common dimming rules */
1339 modest_dimming_rules_group_add_rules (menu_rules_group,
1340 modest_msg_edit_window_menu_dimming_entries,
1341 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1342 MODEST_WINDOW (obj));
1343 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1344 modest_msg_edit_window_toolbar_dimming_entries,
1345 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1346 MODEST_WINDOW (obj));
1347 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1348 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1349 MODEST_WINDOW (obj));
1350 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1351 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1352 MODEST_WINDOW (obj));
1353 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1354 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1355 MODEST_WINDOW (obj));
1356 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1357 modest_msg_edit_window_clipboard_dimming_entries,
1358 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1359 MODEST_WINDOW (obj));
1360 /* Insert dimming rules group for this window */
1361 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1362 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1363 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1364 /* Checks the dimming rules */
1365 g_object_unref (menu_rules_group);
1366 g_object_unref (toolbar_rules_group);
1367 g_object_unref (clipboard_rules_group);
1369 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1371 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1373 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1374 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1375 priv->update_caption_visibility = TRUE;
1377 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1379 /* Track account-removed signal, this window should be closed
1380 in the case we're creating a mail associated to the account
1382 priv->account_removed_handler_id =
1383 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1385 G_CALLBACK(on_account_removed),
1388 return (ModestWindow*) obj;
1392 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1394 GString **string_buffer = (GString **) user_data;
1396 *string_buffer = g_string_append (*string_buffer, buffer);
1402 * @result: A new string which should be freed with g_free().
1405 get_formatted_data (ModestMsgEditWindow *edit_window)
1407 ModestMsgEditWindowPrivate *priv;
1408 GString *string_buffer = g_string_new ("");
1410 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1412 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1414 return g_string_free (string_buffer, FALSE);
1419 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1422 const gchar *account_name;
1423 ModestMsgEditWindowPrivate *priv;
1425 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1427 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1429 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1430 g_return_val_if_fail (account_name, NULL);
1433 /* don't free these (except from) */
1434 data = g_slice_new0 (MsgData);
1435 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1437 data->account_name = g_strdup (account_name);
1438 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1439 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1440 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1441 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1442 if (priv->draft_msg) {
1443 data->draft_msg = g_object_ref (priv->draft_msg);
1444 } else if (priv->outbox_msg) {
1445 data->draft_msg = g_object_ref (priv->outbox_msg);
1447 data->draft_msg = NULL;
1450 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1452 gtk_text_buffer_get_bounds (buf, &b, &e);
1453 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1455 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1456 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1458 data->html_body = NULL;
1460 /* deep-copy the data */
1461 GList *cursor = priv->attachments;
1462 data->attachments = NULL;
1464 if (!(TNY_IS_MIME_PART(cursor->data))) {
1465 g_warning ("strange data in attachment list");
1466 cursor = g_list_next (cursor);
1469 data->attachments = g_list_append (data->attachments,
1470 g_object_ref (cursor->data));
1471 cursor = g_list_next (cursor);
1474 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1475 cursor = priv->images;
1476 data->images = NULL;
1479 if (!(TNY_IS_MIME_PART(cursor->data))) {
1480 g_warning ("strange data in attachment list");
1481 cursor = g_list_next (cursor);
1484 cid = tny_mime_part_get_content_id (cursor->data);
1486 gchar *image_tag_id;
1487 GtkTextTag *image_tag;
1489 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1490 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1491 g_free (image_tag_id);
1493 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1495 ((gtk_text_iter_has_tag (&iter, image_tag))||
1496 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1497 data->images = g_list_append (data->images,
1498 g_object_ref (cursor->data));
1500 cursor = g_list_next (cursor);
1503 data->priority_flags = priv->priority_flags;
1510 unref_gobject (GObject *obj, gpointer data)
1512 if (!G_IS_OBJECT(obj))
1514 g_object_unref (obj);
1518 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1521 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1529 g_free (data->from);
1530 g_free (data->subject);
1531 g_free (data->plain_body);
1532 g_free (data->html_body);
1533 g_free (data->account_name);
1535 if (data->draft_msg != NULL) {
1536 g_object_unref (data->draft_msg);
1537 data->draft_msg = NULL;
1540 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1541 g_list_free (data->attachments);
1542 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1543 g_list_free (data->images);
1545 g_slice_free (MsgData, data);
1549 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1552 ModestMsgEditWindowPrivate *priv = NULL;
1553 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1555 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1557 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1559 return MODEST_MSG_EDIT_FORMAT_HTML;
1561 return MODEST_MSG_EDIT_FORMAT_TEXT;
1565 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1566 ModestMsgEditFormat format)
1568 ModestMsgEditWindowPrivate *priv;
1570 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1571 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1574 case MODEST_MSG_EDIT_FORMAT_HTML:
1575 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1577 case MODEST_MSG_EDIT_FORMAT_TEXT:
1578 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1581 g_return_if_reached ();
1585 ModestMsgEditFormatState *
1586 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1588 ModestMsgEditFormatState *format_state = NULL;
1589 ModestMsgEditWindowPrivate *priv;
1590 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1592 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1593 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1595 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1597 format_state = g_new0 (ModestMsgEditFormatState, 1);
1598 format_state->bold = buffer_format->bold&0x1;
1599 format_state->italics = buffer_format->italic&0x1;
1600 format_state->bullet = buffer_format->bullet&0x1;
1601 format_state->color = buffer_format->color;
1602 format_state->font_size = buffer_format->font_size;
1603 format_state->font_family = wp_get_font_name (buffer_format->font);
1604 format_state->justification = buffer_format->justification;
1605 g_free (buffer_format);
1607 return format_state;
1612 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1613 const ModestMsgEditFormatState *format_state)
1615 ModestMsgEditWindowPrivate *priv;
1616 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1617 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1618 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1619 g_return_if_fail (format_state != NULL);
1621 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1622 gtk_widget_grab_focus (priv->msg_body);
1623 buffer_format->bold = (format_state->bold != FALSE);
1624 buffer_format->italic = (format_state->italics != FALSE);
1625 buffer_format->color = format_state->color;
1626 buffer_format->font_size = format_state->font_size;
1627 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1628 buffer_format->justification = format_state->justification;
1629 buffer_format->bullet = format_state->bullet;
1631 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1633 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1634 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1635 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1636 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1637 buffer_format->cs.font = (buffer_format->font != current_format->font);
1638 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1639 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1641 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1642 if (buffer_format->cs.bold) {
1643 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1644 GINT_TO_POINTER (buffer_format->bold&0x1));
1646 if (buffer_format->cs.italic) {
1647 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1648 GINT_TO_POINTER (buffer_format->italic&0x1));
1650 if (buffer_format->cs.color) {
1651 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1652 GINT_TO_POINTER (&(buffer_format->color)));
1654 if (buffer_format->cs.font_size) {
1655 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1656 GINT_TO_POINTER (buffer_format->font_size));
1658 if (buffer_format->cs.justification) {
1659 switch (buffer_format->justification) {
1660 case GTK_JUSTIFY_LEFT:
1661 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1662 GINT_TO_POINTER(TRUE));
1664 case GTK_JUSTIFY_CENTER:
1665 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1666 GINT_TO_POINTER(TRUE));
1668 case GTK_JUSTIFY_RIGHT:
1669 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1670 GINT_TO_POINTER(TRUE));
1677 if (buffer_format->cs.font) {
1678 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1679 GINT_TO_POINTER (buffer_format->font));
1681 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1682 if (buffer_format->cs.bullet) {
1683 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1684 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1686 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1688 g_free (current_format);
1693 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1695 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1697 ModestWindowPrivate *parent_priv;
1698 ModestMsgEditWindowPrivate *priv;
1699 GtkWidget *new_size_menuitem;
1700 GtkWidget *new_font_menuitem;
1702 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1703 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1705 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1706 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1707 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1708 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1710 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1711 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1712 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1715 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1717 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1718 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1720 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1721 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1723 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1724 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1726 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1727 G_CALLBACK (modest_msg_edit_window_color_button_change),
1729 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1730 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1731 G_CALLBACK (modest_msg_edit_window_color_button_change),
1734 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1735 buffer_format->font_size))->data);
1736 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1740 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1741 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1742 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1744 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1745 G_CALLBACK (modest_msg_edit_window_size_change),
1747 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1748 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1749 G_CALLBACK (modest_msg_edit_window_size_change),
1753 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1754 buffer_format->font))->data);
1755 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1759 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1760 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1761 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1763 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1764 G_CALLBACK (modest_msg_edit_window_font_change),
1766 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1767 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1768 G_CALLBACK (modest_msg_edit_window_font_change),
1772 g_free (buffer_format);
1776 #ifdef MODEST_HILDON_VERSION_0
1778 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1781 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1782 ModestMsgEditWindowPrivate *priv;
1783 GtkWidget *dialog = NULL;
1785 GdkColor *new_color = NULL;
1787 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1788 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1790 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1791 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1792 g_free (buffer_format);
1794 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1795 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1796 if (new_color != NULL) {
1797 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1798 (gpointer) new_color);
1801 gtk_widget_destroy (dialog);
1806 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1809 ModestMsgEditWindowPrivate *priv;
1810 GtkWidget *dialog = NULL;
1812 GdkColor *old_color = NULL;
1813 const GdkColor *new_color = NULL;
1815 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1816 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1818 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1819 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1821 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1822 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1823 if (new_color != NULL)
1824 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1826 gtk_widget_destroy (dialog);
1832 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1835 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1836 ModestMsgEditWindowPrivate *priv;
1837 GtkWidget *dialog = NULL;
1839 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1840 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1842 dialog = hildon_color_chooser_new ();
1843 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1844 g_free (buffer_format);
1846 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1848 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1849 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1852 gtk_widget_destroy (dialog);
1857 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1860 ModestMsgEditWindowPrivate *priv;
1861 GtkWidget *dialog = NULL;
1862 GdkColor *old_color = NULL;
1864 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1865 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1867 dialog = hildon_color_chooser_new ();
1868 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1870 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1872 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1873 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1875 gtk_widget_destroy (dialog);
1878 #endif /*!MODEST_HILDON_VERSION_0*/
1882 static TnyStream* create_stream_for_uri (const gchar* uri)
1887 TnyStream *result = NULL;
1889 GnomeVFSHandle *handle = NULL;
1890 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1891 if (test == GNOME_VFS_OK) {
1892 /* Create the tinymail stream: */
1893 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1894 result = TNY_STREAM (tny_vfs_stream_new (handle));
1901 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1904 ModestMsgEditWindowPrivate *priv;
1905 GtkWidget *dialog = NULL;
1907 GSList *uris = NULL;
1908 GSList *uri_node = NULL;
1910 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1912 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1913 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1914 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1916 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1918 response = gtk_dialog_run (GTK_DIALOG (dialog));
1920 case GTK_RESPONSE_OK:
1921 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1926 gtk_widget_destroy (dialog);
1928 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1930 GnomeVFSHandle *handle = NULL;
1931 GnomeVFSResult result;
1932 GtkTextIter position;
1933 GtkTextMark *insert_mark;
1935 uri = (const gchar *) uri_node->data;
1936 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1937 if (result == GNOME_VFS_OK) {
1939 GnomeVFSFileInfo info;
1940 gchar *filename, *basename, *escaped_filename;
1941 TnyMimePart *mime_part;
1943 const gchar *mime_type = NULL;
1944 GnomeVFSURI *vfs_uri;
1946 vfs_uri = gnome_vfs_uri_new (uri);
1948 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1949 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1950 g_free (escaped_filename);
1951 gnome_vfs_uri_unref (vfs_uri);
1953 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1954 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1956 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1958 mime_part = tny_platform_factory_new_mime_part
1959 (modest_runtime_get_platform_factory ());
1961 TnyStream *stream = create_stream_for_uri (uri);
1962 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1964 content_id = g_strdup_printf ("%d", priv->last_cid);
1965 tny_mime_part_set_content_id (mime_part, content_id);
1966 g_free (content_id);
1969 basename = g_path_get_basename (filename);
1970 tny_mime_part_set_filename (mime_part, basename);
1973 pixbuf = pixbuf_from_stream (stream, mime_type);
1975 if (pixbuf != NULL) {
1976 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1977 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1978 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1981 priv->images = g_list_prepend (priv->images, mime_part);
1982 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1992 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1994 GtkWidget *dialog = NULL;
1996 GSList *uris = NULL;
1999 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2000 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2001 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2003 response = gtk_dialog_run (GTK_DIALOG (dialog));
2005 case GTK_RESPONSE_OK:
2006 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2011 gtk_widget_destroy (dialog);
2013 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2014 const gchar *uri = (const gchar *) uri_node->data;
2015 modest_msg_edit_window_attach_file_one (window, uri);
2017 g_slist_foreach (uris, (GFunc) g_free, NULL);
2018 g_slist_free (uris);
2022 modest_msg_edit_window_attach_file_one (
2023 ModestMsgEditWindow *window,
2026 g_return_if_fail (window);
2027 g_return_if_fail (uri);
2029 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2032 GnomeVFSHandle *handle = NULL;
2033 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2034 if (result == GNOME_VFS_OK) {
2035 TnyMimePart *mime_part;
2037 const gchar *mime_type = NULL;
2039 gchar *escaped_filename;
2042 GnomeVFSFileInfo info;
2043 GnomeVFSURI *vfs_uri;
2045 vfs_uri = gnome_vfs_uri_new (uri);
2048 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2049 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2050 g_free (escaped_filename);
2051 gnome_vfs_uri_unref (vfs_uri);
2053 if (gnome_vfs_get_file_info (uri,
2055 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2056 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2058 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2059 mime_part = tny_platform_factory_new_mime_part
2060 (modest_runtime_get_platform_factory ());
2061 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2063 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2065 content_id = g_strdup_printf ("%d", priv->last_cid);
2066 tny_mime_part_set_content_id (mime_part, content_id);
2067 g_free (content_id);
2070 basename = g_path_get_basename (filename);
2071 tny_mime_part_set_filename (mime_part, basename);
2074 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2075 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2077 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2078 gtk_widget_show_all (priv->attachments_caption);
2079 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2085 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2088 ModestMsgEditWindowPrivate *priv;
2089 gboolean clean_list = FALSE;
2091 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2092 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2094 if (att_list == NULL) {
2095 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2099 if (att_list == NULL) {
2100 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2102 GtkWidget *confirmation_dialog = NULL;
2103 gboolean dialog_response;
2105 gchar *message = NULL;
2106 gchar *filename = NULL;
2108 if (att_list->next == NULL) {
2109 if (TNY_IS_MSG (att_list->data)) {
2110 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2112 filename = g_strdup (tny_header_get_subject (header));
2113 g_object_unref (header);
2115 if (filename == NULL) {
2116 filename = g_strdup (_("mail_va_no_subject"));
2119 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2122 filename = g_strdup ("");
2124 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2125 att_list->next == NULL), filename);
2127 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2129 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2130 gtk_widget_destroy (confirmation_dialog);
2131 if (!dialog_response) {
2133 g_list_free (att_list);
2136 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2138 for (node = att_list; node != NULL; node = g_list_next (node)) {
2139 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2140 const gchar *att_id;
2141 priv->attachments = g_list_remove (priv->attachments, mime_part);
2143 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2145 if (priv->attachments == NULL)
2146 gtk_widget_hide (priv->attachments_caption);
2147 att_id = tny_mime_part_get_content_id (mime_part);
2149 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2151 g_object_unref (mime_part);
2152 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2157 g_list_free (att_list);
2161 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2164 ModestMsgEditWindowPrivate *priv;
2165 GdkColor *new_color;
2166 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2168 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2169 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2172 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2174 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2176 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2178 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2183 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2186 ModestMsgEditWindowPrivate *priv;
2187 gint new_size_index;
2188 ModestMsgEditWindow *window;
2191 window = MODEST_MSG_EDIT_WINDOW (userdata);
2192 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2193 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2195 if (gtk_check_menu_item_get_active (menu_item)) {
2197 WPTextBufferFormat format;
2199 memset (&format, 0, sizeof (format));
2200 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2202 label = gtk_bin_get_child (GTK_BIN (menu_item));
2204 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2205 format.cs.font_size = TRUE;
2206 format.cs.text_position = TRUE;
2207 format.cs.font = TRUE;
2208 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2209 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2211 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2212 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2213 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2215 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2216 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2217 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2223 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2226 ModestMsgEditWindowPrivate *priv;
2227 gint new_font_index;
2228 ModestMsgEditWindow *window;
2231 window = MODEST_MSG_EDIT_WINDOW (userdata);
2232 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2233 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2235 if (gtk_check_menu_item_get_active (menu_item)) {
2238 label = gtk_bin_get_child (GTK_BIN (menu_item));
2240 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2242 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2243 GINT_TO_POINTER(new_font_index)))
2244 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2246 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2247 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2248 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2254 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2256 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2257 ModestWindowPrivate *parent_priv;
2258 ModestWindowMgr *mgr;
2259 gboolean is_fullscreen;
2260 GtkAction *fs_toggle_action;
2263 mgr = modest_runtime_get_window_mgr ();
2264 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2266 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2268 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2269 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2270 if (is_fullscreen != active)
2271 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2279 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2282 ModestMsgEditWindowPrivate *priv = NULL;
2283 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2285 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2286 if (!priv->update_caption_visibility)
2289 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2291 gtk_widget_show (priv->cc_caption);
2293 gtk_widget_hide (priv->cc_caption);
2295 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2299 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2302 ModestMsgEditWindowPrivate *priv = NULL;
2303 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2305 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2306 if (!priv->update_caption_visibility)
2309 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2311 gtk_widget_show (priv->bcc_caption);
2313 gtk_widget_hide (priv->bcc_caption);
2315 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2319 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2320 ModestRecptEditor *editor)
2322 ModestMsgEditWindowPrivate *priv;
2324 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2325 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2326 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2328 if (editor == NULL) {
2329 GtkWidget *view_focus;
2330 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2332 /* This code should be kept in sync with ModestRecptEditor. The
2333 textview inside the recpt editor is the one that really gets the
2334 focus. As it's inside a scrolled window, and this one inside the
2335 hbox recpt editor inherits from, we'll need to go up in the
2336 hierarchy to know if the text view is part of the recpt editor
2337 or if it's a different text entry */
2339 if (gtk_widget_get_parent (view_focus)) {
2340 GtkWidget *first_parent;
2342 first_parent = gtk_widget_get_parent (view_focus);
2343 if (gtk_widget_get_parent (first_parent) &&
2344 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2345 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2350 editor = MODEST_RECPT_EDITOR (priv->to_field);
2354 modest_address_book_select_addresses (editor);
2359 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2361 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2363 modest_msg_edit_window_open_addressbook (window, NULL);
2367 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2368 gboolean show_toolbar)
2370 ModestWindowPrivate *parent_priv;
2371 const gchar *action_name;
2374 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2375 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2377 /* We can not just use the code of
2378 modest_msg_edit_window_setup_toolbar because it has a
2379 mixture of both initialization and creation code. */
2381 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2383 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2385 /* Update also the actions (to update the toggles in the
2386 menus), we have to do it manually because some other window
2387 of the same time could have changed it (remember that the
2388 toolbar fullscreen mode is shared by all the windows of the
2390 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2391 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2393 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2395 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2396 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2402 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2403 TnyHeaderFlags priority_flags)
2405 ModestMsgEditWindowPrivate *priv;
2406 ModestWindowPrivate *parent_priv;
2408 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2410 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2411 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2413 if (priv->priority_flags != priority_flags) {
2414 GtkAction *priority_action = NULL;
2416 priv->priority_flags = priority_flags;
2418 switch (priority_flags) {
2419 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2420 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2421 gtk_widget_show (priv->priority_icon);
2422 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2423 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2425 case TNY_HEADER_FLAG_LOW_PRIORITY:
2426 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2427 gtk_widget_show (priv->priority_icon);
2428 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2429 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2432 gtk_widget_hide (priv->priority_icon);
2433 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2434 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2437 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2438 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2443 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2446 ModestMsgEditWindowPrivate *priv;
2447 ModestWindowPrivate *parent_priv;
2448 gint current_format;
2450 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2452 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2453 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2455 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2456 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2458 if (current_format != file_format) {
2459 switch (file_format) {
2460 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2461 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2462 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2464 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2468 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2469 response = gtk_dialog_run (GTK_DIALOG (dialog));
2470 gtk_widget_destroy (dialog);
2471 if (response == GTK_RESPONSE_OK) {
2472 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2474 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2475 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2480 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2485 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2488 ModestMsgEditWindowPrivate *priv;
2489 WPTextBufferFormat oldfmt, fmt;
2490 gint old_position = 0;
2494 GdkColor *color = NULL;
2495 gboolean bold, bold_set, italic, italic_set;
2496 gboolean underline, underline_set;
2497 gboolean strikethrough, strikethrough_set;
2498 gboolean position_set;
2499 gboolean font_size_set, font_set, color_set;
2502 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2503 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2505 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2507 /* First we get the currently selected font information */
2508 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2510 switch (oldfmt.text_position) {
2511 case TEXT_POSITION_NORMAL:
2514 case TEXT_POSITION_SUPERSCRIPT:
2522 g_object_set (G_OBJECT (dialog),
2523 "bold", oldfmt.bold != FALSE,
2524 "bold-set", !oldfmt.cs.bold,
2525 "underline", oldfmt.underline != FALSE,
2526 "underline-set", !oldfmt.cs.underline,
2527 "italic", oldfmt.italic != FALSE,
2528 "italic-set", !oldfmt.cs.italic,
2529 "strikethrough", oldfmt.strikethrough != FALSE,
2530 "strikethrough-set", !oldfmt.cs.strikethrough,
2531 "color", &oldfmt.color,
2532 "color-set", !oldfmt.cs.color,
2533 "size", wp_font_size[oldfmt.font_size],
2534 "size-set", !oldfmt.cs.font_size,
2535 "position", old_position,
2536 "position-set", !oldfmt.cs.text_position,
2537 "family", wp_get_font_name (oldfmt.font),
2538 "family-set", !oldfmt.cs.font,
2541 gtk_widget_show_all (dialog);
2542 response = gtk_dialog_run (GTK_DIALOG (dialog));
2543 if (response == GTK_RESPONSE_OK) {
2545 g_object_get( dialog,
2547 "bold-set", &bold_set,
2548 "underline", &underline,
2549 "underline-set", &underline_set,
2551 "italic-set", &italic_set,
2552 "strikethrough", &strikethrough,
2553 "strikethrough-set", &strikethrough_set,
2555 "color-set", &color_set,
2557 "size-set", &font_size_set,
2558 "family", &font_name,
2559 "family-set", &font_set,
2560 "position", &position,
2561 "position-set", &position_set,
2566 if (response == GTK_RESPONSE_OK) {
2567 memset(&fmt, 0, sizeof(fmt));
2573 fmt.italic = italic;
2574 fmt.cs.italic = TRUE;
2576 if (underline_set) {
2577 fmt.underline = underline;
2578 fmt.cs.underline = TRUE;
2580 if (strikethrough_set) {
2581 fmt.strikethrough = strikethrough;
2582 fmt.cs.strikethrough = TRUE;
2587 ? TEXT_POSITION_NORMAL
2588 : ( ( position == 1 )
2589 ? TEXT_POSITION_SUPERSCRIPT
2590 : TEXT_POSITION_SUBSCRIPT );
2591 fmt.cs.text_position = TRUE;
2592 fmt.font_size = oldfmt.font_size;
2596 fmt.cs.color = TRUE;
2599 fmt.font = wp_get_font_index(font_name,
2604 if (font_size_set) {
2605 fmt.cs.font_size = TRUE;
2606 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2608 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2609 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2611 gtk_widget_destroy (dialog);
2613 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2617 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2619 ModestMsgEditWindowPrivate *priv;
2621 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2622 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2624 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2626 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2631 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2633 ModestMsgEditWindowPrivate *priv;
2635 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2636 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2638 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2640 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2645 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2647 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2649 priv->can_undo = can_undo;
2653 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2655 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2657 priv->can_redo = can_redo;
2661 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2663 ModestMsgEditWindowPrivate *priv;
2664 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2665 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2667 return priv->can_undo;
2671 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2673 ModestMsgEditWindowPrivate *priv;
2674 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2675 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2677 return priv->can_redo;
2682 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2685 GtkTextIter match_start, match_end;
2687 if (image_id == NULL)
2690 gtk_text_buffer_get_start_iter (buffer, &iter);
2692 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2693 GSList *tags = gtk_text_iter_get_tags (&match_start);
2695 for (node = tags; node != NULL; node = g_slist_next (node)) {
2696 GtkTextTag *tag = (GtkTextTag *) node->data;
2697 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2698 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2699 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2701 offset = gtk_text_iter_get_offset (&match_start);
2702 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2703 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2707 gtk_text_iter_forward_char (&iter);
2712 message_is_empty (ModestMsgEditWindow *window)
2714 ModestMsgEditWindowPrivate *priv = NULL;
2716 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2717 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2719 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2720 * so we can ignore markup.
2722 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2725 count = gtk_text_buffer_get_char_count (buf);
2731 msg_body_focus (GtkWidget *focus,
2732 GdkEventFocus *event,
2736 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2741 recpt_field_changed (GtkTextBuffer *buffer,
2742 ModestMsgEditWindow *editor)
2744 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2748 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2750 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2754 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2756 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2757 GtkTextBuffer *buffer;
2759 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2760 gtk_text_buffer_set_modified (buffer, FALSE);
2761 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2762 gtk_text_buffer_set_modified (buffer, FALSE);
2763 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2764 gtk_text_buffer_set_modified (buffer, FALSE);
2765 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2769 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2771 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2772 GtkTextBuffer *buffer;
2774 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2775 if (gtk_text_buffer_get_modified (buffer))
2777 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2778 if (gtk_text_buffer_get_modified (buffer))
2780 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2781 if (gtk_text_buffer_get_modified (buffer))
2783 if (gtk_text_buffer_get_modified (priv->text_buffer))
2793 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2795 ModestMsgEditWindowPrivate *priv = NULL;
2797 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2800 /* check if there's no recipient added */
2801 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2802 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2803 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2804 /* no recipient contents, then select contacts */
2805 modest_msg_edit_window_open_addressbook (window, NULL);
2809 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2810 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2813 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2814 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2817 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2818 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2822 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2823 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2824 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2831 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2832 ModestMsgEditWindow *window)
2834 modest_msg_edit_window_offer_attach_file (window);
2838 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2840 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2842 return priv->clipboard_text;
2846 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2848 ModestMsgEditWindow *window)
2850 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2851 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2853 if (!GTK_WIDGET_VISIBLE (window))
2856 text = gtk_clipboard_wait_for_text (selection_clipboard);
2858 if (priv->clipboard_text != NULL) {
2859 g_free (priv->clipboard_text);
2861 priv->clipboard_text = text;
2863 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2866 subject_field_move_cursor (GtkEntry *entry,
2867 GtkMovementStep step,
2872 if (!GTK_WIDGET_VISIBLE (window))
2875 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2879 update_window_title (ModestMsgEditWindow *window)
2881 ModestMsgEditWindowPrivate *priv = NULL;
2882 const gchar *subject;
2884 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2885 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2886 if (subject == NULL || subject[0] == '\0')
2887 subject = _("mail_va_new_email");
2889 gtk_window_set_title (GTK_WINDOW (window), subject);
2894 subject_field_changed (GtkEditable *editable,
2895 ModestMsgEditWindow *window)
2897 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2898 update_window_title (window);
2899 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2900 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2904 subject_field_insert_text (GtkEditable *editable,
2906 gint new_text_length,
2908 ModestMsgEditWindow *window)
2910 GString *result = g_string_new ("");
2912 gint result_len = 0;
2913 const gchar *entry_text = NULL;
2916 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2917 old_length = g_utf8_strlen (entry_text, -1);
2919 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2920 gunichar c = g_utf8_get_char_validated (current, 8);
2921 /* Invalid unichar, stop */
2927 result = g_string_append_unichar (result, c);
2931 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2932 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2935 /* Prevent endless recursion */
2936 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2937 g_signal_emit_by_name (editable, "insert-text",
2938 (gpointer) result->str, (gpointer) result->len,
2939 (gpointer) position, (gpointer) window);
2940 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2944 if (result_len + old_length > 1000) {
2945 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2946 dgettext("hildon-common-strings",
2947 "ckdg_ib_maximum_characters_reached"));
2950 g_string_free (result, TRUE);
2954 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2957 ModestMsgEditWindowPrivate *priv = NULL;
2959 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2960 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2962 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2965 gtk_widget_show_all (priv->find_toolbar);
2966 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2968 gtk_widget_hide_all (priv->find_toolbar);
2969 gtk_widget_grab_focus (priv->msg_body);
2975 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2977 GtkTextIter *match_start,
2978 GtkTextIter *match_end)
2980 GtkTextIter end_iter;
2981 gchar *str_casefold;
2984 gchar *range_casefold;
2987 gboolean result = FALSE;
2994 gtk_text_iter_forward_to_end (&end_iter);
2996 str_casefold = g_utf8_casefold (str, -1);
2997 str_chars_n = strlen (str);
2999 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3000 range_casefold = g_utf8_casefold (range_text, -1);
3001 range_chars_n = strlen (range_casefold);
3003 if (range_chars_n < str_chars_n) {
3004 g_free (str_casefold);
3005 g_free (range_text);
3006 g_free (range_casefold);
3010 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3011 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3012 if (!g_utf8_collate (range_subtext, str_casefold)) {
3013 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3015 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3016 match_start, match_end, NULL);
3017 g_free (found_text);
3019 g_free (range_subtext);
3023 g_free (str_casefold);
3024 g_free (range_text);
3025 g_free (range_casefold);
3032 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3033 ModestMsgEditWindow *window)
3035 gchar *current_search = NULL;
3036 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3038 GtkTextIter selection_start, selection_end;
3039 GtkTextIter match_start, match_end;
3040 gboolean continue_search = FALSE;
3042 if (message_is_empty (window)) {
3043 g_free (priv->last_search);
3044 priv->last_search = NULL;
3045 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3049 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3050 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3051 g_free (current_search);
3052 g_free (priv->last_search);
3053 priv->last_search = NULL;
3054 /* Information banner about empty search */
3055 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3059 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3060 continue_search = TRUE;
3062 g_free (priv->last_search);
3063 priv->last_search = g_strdup (current_search);
3066 if (continue_search) {
3067 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3068 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3069 &match_start, &match_end);
3071 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3073 GtkTextIter buffer_start;
3074 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3075 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3076 &match_start, &match_end);
3078 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3081 /* Mark as selected the string found in search */
3083 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3084 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3086 g_free (priv->last_search);
3087 priv->last_search = NULL;
3089 g_free (current_search);
3093 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3094 ModestMsgEditWindow *window)
3096 GtkToggleAction *toggle;
3097 ModestWindowPrivate *parent_priv;
3098 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3100 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3101 gtk_toggle_action_set_active (toggle, FALSE);
3105 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3107 ModestMsgEditWindowPrivate *priv;
3109 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3114 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3117 ModestMsgEditWindowPrivate *priv;
3119 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3125 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3128 ModestMsgEditWindowPrivate *priv;
3129 TnyHeader *header = NULL;
3131 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3132 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3134 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3135 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3137 if (priv->draft_msg != NULL) {
3138 g_object_unref (priv->draft_msg);
3141 if (draft != NULL) {
3142 g_object_ref (draft);
3143 header = tny_msg_get_header (draft);
3144 if (priv->msg_uid) {
3145 g_free (priv->msg_uid);
3146 priv->msg_uid = NULL;
3148 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3149 if (GTK_WIDGET_REALIZED (window))
3150 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3153 priv->draft_msg = draft;
3157 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3158 GtkTextIter *start, GtkTextIter *end,
3161 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3162 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3165 if (tag == NULL+13) return;
3166 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3167 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3168 replace_with_images (window, priv->images);
3173 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3176 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3178 g_return_if_fail (TNY_IS_MIME_PART (part));
3179 priv->attachments = g_list_prepend (priv->attachments, part);
3180 g_object_ref (part);
3181 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3182 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3183 gtk_widget_show_all (priv->attachments_caption);
3184 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3188 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3190 ModestMsgEditWindowPrivate *priv;
3192 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3193 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3195 return priv->msg_uid;
3199 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3200 ModestMsgEditWindowWidgetType widget_type)
3202 ModestMsgEditWindowPrivate *priv;
3204 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3205 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3207 switch (widget_type) {
3208 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3209 return priv->msg_body;
3211 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3212 return priv->to_field;
3214 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3215 return priv->cc_field;
3217 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3218 return priv->bcc_field;
3220 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3221 return priv->subject_field;
3223 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3224 return priv->attachments_view;
3232 remove_tags (WPTextBuffer *buffer)
3234 GtkTextIter start, end;
3236 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3237 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3239 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3243 on_account_removed (TnyAccountStore *account_store,
3244 TnyAccount *account,
3247 /* Do nothing if it's a store account, because we use the
3248 transport to send the messages */
3249 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3250 const gchar *parent_acc = NULL;
3251 const gchar *our_acc = NULL;
3253 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3254 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3255 /* Close this window if I'm showing a message of the removed account */
3256 if (strcmp (parent_acc, our_acc) == 0)
3257 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3262 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3264 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3266 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3272 set_zoom_do_nothing (ModestWindow *window,
3278 get_zoom_do_nothing (ModestWindow *window)