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 init_window (ModestMsgEditWindow *obj)
568 GtkWidget *from_caption, *to_caption, *subject_caption;
569 GtkWidget *main_vbox;
570 ModestMsgEditWindowPrivate *priv;
571 GtkActionGroup *action_group;
572 ModestWindowPrivate *parent_priv;
573 GdkPixbuf *window_icon = NULL;
574 GError *error = NULL;
576 GtkSizeGroup *size_group;
578 GtkWidget *subject_box;
579 GtkWidget *attachment_icon;
580 GtkWidget *window_box;
581 #if (GTK_MINOR_VERSION >= 10)
582 GdkAtom deserialize_type;
584 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
585 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
587 parent_priv->ui_manager = gtk_ui_manager_new();
588 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
589 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
591 /* Add common actions */
592 gtk_action_group_add_actions (action_group,
593 modest_msg_edit_action_entries,
594 G_N_ELEMENTS (modest_msg_edit_action_entries),
596 gtk_action_group_add_toggle_actions (action_group,
597 modest_msg_edit_toggle_action_entries,
598 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
600 gtk_action_group_add_radio_actions (action_group,
601 modest_msg_edit_alignment_radio_action_entries,
602 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
604 G_CALLBACK (modest_ui_actions_on_change_justify),
606 gtk_action_group_add_radio_actions (action_group,
607 modest_msg_edit_priority_action_entries,
608 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
610 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
612 gtk_action_group_add_radio_actions (action_group,
613 modest_msg_edit_file_format_action_entries,
614 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
615 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
616 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
618 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
619 g_object_unref (action_group);
621 /* Load the UI definition */
622 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
625 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
626 g_clear_error (&error);
629 /* Add accelerators */
630 gtk_window_add_accel_group (GTK_WINDOW (obj),
631 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
633 parent_priv->menubar = NULL;
635 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
637 /* Note: This ModestPairList* must exist for as long as the combo
638 * that uses it, because the ModestComboBox uses the ID opaquely,
639 * so it can't know how to manage its memory. */
640 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
642 priv->to_field = modest_recpt_editor_new ();
643 priv->cc_field = modest_recpt_editor_new ();
644 priv->bcc_field = modest_recpt_editor_new ();
645 subject_box = gtk_hbox_new (FALSE, 0);
646 priv->priority_icon = gtk_image_new ();
647 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
648 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
649 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
650 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
651 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
652 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
653 priv->add_attachment_button = gtk_button_new ();
654 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
655 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
656 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
657 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
658 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
659 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
660 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
661 priv->attachments_view = modest_attachments_view_new (NULL);
663 priv->header_box = gtk_vbox_new (FALSE, 0);
665 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
666 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
667 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
668 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
669 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
670 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
671 g_object_unref (size_group);
673 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
674 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
675 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
676 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
677 gtk_size_group_add_widget (size_group, priv->subject_field);
678 gtk_size_group_add_widget (size_group, priv->attachments_view);
679 g_object_unref (size_group);
681 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
682 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
683 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
684 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
685 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
686 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
687 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
690 priv->msg_body = wp_text_view_new ();
691 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
692 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
693 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
694 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
695 #if (GTK_MINOR_VERSION >= 10)
696 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
697 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
699 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
700 deserialize_type, TRUE);
702 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
704 priv->find_toolbar = hildon_find_toolbar_new (NULL);
705 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
707 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
709 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
710 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
711 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
712 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
714 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
716 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
717 frame = gtk_frame_new (NULL);
718 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
720 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
721 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
722 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
724 G_CALLBACK (vadj_changed),
726 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
728 window_box = gtk_vbox_new (FALSE, 0);
729 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
730 gtk_container_add (GTK_CONTAINER(obj), window_box);
731 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
732 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
734 /* Set window icon */
735 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
737 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
738 g_object_unref (window_icon);
743 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
745 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
747 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
748 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
749 priv->clipboard_change_handler_id))
750 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
751 priv->clipboard_change_handler_id);
752 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
753 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
754 priv->default_clipboard_change_handler_id))
755 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
756 priv->default_clipboard_change_handler_id);
758 if (priv->account_removed_handler_id &&
759 g_signal_handler_is_connected (modest_runtime_get_account_store (),
760 priv->account_removed_handler_id))
761 g_signal_handler_disconnect(modest_runtime_get_account_store (),
762 priv->account_removed_handler_id);
766 modest_msg_edit_window_finalize (GObject *obj)
768 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
770 /* Sanity check: shouldn't be needed, the window mgr should
771 call this function before */
772 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
774 if (priv->clipboard_text != NULL) {
775 g_free (priv->clipboard_text);
776 priv->clipboard_text = NULL;
779 if (priv->draft_msg != NULL) {
780 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
781 if (TNY_IS_HEADER (header)) {
782 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
783 modest_window_mgr_unregister_header (mgr, header);
785 g_object_unref (priv->draft_msg);
786 priv->draft_msg = NULL;
788 if (priv->outbox_msg != NULL) {
789 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
790 if (TNY_IS_HEADER (header)) {
791 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
792 modest_window_mgr_unregister_header (mgr, header);
794 g_object_unref (priv->outbox_msg);
795 priv->outbox_msg = NULL;
797 g_free (priv->msg_uid);
798 g_free (priv->last_search);
799 g_slist_free (priv->font_items_group);
800 g_slist_free (priv->size_items_group);
801 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
802 g_list_free (priv->attachments);
803 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
804 g_list_free (priv->images);
806 /* This had to stay alive for as long as the combobox that used it: */
807 modest_pair_list_free (priv->from_field_protos);
809 G_OBJECT_CLASS(parent_class)->finalize (obj);
813 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
815 GdkPixbufLoader *loader;
818 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
823 tny_stream_reset (TNY_STREAM (stream));
824 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
825 unsigned char read_buffer[128];
827 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
828 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
832 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
833 g_object_ref (pixbuf);
834 gdk_pixbuf_loader_close (loader, NULL);
835 g_object_unref (loader);
837 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
838 GdkPixbuf *new_pixbuf;
840 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
841 gdk_pixbuf_get_width (pixbuf);
842 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
843 g_object_unref (pixbuf);
851 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
853 ModestMsgEditWindowPrivate *priv;
856 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
858 for (node = attachments; node != NULL; node = g_list_next (node)) {
859 TnyMimePart *part = (TnyMimePart *) node->data;
860 const gchar *cid = tny_mime_part_get_content_id (part);
861 const gchar *mime_type = tny_mime_part_get_content_type (part);
862 if ((cid != NULL)&&(mime_type != NULL)) {
863 TnyStream *stream = tny_mime_part_get_stream (part);
864 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
865 g_object_unref (stream);
867 if (pixbuf != NULL) {
868 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
869 g_object_unref (pixbuf);
876 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
878 TnyMimePart *parent = NULL;
879 const gchar *content_type = NULL;
880 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
882 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
884 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
885 parent = g_object_ref (msg);
886 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
887 TnyList *parts = TNY_LIST (tny_simple_list_new ());
890 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
891 iter = tny_list_create_iterator (parts);
892 while (!tny_iterator_is_done (iter)) {
894 part = TNY_MIME_PART (tny_iterator_get_current (iter));
895 content_type = tny_mime_part_get_content_type (part);
896 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
900 g_object_unref (part);
902 tny_iterator_next (iter);
904 g_object_unref (iter);
905 g_object_unref (parts);
908 if (parent != NULL) {
909 TnyList *parts = TNY_LIST (tny_simple_list_new ());
912 tny_mime_part_get_parts (TNY_MIME_PART (parent), 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_str_has_prefix (content_type, "image/")) {
919 priv->images = g_list_prepend (priv->images, part);
921 g_object_unref (part);
923 tny_iterator_next (iter);
925 g_object_unref (iter);
926 g_object_unref (parts);
927 g_object_unref (parent);
932 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
935 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
937 for (node = attachments; node != NULL; node = g_list_next (node)) {
938 TnyMimePart *part = (TnyMimePart *) node->data;
939 const gchar *cid = tny_mime_part_get_content_id (part);
941 char *invalid = NULL;
942 gint int_cid = strtol (cid, &invalid, 10);
943 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
944 priv->last_cid = int_cid;
952 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
955 const gchar *to, *cc, *bcc, *subject;
957 ModestMsgEditWindowPrivate *priv;
959 TnyHeaderFlags priority_flags;
960 TnyFolder *msg_folder;
961 gboolean is_html = FALSE;
963 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
964 g_return_if_fail (TNY_IS_MSG (msg));
966 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
968 header = tny_msg_get_header (msg);
969 to = tny_header_get_to (header);
970 cc = tny_header_get_cc (header);
971 bcc = tny_header_get_bcc (header);
972 subject = tny_header_get_subject (header);
973 priority_flags = tny_header_get_priority (header);
976 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
978 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
979 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
980 gtk_widget_show (priv->cc_caption);
981 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
982 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
983 gtk_widget_hide (priv->cc_caption);
986 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
987 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
988 gtk_widget_show (priv->bcc_caption);
989 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
990 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
991 gtk_widget_hide (priv->bcc_caption);
994 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
995 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
998 update_window_title (self);
1000 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1001 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1003 if ((body == NULL)||(body[0] == '\0')) {
1005 body = modest_text_utils_convert_to_html ("");
1008 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1009 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1012 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1015 /* Add attachments to the view */
1016 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1017 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1018 if (priv->attachments == NULL) {
1019 gtk_widget_hide (priv->attachments_caption);
1021 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1022 gtk_widget_show_all (priv->attachments_caption);
1024 get_related_images (self, msg);
1025 update_last_cid (self, priv->attachments);
1026 update_last_cid (self, priv->images);
1027 replace_with_images (self, priv->images);
1029 if (preserve_is_rich && !is_html) {
1030 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1031 /* Get the default format required from configuration */
1032 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1033 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1036 /* Set the default focus depending on having already a To: field or not */
1037 if ((!to)||(*to == '\0')) {
1038 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1040 gtk_widget_grab_focus (priv->msg_body);
1043 /* TODO: lower priority, select in the From: combo to the
1044 value that comes from msg <- not sure, should it be
1047 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1049 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1050 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1052 modest_msg_edit_window_reset_modified (self);
1054 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1055 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1056 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1058 if (priv->msg_uid) {
1059 g_free (priv->msg_uid);
1060 priv->msg_uid = NULL;
1063 /* we should set a reference to the incoming message if it is a draft */
1064 msg_folder = tny_msg_get_folder (msg);
1066 if (modest_tny_folder_is_local_folder (msg_folder)) {
1067 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1068 if (type == TNY_FOLDER_TYPE_INVALID)
1069 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1071 if (type == TNY_FOLDER_TYPE_DRAFTS)
1072 priv->draft_msg = g_object_ref(msg);
1073 if (type == TNY_FOLDER_TYPE_OUTBOX)
1074 priv->outbox_msg = g_object_ref(msg);
1075 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1077 g_object_unref (msg_folder);
1082 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1085 GList *item_children, *node;
1086 GtkWidget *bin_child;
1088 bin_child = gtk_bin_get_child (GTK_BIN(item));
1090 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1092 for (node = item_children; node != NULL; node = g_list_next (node)) {
1093 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1094 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1097 g_list_free (item_children);
1101 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1104 GList *item_children, *node;
1106 box = gtk_bin_get_child (GTK_BIN (item));
1107 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1108 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1110 for (node = item_children; node != NULL; node = g_list_next (node)) {
1111 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1112 if (GTK_IS_TOGGLE_BUTTON (node->data))
1113 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1114 else if (GTK_IS_BUTTON (node->data))
1115 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1117 g_list_free (item_children);
1122 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1124 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1125 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1126 GtkWidget *placeholder;
1127 GtkWidget *tool_item;
1132 GtkWidget *sizes_menu;
1133 GtkWidget *fonts_menu;
1134 GSList *radio_group = NULL;
1135 GSList *node = NULL;
1139 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1140 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1142 /* Font color placeholder */
1143 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1144 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1147 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1148 priv->font_color_button = hildon_color_button_new ();
1149 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1150 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1151 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1152 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1153 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1154 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1155 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1157 G_CALLBACK (modest_msg_edit_window_color_button_change),
1160 /* Font size and face placeholder */
1161 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1162 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1164 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1165 priv->size_tool_button_label = gtk_label_new (NULL);
1166 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1167 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1168 size_text,"</span>", NULL);
1169 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1171 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1172 sizes_menu = gtk_menu_new ();
1173 priv->size_items_group = NULL;
1175 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1176 GtkWidget *size_menu_item;
1178 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1179 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1180 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1181 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1182 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1183 gtk_widget_show (size_menu_item);
1185 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1189 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1190 GtkWidget *item = (GtkWidget *) node->data;
1191 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1195 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1196 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1197 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1198 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1199 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1200 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1201 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1202 priv->font_size_toolitem = tool_item;
1205 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1206 priv->font_tool_button_label = gtk_label_new (NULL);
1207 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1208 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1210 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1211 fonts_menu = gtk_menu_new ();
1212 priv->font_items_group = NULL;
1214 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1215 GtkWidget *font_menu_item;
1216 GtkWidget *child_label;
1218 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1219 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1220 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1221 wp_get_font_name (font_index), "</span>", NULL);
1222 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1225 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1226 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1227 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1228 gtk_widget_show (font_menu_item);
1230 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1233 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1234 GtkWidget *item = (GtkWidget *) node->data;
1235 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1238 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1239 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1240 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1241 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1242 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1243 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1244 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1245 priv->font_face_toolitem = tool_item;
1247 /* Set expand and homogeneous for remaining items */
1248 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1249 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1250 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1251 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1252 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1253 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1254 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1255 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1256 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1258 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1259 will not show the tool items added to the placeholders) */
1260 gtk_widget_show_all (parent_priv->toolbar);
1262 /* Set the no show all *after* showing all items. We do not
1263 want the toolbar to be shown with a show all because it
1264 could go agains the gconf setting regarding showing or not
1265 the toolbar of the editor window */
1266 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1272 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1275 ModestWindowPrivate *parent_priv;
1276 ModestMsgEditWindowPrivate *priv;
1277 ModestPair *account_pair = NULL;
1278 ModestDimmingRulesGroup *menu_rules_group = NULL;
1279 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1280 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1281 ModestWindowMgr *mgr = NULL;
1283 g_return_val_if_fail (msg, NULL);
1284 g_return_val_if_fail (account_name, NULL);
1286 mgr = modest_runtime_get_window_mgr ();
1288 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1290 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1291 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1293 /* Menubar. Update the state of some toggles */
1294 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1295 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1296 priv->from_field_protos = get_transports ();
1297 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1298 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1299 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1302 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1304 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1306 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1308 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1309 if (account_pair != NULL)
1310 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1312 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1313 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1314 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1315 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1316 /* Add common dimming rules */
1317 modest_dimming_rules_group_add_rules (menu_rules_group,
1318 modest_msg_edit_window_menu_dimming_entries,
1319 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1320 MODEST_WINDOW (obj));
1321 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1322 modest_msg_edit_window_toolbar_dimming_entries,
1323 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1324 MODEST_WINDOW (obj));
1325 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1326 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1327 MODEST_WINDOW (obj));
1328 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1329 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1330 MODEST_WINDOW (obj));
1331 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1332 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1333 MODEST_WINDOW (obj));
1334 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1335 modest_msg_edit_window_clipboard_dimming_entries,
1336 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1337 MODEST_WINDOW (obj));
1338 /* Insert dimming rules group for this window */
1339 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1340 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1341 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1342 /* Checks the dimming rules */
1343 g_object_unref (menu_rules_group);
1344 g_object_unref (toolbar_rules_group);
1345 g_object_unref (clipboard_rules_group);
1346 gtk_widget_show_all (GTK_WIDGET (obj));
1348 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1350 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1352 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1353 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1354 priv->update_caption_visibility = TRUE;
1356 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1358 /* Track account-removed signal, this window should be closed
1359 in the case we're creating a mail associated to the account
1361 priv->account_removed_handler_id =
1362 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1364 G_CALLBACK(on_account_removed),
1367 return (ModestWindow*) obj;
1371 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1373 GString **string_buffer = (GString **) user_data;
1375 *string_buffer = g_string_append (*string_buffer, buffer);
1381 * @result: A new string which should be freed with g_free().
1384 get_formatted_data (ModestMsgEditWindow *edit_window)
1386 ModestMsgEditWindowPrivate *priv;
1387 GString *string_buffer = g_string_new ("");
1389 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1391 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1393 return g_string_free (string_buffer, FALSE);
1398 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1401 const gchar *account_name;
1402 ModestMsgEditWindowPrivate *priv;
1404 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1406 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1408 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1409 g_return_val_if_fail (account_name, NULL);
1412 /* don't free these (except from) */
1413 data = g_slice_new0 (MsgData);
1414 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1416 data->account_name = g_strdup (account_name);
1417 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1418 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1419 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1420 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1421 if (priv->draft_msg) {
1422 data->draft_msg = g_object_ref (priv->draft_msg);
1423 } else if (priv->outbox_msg) {
1424 data->draft_msg = g_object_ref (priv->outbox_msg);
1426 data->draft_msg = NULL;
1429 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1431 gtk_text_buffer_get_bounds (buf, &b, &e);
1432 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1434 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1435 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1437 data->html_body = NULL;
1439 /* deep-copy the data */
1440 GList *cursor = priv->attachments;
1441 data->attachments = NULL;
1443 if (!(TNY_IS_MIME_PART(cursor->data))) {
1444 g_warning ("strange data in attachment list");
1445 cursor = g_list_next (cursor);
1448 data->attachments = g_list_append (data->attachments,
1449 g_object_ref (cursor->data));
1450 cursor = g_list_next (cursor);
1453 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1454 cursor = priv->images;
1455 data->images = NULL;
1458 if (!(TNY_IS_MIME_PART(cursor->data))) {
1459 g_warning ("strange data in attachment list");
1460 cursor = g_list_next (cursor);
1463 cid = tny_mime_part_get_content_id (cursor->data);
1465 gchar *image_tag_id;
1466 GtkTextTag *image_tag;
1468 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1469 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1470 g_free (image_tag_id);
1472 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1474 ((gtk_text_iter_has_tag (&iter, image_tag))||
1475 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1476 data->images = g_list_append (data->images,
1477 g_object_ref (cursor->data));
1479 cursor = g_list_next (cursor);
1482 data->priority_flags = priv->priority_flags;
1489 unref_gobject (GObject *obj, gpointer data)
1491 if (!G_IS_OBJECT(obj))
1493 g_object_unref (obj);
1497 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1500 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1508 g_free (data->from);
1509 g_free (data->subject);
1510 g_free (data->plain_body);
1511 g_free (data->html_body);
1512 g_free (data->account_name);
1514 if (data->draft_msg != NULL) {
1515 g_object_unref (data->draft_msg);
1516 data->draft_msg = NULL;
1519 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1520 g_list_free (data->attachments);
1521 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1522 g_list_free (data->images);
1524 g_slice_free (MsgData, data);
1528 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1531 ModestMsgEditWindowPrivate *priv = NULL;
1532 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1534 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1536 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1538 return MODEST_MSG_EDIT_FORMAT_HTML;
1540 return MODEST_MSG_EDIT_FORMAT_TEXT;
1544 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1545 ModestMsgEditFormat format)
1547 ModestMsgEditWindowPrivate *priv;
1549 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1550 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1553 case MODEST_MSG_EDIT_FORMAT_HTML:
1554 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1556 case MODEST_MSG_EDIT_FORMAT_TEXT:
1557 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1560 g_return_if_reached ();
1564 ModestMsgEditFormatState *
1565 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1567 ModestMsgEditFormatState *format_state = NULL;
1568 ModestMsgEditWindowPrivate *priv;
1569 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1571 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1572 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1574 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1576 format_state = g_new0 (ModestMsgEditFormatState, 1);
1577 format_state->bold = buffer_format->bold&0x1;
1578 format_state->italics = buffer_format->italic&0x1;
1579 format_state->bullet = buffer_format->bullet&0x1;
1580 format_state->color = buffer_format->color;
1581 format_state->font_size = buffer_format->font_size;
1582 format_state->font_family = wp_get_font_name (buffer_format->font);
1583 format_state->justification = buffer_format->justification;
1584 g_free (buffer_format);
1586 return format_state;
1591 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1592 const ModestMsgEditFormatState *format_state)
1594 ModestMsgEditWindowPrivate *priv;
1595 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1596 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1597 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1598 g_return_if_fail (format_state != NULL);
1600 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1601 gtk_widget_grab_focus (priv->msg_body);
1602 buffer_format->bold = (format_state->bold != FALSE);
1603 buffer_format->italic = (format_state->italics != FALSE);
1604 buffer_format->color = format_state->color;
1605 buffer_format->font_size = format_state->font_size;
1606 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1607 buffer_format->justification = format_state->justification;
1608 buffer_format->bullet = format_state->bullet;
1610 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1612 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1613 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1614 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1615 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1616 buffer_format->cs.font = (buffer_format->font != current_format->font);
1617 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1618 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1620 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1621 if (buffer_format->cs.bold) {
1622 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1623 GINT_TO_POINTER (buffer_format->bold&0x1));
1625 if (buffer_format->cs.italic) {
1626 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1627 GINT_TO_POINTER (buffer_format->italic&0x1));
1629 if (buffer_format->cs.color) {
1630 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1631 GINT_TO_POINTER (&(buffer_format->color)));
1633 if (buffer_format->cs.font_size) {
1634 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1635 GINT_TO_POINTER (buffer_format->font_size));
1637 if (buffer_format->cs.justification) {
1638 switch (buffer_format->justification) {
1639 case GTK_JUSTIFY_LEFT:
1640 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1641 GINT_TO_POINTER(TRUE));
1643 case GTK_JUSTIFY_CENTER:
1644 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1645 GINT_TO_POINTER(TRUE));
1647 case GTK_JUSTIFY_RIGHT:
1648 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1649 GINT_TO_POINTER(TRUE));
1656 if (buffer_format->cs.font) {
1657 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1658 GINT_TO_POINTER (buffer_format->font));
1660 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1661 if (buffer_format->cs.bullet) {
1662 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1663 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1665 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1667 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1669 g_free (current_format);
1674 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1676 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1678 ModestWindowPrivate *parent_priv;
1679 ModestMsgEditWindowPrivate *priv;
1680 GtkWidget *new_size_menuitem;
1681 GtkWidget *new_font_menuitem;
1683 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1684 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1686 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1687 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1688 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1689 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1691 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1692 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1693 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1696 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1698 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1699 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1701 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1702 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1704 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1705 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1708 switch (buffer_format->justification)
1710 case GTK_JUSTIFY_LEFT:
1711 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentLeftMenu");
1712 g_warning ("GTK_JUSTIFY_LEFT");
1714 case GTK_JUSTIFY_CENTER:
1715 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentCenterMenu");
1716 g_warning ("GTK_JUSTIFY_CENTER");
1718 case GTK_JUSTIFY_RIGHT:
1719 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentRightMenu");
1720 g_warning ("GTK_JUSTIFY_RIGHT");
1727 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1729 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1730 G_CALLBACK (modest_msg_edit_window_color_button_change),
1732 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1733 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1734 G_CALLBACK (modest_msg_edit_window_color_button_change),
1737 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1738 buffer_format->font_size))->data);
1739 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1743 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1744 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1745 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1747 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1748 G_CALLBACK (modest_msg_edit_window_size_change),
1750 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1751 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1752 G_CALLBACK (modest_msg_edit_window_size_change),
1756 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1757 buffer_format->font))->data);
1758 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1762 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1763 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1764 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1766 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1767 G_CALLBACK (modest_msg_edit_window_font_change),
1769 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1770 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1771 G_CALLBACK (modest_msg_edit_window_font_change),
1775 g_free (buffer_format);
1779 #ifdef MODEST_HILDON_VERSION_0
1781 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1784 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1785 ModestMsgEditWindowPrivate *priv;
1786 GtkWidget *dialog = NULL;
1788 GdkColor *new_color = NULL;
1790 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1791 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1793 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1794 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1795 g_free (buffer_format);
1797 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1798 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1799 if (new_color != NULL) {
1800 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1801 (gpointer) new_color);
1804 gtk_widget_destroy (dialog);
1809 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1812 ModestMsgEditWindowPrivate *priv;
1813 GtkWidget *dialog = NULL;
1815 GdkColor *old_color = NULL;
1816 const GdkColor *new_color = NULL;
1818 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1819 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1821 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1822 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1824 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1825 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1826 if (new_color != NULL)
1827 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1829 gtk_widget_destroy (dialog);
1835 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1838 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1839 ModestMsgEditWindowPrivate *priv;
1840 GtkWidget *dialog = NULL;
1842 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1843 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1845 dialog = hildon_color_chooser_new ();
1846 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1847 g_free (buffer_format);
1849 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1851 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1852 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1855 gtk_widget_destroy (dialog);
1860 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1863 ModestMsgEditWindowPrivate *priv;
1864 GtkWidget *dialog = NULL;
1865 GdkColor *old_color = NULL;
1867 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1868 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1870 dialog = hildon_color_chooser_new ();
1871 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1873 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1875 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1876 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1878 gtk_widget_destroy (dialog);
1881 #endif /*!MODEST_HILDON_VERSION_0*/
1885 static TnyStream* create_stream_for_uri (const gchar* uri)
1890 TnyStream *result = NULL;
1892 GnomeVFSHandle *handle = NULL;
1893 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1894 if (test == GNOME_VFS_OK) {
1895 /* Create the tinymail stream: */
1896 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1897 result = TNY_STREAM (tny_vfs_stream_new (handle));
1904 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1907 ModestMsgEditWindowPrivate *priv;
1908 GtkWidget *dialog = NULL;
1910 GSList *uris = NULL;
1911 GSList *uri_node = NULL;
1913 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1915 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1916 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1917 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1919 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1921 response = gtk_dialog_run (GTK_DIALOG (dialog));
1923 case GTK_RESPONSE_OK:
1924 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1929 gtk_widget_destroy (dialog);
1931 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1933 GnomeVFSHandle *handle = NULL;
1934 GnomeVFSResult result;
1935 GtkTextIter position;
1936 GtkTextMark *insert_mark;
1938 uri = (const gchar *) uri_node->data;
1939 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1940 if (result == GNOME_VFS_OK) {
1942 GnomeVFSFileInfo info;
1943 gchar *filename, *basename, *escaped_filename;
1944 TnyMimePart *mime_part;
1946 const gchar *mime_type = NULL;
1947 GnomeVFSURI *vfs_uri;
1949 vfs_uri = gnome_vfs_uri_new (uri);
1951 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1952 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1953 g_free (escaped_filename);
1954 gnome_vfs_uri_unref (vfs_uri);
1956 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1957 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1959 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1961 mime_part = tny_platform_factory_new_mime_part
1962 (modest_runtime_get_platform_factory ());
1964 TnyStream *stream = create_stream_for_uri (uri);
1965 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1967 content_id = g_strdup_printf ("%d", priv->last_cid);
1968 tny_mime_part_set_content_id (mime_part, content_id);
1969 g_free (content_id);
1972 basename = g_path_get_basename (filename);
1973 tny_mime_part_set_filename (mime_part, basename);
1976 pixbuf = pixbuf_from_stream (stream, mime_type);
1978 if (pixbuf != NULL) {
1979 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1980 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1981 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1984 priv->images = g_list_prepend (priv->images, mime_part);
1985 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1995 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1997 GtkWidget *dialog = NULL;
1999 GSList *uris = NULL;
2002 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2003 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2004 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2006 response = gtk_dialog_run (GTK_DIALOG (dialog));
2008 case GTK_RESPONSE_OK:
2009 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2014 gtk_widget_destroy (dialog);
2016 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2017 const gchar *uri = (const gchar *) uri_node->data;
2018 modest_msg_edit_window_attach_file_one (window, uri);
2020 g_slist_foreach (uris, (GFunc) g_free, NULL);
2021 g_slist_free (uris);
2025 modest_msg_edit_window_attach_file_one (
2026 ModestMsgEditWindow *window,
2029 g_return_if_fail (window);
2030 g_return_if_fail (uri);
2032 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2035 GnomeVFSHandle *handle = NULL;
2036 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2037 if (result == GNOME_VFS_OK) {
2038 TnyMimePart *mime_part;
2040 const gchar *mime_type = NULL;
2042 gchar *escaped_filename;
2045 GnomeVFSFileInfo info;
2046 GnomeVFSURI *vfs_uri;
2048 vfs_uri = gnome_vfs_uri_new (uri);
2051 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2052 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2053 g_free (escaped_filename);
2054 gnome_vfs_uri_unref (vfs_uri);
2056 if (gnome_vfs_get_file_info (uri,
2058 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2060 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2061 mime_part = tny_platform_factory_new_mime_part
2062 (modest_runtime_get_platform_factory ());
2063 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2065 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2067 content_id = g_strdup_printf ("%d", priv->last_cid);
2068 tny_mime_part_set_content_id (mime_part, content_id);
2069 g_free (content_id);
2072 basename = g_path_get_basename (filename);
2073 tny_mime_part_set_filename (mime_part, basename);
2076 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2077 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2079 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2080 gtk_widget_show_all (priv->attachments_caption);
2081 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2087 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2090 ModestMsgEditWindowPrivate *priv;
2091 gboolean clean_list = FALSE;
2093 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2094 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2096 if (att_list == NULL) {
2097 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2101 if (att_list == NULL) {
2102 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2104 GtkWidget *confirmation_dialog = NULL;
2105 gboolean dialog_response;
2107 gchar *message = NULL;
2108 gchar *filename = NULL;
2110 if (att_list->next == NULL) {
2111 if (TNY_IS_MSG (att_list->data)) {
2112 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2114 filename = g_strdup (tny_header_get_subject (header));
2115 g_object_unref (header);
2117 if (filename == NULL) {
2118 filename = g_strdup (_("mail_va_no_subject"));
2121 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2124 filename = g_strdup ("");
2126 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2127 att_list->next == NULL), filename);
2129 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2131 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2132 gtk_widget_destroy (confirmation_dialog);
2133 if (!dialog_response) {
2135 g_list_free (att_list);
2138 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2140 for (node = att_list; node != NULL; node = g_list_next (node)) {
2141 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2142 const gchar *att_id;
2143 priv->attachments = g_list_remove (priv->attachments, mime_part);
2145 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2147 if (priv->attachments == NULL)
2148 gtk_widget_hide (priv->attachments_caption);
2149 att_id = tny_mime_part_get_content_id (mime_part);
2151 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2153 g_object_unref (mime_part);
2154 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2159 g_list_free (att_list);
2163 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2166 ModestMsgEditWindowPrivate *priv;
2167 GdkColor *new_color;
2168 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2170 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2171 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2174 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2176 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2178 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2180 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2185 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2188 ModestMsgEditWindowPrivate *priv;
2189 gint new_size_index;
2190 ModestMsgEditWindow *window;
2193 window = MODEST_MSG_EDIT_WINDOW (userdata);
2194 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2195 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2197 if (gtk_check_menu_item_get_active (menu_item)) {
2199 WPTextBufferFormat format;
2201 memset (&format, 0, sizeof (format));
2202 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2204 label = gtk_bin_get_child (GTK_BIN (menu_item));
2206 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2207 format.cs.font_size = TRUE;
2208 format.cs.text_position = TRUE;
2209 format.cs.font = TRUE;
2210 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2211 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2213 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2214 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2215 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2217 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2218 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2219 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2225 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2228 ModestMsgEditWindowPrivate *priv;
2229 gint new_font_index;
2230 ModestMsgEditWindow *window;
2233 window = MODEST_MSG_EDIT_WINDOW (userdata);
2234 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2235 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2237 if (gtk_check_menu_item_get_active (menu_item)) {
2240 label = gtk_bin_get_child (GTK_BIN (menu_item));
2242 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2244 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2245 GINT_TO_POINTER(new_font_index)))
2246 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2248 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2249 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2250 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2256 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2258 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2259 ModestWindowPrivate *parent_priv;
2260 ModestWindowMgr *mgr;
2261 gboolean is_fullscreen;
2262 GtkAction *fs_toggle_action;
2265 mgr = modest_runtime_get_window_mgr ();
2266 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2268 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2270 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2271 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2272 if (is_fullscreen != active)
2273 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2281 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2284 ModestMsgEditWindowPrivate *priv = NULL;
2285 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2287 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2288 if (!priv->update_caption_visibility)
2291 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2293 gtk_widget_show (priv->cc_caption);
2295 gtk_widget_hide (priv->cc_caption);
2297 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2301 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2304 ModestMsgEditWindowPrivate *priv = NULL;
2305 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2307 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2308 if (!priv->update_caption_visibility)
2311 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2313 gtk_widget_show (priv->bcc_caption);
2315 gtk_widget_hide (priv->bcc_caption);
2317 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2321 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2322 ModestRecptEditor *editor)
2324 ModestMsgEditWindowPrivate *priv;
2326 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2327 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2328 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2330 if (editor == NULL) {
2331 GtkWidget *view_focus;
2332 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2334 /* This code should be kept in sync with ModestRecptEditor. The
2335 textview inside the recpt editor is the one that really gets the
2336 focus. As it's inside a scrolled window, and this one inside the
2337 hbox recpt editor inherits from, we'll need to go up in the
2338 hierarchy to know if the text view is part of the recpt editor
2339 or if it's a different text entry */
2341 if (gtk_widget_get_parent (view_focus)) {
2342 GtkWidget *first_parent;
2344 first_parent = gtk_widget_get_parent (view_focus);
2345 if (gtk_widget_get_parent (first_parent) &&
2346 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2347 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2352 editor = MODEST_RECPT_EDITOR (priv->to_field);
2356 modest_address_book_select_addresses (editor);
2361 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2363 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2365 modest_msg_edit_window_open_addressbook (window, NULL);
2369 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2370 gboolean show_toolbar)
2372 ModestWindowPrivate *parent_priv;
2373 const gchar *action_name;
2376 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2377 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2379 /* We can not just use the code of
2380 modest_msg_edit_window_setup_toolbar because it has a
2381 mixture of both initialization and creation code. */
2383 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2385 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2387 /* Update also the actions (to update the toggles in the
2388 menus), we have to do it manually because some other window
2389 of the same time could have changed it (remember that the
2390 toolbar fullscreen mode is shared by all the windows of the
2392 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2393 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2395 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2397 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2398 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2404 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2405 TnyHeaderFlags priority_flags)
2407 ModestMsgEditWindowPrivate *priv;
2408 ModestWindowPrivate *parent_priv;
2410 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2412 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2413 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2415 if (priv->priority_flags != priority_flags) {
2416 GtkAction *priority_action = NULL;
2418 priv->priority_flags = priority_flags;
2420 switch (priority_flags) {
2421 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2422 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2423 gtk_widget_show (priv->priority_icon);
2424 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2425 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2427 case TNY_HEADER_FLAG_LOW_PRIORITY:
2428 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2429 gtk_widget_show (priv->priority_icon);
2430 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2431 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2434 gtk_widget_hide (priv->priority_icon);
2435 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2436 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2439 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2440 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2445 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2448 ModestMsgEditWindowPrivate *priv;
2449 ModestWindowPrivate *parent_priv;
2450 gint current_format;
2452 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2454 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2455 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2457 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2458 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2460 if (current_format != file_format) {
2461 switch (file_format) {
2462 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2463 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2464 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2466 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2470 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2471 response = gtk_dialog_run (GTK_DIALOG (dialog));
2472 gtk_widget_destroy (dialog);
2473 if (response == GTK_RESPONSE_OK) {
2474 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2476 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2477 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2482 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2487 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2490 ModestMsgEditWindowPrivate *priv;
2491 WPTextBufferFormat oldfmt, fmt;
2492 gint old_position = 0;
2496 GdkColor *color = NULL;
2497 gboolean bold, bold_set, italic, italic_set;
2498 gboolean underline, underline_set;
2499 gboolean strikethrough, strikethrough_set;
2500 gboolean position_set;
2501 gboolean font_size_set, font_set, color_set;
2504 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2505 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2507 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2509 /* First we get the currently selected font information */
2510 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2512 switch (oldfmt.text_position) {
2513 case TEXT_POSITION_NORMAL:
2516 case TEXT_POSITION_SUPERSCRIPT:
2524 g_object_set (G_OBJECT (dialog),
2525 "bold", oldfmt.bold != FALSE,
2526 "bold-set", !oldfmt.cs.bold,
2527 "underline", oldfmt.underline != FALSE,
2528 "underline-set", !oldfmt.cs.underline,
2529 "italic", oldfmt.italic != FALSE,
2530 "italic-set", !oldfmt.cs.italic,
2531 "strikethrough", oldfmt.strikethrough != FALSE,
2532 "strikethrough-set", !oldfmt.cs.strikethrough,
2533 "color", &oldfmt.color,
2534 "color-set", !oldfmt.cs.color,
2535 "size", wp_font_size[oldfmt.font_size],
2536 "size-set", !oldfmt.cs.font_size,
2537 "position", old_position,
2538 "position-set", !oldfmt.cs.text_position,
2539 "family", wp_get_font_name (oldfmt.font),
2540 "family-set", !oldfmt.cs.font,
2543 gtk_widget_show_all (dialog);
2544 response = gtk_dialog_run (GTK_DIALOG (dialog));
2545 if (response == GTK_RESPONSE_OK) {
2547 g_object_get( dialog,
2549 "bold-set", &bold_set,
2550 "underline", &underline,
2551 "underline-set", &underline_set,
2553 "italic-set", &italic_set,
2554 "strikethrough", &strikethrough,
2555 "strikethrough-set", &strikethrough_set,
2557 "color-set", &color_set,
2559 "size-set", &font_size_set,
2560 "family", &font_name,
2561 "family-set", &font_set,
2562 "position", &position,
2563 "position-set", &position_set,
2568 if (response == GTK_RESPONSE_OK) {
2569 memset(&fmt, 0, sizeof(fmt));
2575 fmt.italic = italic;
2576 fmt.cs.italic = TRUE;
2578 if (underline_set) {
2579 fmt.underline = underline;
2580 fmt.cs.underline = TRUE;
2582 if (strikethrough_set) {
2583 fmt.strikethrough = strikethrough;
2584 fmt.cs.strikethrough = TRUE;
2589 ? TEXT_POSITION_NORMAL
2590 : ( ( position == 1 )
2591 ? TEXT_POSITION_SUPERSCRIPT
2592 : TEXT_POSITION_SUBSCRIPT );
2593 fmt.cs.text_position = TRUE;
2594 fmt.font_size = oldfmt.font_size;
2598 fmt.cs.color = TRUE;
2601 fmt.font = wp_get_font_index(font_name,
2606 if (font_size_set) {
2607 fmt.cs.font_size = TRUE;
2608 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2610 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2611 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2613 gtk_widget_destroy (dialog);
2615 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2619 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2621 ModestMsgEditWindowPrivate *priv;
2623 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2624 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2626 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2628 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2633 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2635 ModestMsgEditWindowPrivate *priv;
2637 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2638 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2640 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2642 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2647 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2649 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2651 priv->can_undo = can_undo;
2655 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2657 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2659 priv->can_redo = can_redo;
2663 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2665 ModestMsgEditWindowPrivate *priv;
2666 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2667 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2669 return priv->can_undo;
2673 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2675 ModestMsgEditWindowPrivate *priv;
2676 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2677 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2679 return priv->can_redo;
2684 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2687 GtkTextIter match_start, match_end;
2689 if (image_id == NULL)
2692 gtk_text_buffer_get_start_iter (buffer, &iter);
2694 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2695 GSList *tags = gtk_text_iter_get_tags (&match_start);
2697 for (node = tags; node != NULL; node = g_slist_next (node)) {
2698 GtkTextTag *tag = (GtkTextTag *) node->data;
2699 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2700 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2701 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2703 offset = gtk_text_iter_get_offset (&match_start);
2704 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2705 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2709 gtk_text_iter_forward_char (&iter);
2714 message_is_empty (ModestMsgEditWindow *window)
2716 ModestMsgEditWindowPrivate *priv = NULL;
2718 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2719 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2721 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2722 * so we can ignore markup.
2724 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2727 count = gtk_text_buffer_get_char_count (buf);
2733 msg_body_focus (GtkWidget *focus,
2734 GdkEventFocus *event,
2738 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2743 recpt_field_changed (GtkTextBuffer *buffer,
2744 ModestMsgEditWindow *editor)
2746 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2750 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2752 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2756 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2758 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2759 GtkTextBuffer *buffer;
2761 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2762 gtk_text_buffer_set_modified (buffer, FALSE);
2763 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2764 gtk_text_buffer_set_modified (buffer, FALSE);
2765 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2766 gtk_text_buffer_set_modified (buffer, FALSE);
2767 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2771 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2773 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2774 GtkTextBuffer *buffer;
2776 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2777 if (gtk_text_buffer_get_modified (buffer))
2779 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2780 if (gtk_text_buffer_get_modified (buffer))
2782 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2783 if (gtk_text_buffer_get_modified (buffer))
2785 if (gtk_text_buffer_get_modified (priv->text_buffer))
2795 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2797 ModestMsgEditWindowPrivate *priv = NULL;
2799 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2800 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2802 /* check if there's no recipient added */
2803 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2804 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2805 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2806 /* no recipient contents, then select contacts */
2807 modest_msg_edit_window_open_addressbook (window, NULL);
2811 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2812 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2815 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2816 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2819 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2820 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2824 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2825 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2826 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2833 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2834 ModestMsgEditWindow *window)
2836 modest_msg_edit_window_offer_attach_file (window);
2840 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2842 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2844 return priv->clipboard_text;
2848 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2850 ModestMsgEditWindow *window)
2852 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2853 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2855 if (!GTK_WIDGET_VISIBLE (window))
2858 text = gtk_clipboard_wait_for_text (selection_clipboard);
2860 if (priv->clipboard_text != NULL) {
2861 g_free (priv->clipboard_text);
2863 priv->clipboard_text = text;
2865 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2868 subject_field_move_cursor (GtkEntry *entry,
2869 GtkMovementStep step,
2874 if (!GTK_WIDGET_VISIBLE (window))
2877 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2881 update_window_title (ModestMsgEditWindow *window)
2883 ModestMsgEditWindowPrivate *priv = NULL;
2884 const gchar *subject;
2886 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2887 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2888 if (subject == NULL || subject[0] == '\0')
2889 subject = _("mail_va_new_email");
2891 gtk_window_set_title (GTK_WINDOW (window), subject);
2896 subject_field_changed (GtkEditable *editable,
2897 ModestMsgEditWindow *window)
2899 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2900 update_window_title (window);
2901 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2902 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2906 subject_field_insert_text (GtkEditable *editable,
2908 gint new_text_length,
2910 ModestMsgEditWindow *window)
2912 GString *result = g_string_new ("");
2914 gint result_len = 0;
2915 const gchar *entry_text = NULL;
2918 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2919 old_length = g_utf8_strlen (entry_text, -1);
2921 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2922 gunichar c = g_utf8_get_char_validated (current, 8);
2923 /* Invalid unichar, stop */
2929 result = g_string_append_unichar (result, c);
2933 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2934 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2937 /* Prevent endless recursion */
2938 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2939 g_signal_emit_by_name (editable, "insert-text",
2940 (gpointer) result->str, (gpointer) result->len,
2941 (gpointer) position, (gpointer) window);
2942 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2946 if (result_len + old_length > 1000) {
2947 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2948 dgettext("hildon-common-strings",
2949 "ckdg_ib_maximum_characters_reached"));
2952 g_string_free (result, TRUE);
2956 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2959 ModestMsgEditWindowPrivate *priv = NULL;
2961 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2962 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2964 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2967 gtk_widget_show_all (priv->find_toolbar);
2968 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2970 gtk_widget_hide_all (priv->find_toolbar);
2971 gtk_widget_grab_focus (priv->msg_body);
2977 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2979 GtkTextIter *match_start,
2980 GtkTextIter *match_end)
2982 GtkTextIter end_iter;
2983 gchar *str_casefold;
2986 gchar *range_casefold;
2989 gboolean result = FALSE;
2996 gtk_text_iter_forward_to_end (&end_iter);
2998 str_casefold = g_utf8_casefold (str, -1);
2999 str_chars_n = strlen (str);
3001 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3002 range_casefold = g_utf8_casefold (range_text, -1);
3003 range_chars_n = strlen (range_casefold);
3005 if (range_chars_n < str_chars_n) {
3006 g_free (str_casefold);
3007 g_free (range_text);
3008 g_free (range_casefold);
3012 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3013 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3014 if (!g_utf8_collate (range_subtext, str_casefold)) {
3015 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3017 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3018 match_start, match_end, NULL);
3019 g_free (found_text);
3021 g_free (range_subtext);
3025 g_free (str_casefold);
3026 g_free (range_text);
3027 g_free (range_casefold);
3034 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3035 ModestMsgEditWindow *window)
3037 gchar *current_search = NULL;
3038 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3040 GtkTextIter selection_start, selection_end;
3041 GtkTextIter match_start, match_end;
3042 gboolean continue_search = FALSE;
3044 if (message_is_empty (window)) {
3045 g_free (priv->last_search);
3046 priv->last_search = NULL;
3047 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3051 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3052 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3053 g_free (current_search);
3054 g_free (priv->last_search);
3055 priv->last_search = NULL;
3056 /* Information banner about empty search */
3057 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3061 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3062 continue_search = TRUE;
3064 g_free (priv->last_search);
3065 priv->last_search = g_strdup (current_search);
3068 if (continue_search) {
3069 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3070 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3071 &match_start, &match_end);
3073 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3075 GtkTextIter buffer_start;
3076 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3077 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3078 &match_start, &match_end);
3080 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3083 /* Mark as selected the string found in search */
3085 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3086 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3088 g_free (priv->last_search);
3089 priv->last_search = NULL;
3091 g_free (current_search);
3095 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3096 ModestMsgEditWindow *window)
3098 GtkToggleAction *toggle;
3099 ModestWindowPrivate *parent_priv;
3100 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3102 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3103 gtk_toggle_action_set_active (toggle, FALSE);
3107 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3109 ModestMsgEditWindowPrivate *priv;
3111 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3116 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3119 ModestMsgEditWindowPrivate *priv;
3121 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3127 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3130 ModestMsgEditWindowPrivate *priv;
3131 TnyHeader *header = NULL;
3133 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3134 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3136 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3137 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3139 if (priv->draft_msg != NULL) {
3140 g_object_unref (priv->draft_msg);
3143 if (draft != NULL) {
3144 g_object_ref (draft);
3145 header = tny_msg_get_header (draft);
3146 if (priv->msg_uid) {
3147 g_free (priv->msg_uid);
3148 priv->msg_uid = NULL;
3150 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3151 if (GTK_WIDGET_REALIZED (window))
3152 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3155 priv->draft_msg = draft;
3159 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3160 GtkTextIter *start, GtkTextIter *end,
3163 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3164 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3167 if (tag == NULL+13) return;
3168 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3169 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3170 replace_with_images (window, priv->images);
3175 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3178 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3180 g_return_if_fail (TNY_IS_MIME_PART (part));
3181 priv->attachments = g_list_prepend (priv->attachments, part);
3182 g_object_ref (part);
3183 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3184 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3185 gtk_widget_show_all (priv->attachments_caption);
3186 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3190 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3192 ModestMsgEditWindowPrivate *priv;
3194 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3195 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3197 return priv->msg_uid;
3201 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3202 ModestMsgEditWindowWidgetType widget_type)
3204 ModestMsgEditWindowPrivate *priv;
3206 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3207 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3209 switch (widget_type) {
3210 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3211 return priv->msg_body;
3213 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3214 return priv->to_field;
3216 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3217 return priv->cc_field;
3219 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3220 return priv->bcc_field;
3222 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3223 return priv->subject_field;
3225 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3226 return priv->attachments_view;
3234 remove_tags (WPTextBuffer *buffer)
3236 GtkTextIter start, end;
3238 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3239 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3241 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3245 on_account_removed (TnyAccountStore *account_store,
3246 TnyAccount *account,
3249 /* Do nothing if it's a store account, because we use the
3250 transport to send the messages */
3251 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3252 const gchar *parent_acc = NULL;
3253 const gchar *our_acc = NULL;
3255 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3256 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3257 /* Close this window if I'm showing a message of the removed account */
3258 if (strcmp (parent_acc, our_acc) == 0)
3259 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3264 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3266 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3268 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3274 set_zoom_do_nothing (ModestWindow *window,
3280 get_zoom_do_nothing (ModestWindow *window)