1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include <modest-utils.h>
79 #include "modest-maemo-utils.h"
82 #define DEFAULT_FONT_SIZE 3
83 #define DEFAULT_FONT 2
84 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
85 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
86 #define DEFAULT_MAIN_VBOX_SPACING 6
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #define DEFAULT_FONT_SCALE 1.5
91 static gboolean is_wp_text_buffer_started = FALSE;
93 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
94 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
95 static void modest_msg_edit_window_finalize (GObject *obj);
97 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
98 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
99 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
101 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
102 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
103 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
104 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
105 GtkTextIter *start, GtkTextIter *end,
107 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
108 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
109 static void subject_field_insert_text (GtkEditable *editable,
111 gint new_text_length,
113 ModestMsgEditWindow *window);
114 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
116 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
118 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
121 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
122 GdkEventWindowState *event,
124 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
125 ModestRecptEditor *editor);
126 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
127 ModestMsgEditWindow *window);
129 /* ModestWindow methods implementation */
130 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
131 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
132 gboolean show_toolbar);
133 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
135 ModestMsgEditWindow *window);
136 static void subject_field_move_cursor (GtkEntry *entry,
137 GtkMovementStep step,
141 static void update_window_title (ModestMsgEditWindow *window);
144 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
145 ModestMsgEditWindow *window);
146 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
147 ModestMsgEditWindow *window);
148 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
150 GtkTextIter *match_start,
151 GtkTextIter *match_end);
153 static void remove_tags (WPTextBuffer *buffer);
155 static void on_account_removed (TnyAccountStore *account_store,
159 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
161 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
163 static gdouble get_zoom_do_nothing (ModestWindow *window);
165 static void init_window (ModestMsgEditWindow *obj);
167 static void DEBUG_BUFFER (WPTextBuffer *buffer)
171 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
173 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
174 while (!gtk_text_iter_is_end (&iter)) {
175 GString *output = g_string_new ("");
176 GSList *toggled_tags;
179 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
180 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
181 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
182 GtkTextTag *tag = (GtkTextTag *) node->data;
184 g_object_get (G_OBJECT (tag), "name", &name, NULL);
185 output = g_string_append (output, name);
186 g_string_append (output, " ");
188 output = g_string_append (output, "] OPENED [ ");
189 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
190 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
191 GtkTextTag *tag = (GtkTextTag *) node->data;
193 g_object_get (G_OBJECT (tag), "name", &name, NULL);
194 output = g_string_append (output, name);
195 g_string_append (output, " ");
197 output = g_string_append (output, "]\n");
198 g_message ("%s", output->str);
199 g_string_free (output, TRUE);
200 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
202 g_message ("END BUFFER");
207 /* static gboolean */
208 /* on_key_pressed (GtkWidget *self, */
209 /* GdkEventKey *event, */
210 /* gpointer user_data); */
212 /* list my signals */
219 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
220 struct _ModestMsgEditWindowPrivate {
222 GtkWidget *header_box;
224 ModestPairList *from_field_protos;
225 GtkWidget *from_field;
229 GtkWidget *bcc_field;
230 GtkWidget *subject_field;
231 GtkWidget *attachments_view;
232 GtkWidget *priority_icon;
233 GtkWidget *add_attachment_button;
235 GtkWidget *cc_caption;
236 GtkWidget *bcc_caption;
237 gboolean update_caption_visibility;
238 GtkWidget *attachments_caption;
240 GtkTextBuffer *text_buffer;
242 GtkWidget *font_size_toolitem;
243 GtkWidget *font_face_toolitem;
244 GtkWidget *font_color_button;
245 GSList *font_items_group;
246 GtkWidget *font_tool_button_label;
247 GSList *size_items_group;
248 GtkWidget *size_tool_button_label;
250 GtkWidget *find_toolbar;
254 GtkWidget *scroll_area;
255 gint last_vadj_upper;
261 TnyHeaderFlags priority_flags;
263 gboolean can_undo, can_redo;
264 gulong clipboard_change_handler_id;
265 gulong default_clipboard_change_handler_id;
266 gulong account_removed_handler_id;
267 gchar *clipboard_text;
276 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
277 MODEST_TYPE_MSG_EDIT_WINDOW, \
278 ModestMsgEditWindowPrivate))
280 static GtkWindowClass *parent_class = NULL;
282 /* uncomment the following if you have defined any signals */
283 /* static guint signals[LAST_SIGNAL] = {0}; */
286 modest_msg_edit_window_get_type (void)
288 static GType my_type = 0;
290 static const GTypeInfo my_info = {
291 sizeof(ModestMsgEditWindowClass),
292 NULL, /* base init */
293 NULL, /* base finalize */
294 (GClassInitFunc) modest_msg_edit_window_class_init,
295 NULL, /* class finalize */
296 NULL, /* class data */
297 sizeof(ModestMsgEditWindow),
299 (GInstanceInitFunc) modest_msg_edit_window_init,
302 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
303 "ModestMsgEditWindow",
311 save_state (ModestWindow *self)
313 modest_widget_memory_save (modest_runtime_get_conf(),
314 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
319 restore_settings (ModestMsgEditWindow *self)
321 ModestConf *conf = NULL;
323 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
325 conf = modest_runtime_get_conf ();
326 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
327 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
328 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
329 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
330 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
331 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
332 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
333 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
335 /* set initial state of cc and bcc */
336 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
337 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
338 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
339 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
340 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
341 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
343 /* Dim at start clipboard actions */
344 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
345 gtk_action_set_sensitive (action, FALSE);
346 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
347 gtk_action_set_sensitive (action, FALSE);
348 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
349 gtk_action_set_sensitive (action, FALSE);
351 modest_widget_memory_restore (conf,
352 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
357 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
359 GObjectClass *gobject_class;
360 ModestWindowClass *modest_window_class;
361 gobject_class = (GObjectClass*) klass;
362 modest_window_class = (ModestWindowClass*) klass;
364 parent_class = g_type_class_peek_parent (klass);
365 gobject_class->finalize = modest_msg_edit_window_finalize;
367 modest_window_class->set_zoom_func = set_zoom_do_nothing;
368 modest_window_class->get_zoom_func = get_zoom_do_nothing;
369 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
370 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
371 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
372 modest_window_class->save_state_func = save_state;
373 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
375 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
379 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
381 ModestMsgEditWindowPrivate *priv;
382 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
384 priv->msg_body = NULL;
385 priv->from_field = NULL;
386 priv->to_field = NULL;
387 priv->cc_field = NULL;
388 priv->bcc_field = NULL;
389 priv->subject_field = NULL;
390 priv->attachments = NULL;
394 priv->cc_caption = NULL;
395 priv->bcc_caption = NULL;
396 priv->update_caption_visibility = FALSE;
398 priv->priority_flags = 0;
400 priv->find_toolbar = NULL;
401 priv->last_search = NULL;
403 priv->draft_msg = NULL;
404 priv->outbox_msg = NULL;
405 priv->msg_uid = NULL;
407 priv->can_undo = FALSE;
408 priv->can_redo = FALSE;
409 priv->clipboard_change_handler_id = 0;
410 priv->default_clipboard_change_handler_id = 0;
411 priv->account_removed_handler_id = 0;
412 priv->clipboard_text = NULL;
415 priv->last_vadj_upper = 0;
417 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
418 GTK_WINDOW(obj),"applications_email_editor");
420 if (!is_wp_text_buffer_started) {
421 is_wp_text_buffer_started = TRUE;
422 wp_text_buffer_library_init ();
427 hildon_program_add_window (hildon_program_get_instance(),
432 /* FIXME: this is a dup from the one in gtk/ */
435 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
437 static ModestPairList*
438 get_transports (void)
440 GSList *transports = NULL;
442 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
443 GSList *accounts = modest_account_mgr_account_names (account_mgr,
444 TRUE /* only enabled accounts. */);
446 GSList *cursor = accounts;
448 gchar *account_name = cursor->data;
449 gchar *from_string = NULL;
451 from_string = modest_account_mgr_get_from_string (account_mgr,
455 if (from_string && account_name) {
456 gchar *name = account_name;
457 ModestPair *pair = modest_pair_new ((gpointer) name,
458 (gpointer) from_string , TRUE);
459 transports = g_slist_prepend (transports, pair);
462 cursor = cursor->next;
464 g_slist_free (accounts); /* only free the accounts, not the elements,
465 * because they are used in the pairlist */
469 void vadj_changed (GtkAdjustment *adj,
470 ModestMsgEditWindow *window)
472 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
474 GdkRectangle rectangle, cursor_rectangle;
475 GtkTextIter position;
479 /* We detect if cursor is visible using the full height, not only the center. This
481 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
482 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
484 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
485 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
487 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
488 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
490 if (gtk_widget_is_focus (priv->msg_body) &&
492 if (priv->last_vadj_upper != adj->upper) {
495 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
496 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
497 insert, 0.1, FALSE, 0.0, 0.0);
500 priv->last_vadj_upper = adj->upper;
505 connect_signals (ModestMsgEditWindow *obj)
507 ModestMsgEditWindowPrivate *priv;
509 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
511 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
512 G_CALLBACK (text_buffer_refresh_attributes), obj);
513 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
514 G_CALLBACK (text_buffer_can_undo), obj);
515 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
516 G_CALLBACK (text_buffer_can_redo), obj);
517 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
518 G_CALLBACK (body_changed), obj);
519 g_signal_connect (G_OBJECT (obj), "window-state-event",
520 G_CALLBACK (modest_msg_edit_window_window_state_event),
522 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
523 G_CALLBACK (text_buffer_apply_tag), obj);
524 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
525 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
526 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
527 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
528 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
529 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
531 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
532 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
534 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
535 G_CALLBACK (msg_body_focus), obj);
536 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
537 G_CALLBACK (msg_body_focus), obj);
538 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
539 "changed", G_CALLBACK (recpt_field_changed), obj);
540 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
541 "changed", G_CALLBACK (recpt_field_changed), obj);
542 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
543 "changed", G_CALLBACK (recpt_field_changed), obj);
544 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
545 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
546 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
548 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
549 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
551 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
553 G_CALLBACK (vadj_changed),
556 priv->clipboard_change_handler_id =
557 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
558 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
559 priv->default_clipboard_change_handler_id =
560 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
561 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
566 menubar_to_menu (GtkUIManager *ui_manager)
568 GtkWidget *main_menu;
570 /* Get the menubar from the UI manager */
571 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
577 init_window (ModestMsgEditWindow *obj)
579 GtkWidget *from_caption, *to_caption, *subject_caption;
580 GtkWidget *main_vbox;
581 ModestMsgEditWindowPrivate *priv;
582 GtkActionGroup *action_group;
583 ModestWindowPrivate *parent_priv;
584 GdkPixbuf *window_icon = NULL;
585 GError *error = NULL;
587 GtkSizeGroup *size_group;
589 GtkWidget *subject_box;
590 GtkWidget *attachment_icon;
591 GtkWidget *window_box;
592 #if (GTK_MINOR_VERSION >= 10)
593 GdkAtom deserialize_type;
595 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
596 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
598 parent_priv->ui_manager = gtk_ui_manager_new();
599 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
600 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
602 /* Add common actions */
603 gtk_action_group_add_actions (action_group,
604 modest_msg_edit_action_entries,
605 G_N_ELEMENTS (modest_msg_edit_action_entries),
607 gtk_action_group_add_toggle_actions (action_group,
608 modest_msg_edit_toggle_action_entries,
609 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
611 gtk_action_group_add_radio_actions (action_group,
612 modest_msg_edit_alignment_radio_action_entries,
613 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
615 G_CALLBACK (modest_ui_actions_on_change_justify),
617 gtk_action_group_add_radio_actions (action_group,
618 modest_msg_edit_priority_action_entries,
619 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
621 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
623 gtk_action_group_add_radio_actions (action_group,
624 modest_msg_edit_file_format_action_entries,
625 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
626 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
627 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
629 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
630 g_object_unref (action_group);
632 /* Load the UI definition */
633 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
636 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
637 g_clear_error (&error);
640 /* Add accelerators */
641 gtk_window_add_accel_group (GTK_WINDOW (obj),
642 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
644 parent_priv->menubar = NULL;
646 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
648 /* Note: This ModestPairList* must exist for as long as the combo
649 * that uses it, because the ModestComboBox uses the ID opaquely,
650 * so it can't know how to manage its memory. */
651 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
653 priv->to_field = modest_recpt_editor_new ();
654 priv->cc_field = modest_recpt_editor_new ();
655 priv->bcc_field = modest_recpt_editor_new ();
656 subject_box = gtk_hbox_new (FALSE, 0);
657 priv->priority_icon = gtk_image_new ();
658 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
659 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
660 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
661 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
662 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
663 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
664 priv->add_attachment_button = gtk_button_new ();
665 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
666 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
667 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
668 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
669 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
670 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
671 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
672 priv->attachments_view = modest_attachments_view_new (NULL);
674 priv->header_box = gtk_vbox_new (FALSE, 0);
676 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
677 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
678 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
679 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
680 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
681 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
682 g_object_unref (size_group);
684 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
685 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
686 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
687 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
688 gtk_size_group_add_widget (size_group, priv->subject_field);
689 gtk_size_group_add_widget (size_group, priv->attachments_view);
690 g_object_unref (size_group);
692 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
694 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
695 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
696 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
697 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
698 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
701 priv->msg_body = wp_text_view_new ();
702 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
703 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
704 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
705 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
706 #if (GTK_MINOR_VERSION >= 10)
707 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
708 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
710 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
711 deserialize_type, TRUE);
713 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
715 priv->find_toolbar = hildon_find_toolbar_new (NULL);
716 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
718 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
720 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
721 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
722 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
723 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
725 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
727 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
728 frame = gtk_frame_new (NULL);
729 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
731 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
732 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
733 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
735 G_CALLBACK (vadj_changed),
737 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
739 window_box = gtk_vbox_new (FALSE, 0);
740 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
741 gtk_container_add (GTK_CONTAINER(obj), window_box);
742 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
743 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
745 /* Set window icon */
746 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
748 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
749 g_object_unref (window_icon);
754 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
756 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
758 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
759 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
760 priv->clipboard_change_handler_id))
761 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
762 priv->clipboard_change_handler_id);
763 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
764 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
765 priv->default_clipboard_change_handler_id))
766 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
767 priv->default_clipboard_change_handler_id);
769 if (priv->account_removed_handler_id &&
770 g_signal_handler_is_connected (modest_runtime_get_account_store (),
771 priv->account_removed_handler_id))
772 g_signal_handler_disconnect(modest_runtime_get_account_store (),
773 priv->account_removed_handler_id);
777 modest_msg_edit_window_finalize (GObject *obj)
779 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
781 /* Sanity check: shouldn't be needed, the window mgr should
782 call this function before */
783 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
785 if (priv->clipboard_text != NULL) {
786 g_free (priv->clipboard_text);
787 priv->clipboard_text = NULL;
790 if (priv->draft_msg != NULL) {
791 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
792 if (TNY_IS_HEADER (header)) {
793 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
794 modest_window_mgr_unregister_header (mgr, header);
796 g_object_unref (priv->draft_msg);
797 priv->draft_msg = NULL;
799 if (priv->outbox_msg != NULL) {
800 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
801 if (TNY_IS_HEADER (header)) {
802 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
803 modest_window_mgr_unregister_header (mgr, header);
805 g_object_unref (priv->outbox_msg);
806 priv->outbox_msg = NULL;
808 g_free (priv->msg_uid);
809 g_free (priv->last_search);
810 g_slist_free (priv->font_items_group);
811 g_slist_free (priv->size_items_group);
812 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
813 g_list_free (priv->attachments);
814 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
815 g_list_free (priv->images);
817 /* This had to stay alive for as long as the combobox that used it: */
818 modest_pair_list_free (priv->from_field_protos);
820 G_OBJECT_CLASS(parent_class)->finalize (obj);
824 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
826 GdkPixbufLoader *loader;
829 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
834 tny_stream_reset (TNY_STREAM (stream));
835 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
836 unsigned char read_buffer[128];
838 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
839 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
843 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
844 g_object_ref (pixbuf);
845 gdk_pixbuf_loader_close (loader, NULL);
846 g_object_unref (loader);
848 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
849 GdkPixbuf *new_pixbuf;
851 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
852 gdk_pixbuf_get_width (pixbuf);
853 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
854 g_object_unref (pixbuf);
862 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
864 ModestMsgEditWindowPrivate *priv;
867 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
869 for (node = attachments; node != NULL; node = g_list_next (node)) {
870 TnyMimePart *part = (TnyMimePart *) node->data;
871 const gchar *cid = tny_mime_part_get_content_id (part);
872 const gchar *mime_type = tny_mime_part_get_content_type (part);
873 if ((cid != NULL)&&(mime_type != NULL)) {
874 TnyStream *stream = tny_mime_part_get_stream (part);
875 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
876 g_object_unref (stream);
878 if (pixbuf != NULL) {
879 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
880 g_object_unref (pixbuf);
887 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
889 TnyMimePart *parent = NULL;
890 const gchar *content_type = NULL;
891 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
893 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
895 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
896 parent = g_object_ref (msg);
897 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
898 TnyList *parts = TNY_LIST (tny_simple_list_new ());
901 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
902 iter = tny_list_create_iterator (parts);
903 while (!tny_iterator_is_done (iter)) {
905 part = TNY_MIME_PART (tny_iterator_get_current (iter));
906 content_type = tny_mime_part_get_content_type (part);
907 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
911 g_object_unref (part);
913 tny_iterator_next (iter);
915 g_object_unref (iter);
916 g_object_unref (parts);
919 if (parent != NULL) {
920 TnyList *parts = TNY_LIST (tny_simple_list_new ());
923 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
924 iter = tny_list_create_iterator (parts);
925 while (!tny_iterator_is_done (iter)) {
927 part = TNY_MIME_PART (tny_iterator_get_current (iter));
928 content_type = tny_mime_part_get_content_type (part);
929 if (content_type && g_str_has_prefix (content_type, "image/")) {
930 priv->images = g_list_prepend (priv->images, part);
932 g_object_unref (part);
934 tny_iterator_next (iter);
936 g_object_unref (iter);
937 g_object_unref (parts);
938 g_object_unref (parent);
943 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
946 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
948 for (node = attachments; node != NULL; node = g_list_next (node)) {
949 TnyMimePart *part = (TnyMimePart *) node->data;
950 const gchar *cid = tny_mime_part_get_content_id (part);
952 char *invalid = NULL;
953 gint int_cid = strtol (cid, &invalid, 10);
954 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
955 priv->last_cid = int_cid;
963 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
966 const gchar *to, *cc, *bcc, *subject;
968 ModestMsgEditWindowPrivate *priv;
970 TnyHeaderFlags priority_flags;
971 TnyFolder *msg_folder;
972 gboolean is_html = FALSE;
974 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
975 g_return_if_fail (TNY_IS_MSG (msg));
977 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
979 header = tny_msg_get_header (msg);
980 to = tny_header_get_to (header);
981 cc = tny_header_get_cc (header);
982 bcc = tny_header_get_bcc (header);
983 subject = tny_header_get_subject (header);
984 priority_flags = tny_header_get_priority (header);
987 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
989 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
990 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
991 gtk_widget_show (priv->cc_caption);
992 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
993 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
994 gtk_widget_hide (priv->cc_caption);
997 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
998 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
999 gtk_widget_show (priv->bcc_caption);
1000 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1001 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1002 gtk_widget_hide (priv->bcc_caption);
1005 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1006 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1009 update_window_title (self);
1011 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1012 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1014 if ((body == NULL)||(body[0] == '\0')) {
1016 body = modest_text_utils_convert_to_html ("");
1019 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1020 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1023 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1026 /* Add attachments to the view */
1027 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1028 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1029 if (priv->attachments == NULL) {
1030 gtk_widget_hide (priv->attachments_caption);
1032 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1033 gtk_widget_show_all (priv->attachments_caption);
1035 get_related_images (self, msg);
1036 update_last_cid (self, priv->attachments);
1037 update_last_cid (self, priv->images);
1038 replace_with_images (self, priv->images);
1040 if (preserve_is_rich && !is_html) {
1041 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1042 /* Get the default format required from configuration */
1043 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1044 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1047 /* Set the default focus depending on having already a To: field or not */
1048 if ((!to)||(*to == '\0')) {
1049 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1051 gtk_widget_grab_focus (priv->msg_body);
1054 /* TODO: lower priority, select in the From: combo to the
1055 value that comes from msg <- not sure, should it be
1058 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1060 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1061 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1063 modest_msg_edit_window_reset_modified (self);
1065 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1066 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1067 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1069 if (priv->msg_uid) {
1070 g_free (priv->msg_uid);
1071 priv->msg_uid = NULL;
1074 /* we should set a reference to the incoming message if it is a draft */
1075 msg_folder = tny_msg_get_folder (msg);
1077 if (modest_tny_folder_is_local_folder (msg_folder)) {
1078 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1079 if (type == TNY_FOLDER_TYPE_INVALID)
1080 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1082 if (type == TNY_FOLDER_TYPE_DRAFTS)
1083 priv->draft_msg = g_object_ref(msg);
1084 if (type == TNY_FOLDER_TYPE_OUTBOX)
1085 priv->outbox_msg = g_object_ref(msg);
1086 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1088 g_object_unref (msg_folder);
1093 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1096 GList *item_children, *node;
1097 GtkWidget *bin_child;
1099 bin_child = gtk_bin_get_child (GTK_BIN(item));
1101 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1103 for (node = item_children; node != NULL; node = g_list_next (node)) {
1104 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1105 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1108 g_list_free (item_children);
1112 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1115 GList *item_children, *node;
1117 box = gtk_bin_get_child (GTK_BIN (item));
1118 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1119 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1121 for (node = item_children; node != NULL; node = g_list_next (node)) {
1122 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1123 if (GTK_IS_TOGGLE_BUTTON (node->data))
1124 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1125 else if (GTK_IS_BUTTON (node->data))
1126 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1128 g_list_free (item_children);
1133 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1135 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1136 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1137 GtkWidget *placeholder;
1138 GtkWidget *tool_item;
1143 GtkWidget *sizes_menu;
1144 GtkWidget *fonts_menu;
1145 GSList *radio_group = NULL;
1146 GSList *node = NULL;
1150 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1151 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1153 /* Font color placeholder */
1154 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1155 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1158 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1159 priv->font_color_button = hildon_color_button_new ();
1160 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1161 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1162 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1163 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1164 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1165 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1166 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1168 G_CALLBACK (modest_msg_edit_window_color_button_change),
1171 /* Font size and face placeholder */
1172 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1173 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1175 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1176 priv->size_tool_button_label = gtk_label_new (NULL);
1177 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1178 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1179 size_text,"</span>", NULL);
1180 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1182 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1183 sizes_menu = gtk_menu_new ();
1184 priv->size_items_group = NULL;
1186 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1187 GtkWidget *size_menu_item;
1189 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1190 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1191 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1192 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1193 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1194 gtk_widget_show (size_menu_item);
1196 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1200 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1201 GtkWidget *item = (GtkWidget *) node->data;
1202 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1206 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1207 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1208 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1209 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1210 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1211 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1212 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1213 priv->font_size_toolitem = tool_item;
1216 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1217 priv->font_tool_button_label = gtk_label_new (NULL);
1218 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1219 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1221 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1222 fonts_menu = gtk_menu_new ();
1223 priv->font_items_group = NULL;
1225 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1226 GtkWidget *font_menu_item;
1227 GtkWidget *child_label;
1229 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1230 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1231 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1232 wp_get_font_name (font_index), "</span>", NULL);
1233 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1236 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1237 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1238 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1239 gtk_widget_show (font_menu_item);
1241 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1244 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1245 GtkWidget *item = (GtkWidget *) node->data;
1246 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1249 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1250 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1251 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1252 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1253 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1254 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1255 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1256 priv->font_face_toolitem = tool_item;
1258 /* Set expand and homogeneous for remaining items */
1259 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1260 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1261 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1262 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1263 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1264 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1265 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1266 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1267 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1269 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1270 will not show the tool items added to the placeholders) */
1271 gtk_widget_show_all (parent_priv->toolbar);
1273 /* Set the no show all *after* showing all items. We do not
1274 want the toolbar to be shown with a show all because it
1275 could go agains the gconf setting regarding showing or not
1276 the toolbar of the editor window */
1277 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1283 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1286 ModestWindowPrivate *parent_priv;
1287 ModestMsgEditWindowPrivate *priv;
1288 ModestPair *account_pair = NULL;
1289 ModestDimmingRulesGroup *menu_rules_group = NULL;
1290 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1291 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1292 ModestWindowMgr *mgr = NULL;
1294 g_return_val_if_fail (msg, NULL);
1295 g_return_val_if_fail (account_name, NULL);
1297 mgr = modest_runtime_get_window_mgr ();
1299 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1301 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1302 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1304 /* Menubar. Update the state of some toggles */
1305 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1306 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1307 priv->from_field_protos = get_transports ();
1308 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1309 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1310 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1313 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1315 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1317 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1319 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1320 if (account_pair != NULL)
1321 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1323 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1324 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1325 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1326 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1327 /* Add common dimming rules */
1328 modest_dimming_rules_group_add_rules (menu_rules_group,
1329 modest_msg_edit_window_menu_dimming_entries,
1330 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1331 MODEST_WINDOW (obj));
1332 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1333 modest_msg_edit_window_toolbar_dimming_entries,
1334 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1335 MODEST_WINDOW (obj));
1336 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1337 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1338 MODEST_WINDOW (obj));
1339 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1340 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1341 MODEST_WINDOW (obj));
1342 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1343 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1344 MODEST_WINDOW (obj));
1345 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1346 modest_msg_edit_window_clipboard_dimming_entries,
1347 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1348 MODEST_WINDOW (obj));
1349 /* Insert dimming rules group for this window */
1350 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1351 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1352 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1353 /* Checks the dimming rules */
1354 g_object_unref (menu_rules_group);
1355 g_object_unref (toolbar_rules_group);
1356 g_object_unref (clipboard_rules_group);
1358 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1360 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1362 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1363 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1364 priv->update_caption_visibility = TRUE;
1366 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1368 /* Track account-removed signal, this window should be closed
1369 in the case we're creating a mail associated to the account
1371 priv->account_removed_handler_id =
1372 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1374 G_CALLBACK(on_account_removed),
1377 return (ModestWindow*) obj;
1381 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1383 GString **string_buffer = (GString **) user_data;
1385 *string_buffer = g_string_append (*string_buffer, buffer);
1391 * @result: A new string which should be freed with g_free().
1394 get_formatted_data (ModestMsgEditWindow *edit_window)
1396 ModestMsgEditWindowPrivate *priv;
1397 GString *string_buffer = g_string_new ("");
1399 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1401 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1403 return g_string_free (string_buffer, FALSE);
1408 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1411 const gchar *account_name;
1412 ModestMsgEditWindowPrivate *priv;
1414 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1416 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1418 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1419 g_return_val_if_fail (account_name, NULL);
1422 /* don't free these (except from) */
1423 data = g_slice_new0 (MsgData);
1424 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1426 data->account_name = g_strdup (account_name);
1427 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1428 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1429 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1430 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1431 if (priv->draft_msg) {
1432 data->draft_msg = g_object_ref (priv->draft_msg);
1433 } else if (priv->outbox_msg) {
1434 data->draft_msg = g_object_ref (priv->outbox_msg);
1436 data->draft_msg = NULL;
1439 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1441 gtk_text_buffer_get_bounds (buf, &b, &e);
1442 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1444 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1445 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1447 data->html_body = NULL;
1449 /* deep-copy the data */
1450 GList *cursor = priv->attachments;
1451 data->attachments = NULL;
1453 if (!(TNY_IS_MIME_PART(cursor->data))) {
1454 g_warning ("strange data in attachment list");
1455 cursor = g_list_next (cursor);
1458 data->attachments = g_list_append (data->attachments,
1459 g_object_ref (cursor->data));
1460 cursor = g_list_next (cursor);
1463 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1464 cursor = priv->images;
1465 data->images = NULL;
1468 if (!(TNY_IS_MIME_PART(cursor->data))) {
1469 g_warning ("strange data in attachment list");
1470 cursor = g_list_next (cursor);
1473 cid = tny_mime_part_get_content_id (cursor->data);
1475 gchar *image_tag_id;
1476 GtkTextTag *image_tag;
1478 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1479 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1480 g_free (image_tag_id);
1482 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1484 ((gtk_text_iter_has_tag (&iter, image_tag))||
1485 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1486 data->images = g_list_append (data->images,
1487 g_object_ref (cursor->data));
1489 cursor = g_list_next (cursor);
1492 data->priority_flags = priv->priority_flags;
1499 unref_gobject (GObject *obj, gpointer data)
1501 if (!G_IS_OBJECT(obj))
1503 g_object_unref (obj);
1507 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1510 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1518 g_free (data->from);
1519 g_free (data->subject);
1520 g_free (data->plain_body);
1521 g_free (data->html_body);
1522 g_free (data->account_name);
1524 if (data->draft_msg != NULL) {
1525 g_object_unref (data->draft_msg);
1526 data->draft_msg = NULL;
1529 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1530 g_list_free (data->attachments);
1531 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1532 g_list_free (data->images);
1534 g_slice_free (MsgData, data);
1538 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1541 ModestMsgEditWindowPrivate *priv = NULL;
1542 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1544 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1546 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1548 return MODEST_MSG_EDIT_FORMAT_HTML;
1550 return MODEST_MSG_EDIT_FORMAT_TEXT;
1554 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1555 ModestMsgEditFormat format)
1557 ModestMsgEditWindowPrivate *priv;
1559 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1560 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1563 case MODEST_MSG_EDIT_FORMAT_HTML:
1564 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1566 case MODEST_MSG_EDIT_FORMAT_TEXT:
1567 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1570 g_return_if_reached ();
1574 ModestMsgEditFormatState *
1575 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1577 ModestMsgEditFormatState *format_state = NULL;
1578 ModestMsgEditWindowPrivate *priv;
1579 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1581 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1582 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1584 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1586 format_state = g_new0 (ModestMsgEditFormatState, 1);
1587 format_state->bold = buffer_format->bold&0x1;
1588 format_state->italics = buffer_format->italic&0x1;
1589 format_state->bullet = buffer_format->bullet&0x1;
1590 format_state->color = buffer_format->color;
1591 format_state->font_size = buffer_format->font_size;
1592 format_state->font_family = wp_get_font_name (buffer_format->font);
1593 format_state->justification = buffer_format->justification;
1594 g_free (buffer_format);
1596 return format_state;
1601 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1602 const ModestMsgEditFormatState *format_state)
1604 ModestMsgEditWindowPrivate *priv;
1605 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1606 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1607 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1608 g_return_if_fail (format_state != NULL);
1610 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1611 gtk_widget_grab_focus (priv->msg_body);
1612 buffer_format->bold = (format_state->bold != FALSE);
1613 buffer_format->italic = (format_state->italics != FALSE);
1614 buffer_format->color = format_state->color;
1615 buffer_format->font_size = format_state->font_size;
1616 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1617 buffer_format->justification = format_state->justification;
1618 buffer_format->bullet = format_state->bullet;
1620 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1622 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1623 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1624 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1625 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1626 buffer_format->cs.font = (buffer_format->font != current_format->font);
1627 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1628 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1630 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1631 if (buffer_format->cs.bold) {
1632 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1633 GINT_TO_POINTER (buffer_format->bold&0x1));
1635 if (buffer_format->cs.italic) {
1636 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1637 GINT_TO_POINTER (buffer_format->italic&0x1));
1639 if (buffer_format->cs.color) {
1640 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1641 GINT_TO_POINTER (&(buffer_format->color)));
1643 if (buffer_format->cs.font_size) {
1644 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1645 GINT_TO_POINTER (buffer_format->font_size));
1647 if (buffer_format->cs.justification) {
1648 switch (buffer_format->justification) {
1649 case GTK_JUSTIFY_LEFT:
1650 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1651 GINT_TO_POINTER(TRUE));
1653 case GTK_JUSTIFY_CENTER:
1654 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1655 GINT_TO_POINTER(TRUE));
1657 case GTK_JUSTIFY_RIGHT:
1658 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1659 GINT_TO_POINTER(TRUE));
1666 if (buffer_format->cs.font) {
1667 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1668 GINT_TO_POINTER (buffer_format->font));
1670 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1671 if (buffer_format->cs.bullet) {
1672 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1673 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1675 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1677 g_free (current_format);
1682 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1684 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1686 ModestWindowPrivate *parent_priv;
1687 ModestMsgEditWindowPrivate *priv;
1688 GtkWidget *new_size_menuitem;
1689 GtkWidget *new_font_menuitem;
1691 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1692 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1694 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1695 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1696 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1697 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1699 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1700 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1701 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1704 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1706 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1707 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1709 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1710 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1712 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1713 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1715 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1716 G_CALLBACK (modest_msg_edit_window_color_button_change),
1718 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1719 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1720 G_CALLBACK (modest_msg_edit_window_color_button_change),
1723 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1724 buffer_format->font_size))->data);
1725 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1729 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1730 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1731 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1733 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1734 G_CALLBACK (modest_msg_edit_window_size_change),
1736 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1737 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1738 G_CALLBACK (modest_msg_edit_window_size_change),
1742 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1743 buffer_format->font))->data);
1744 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1748 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1749 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1750 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1752 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1753 G_CALLBACK (modest_msg_edit_window_font_change),
1755 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1756 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1757 G_CALLBACK (modest_msg_edit_window_font_change),
1761 g_free (buffer_format);
1765 #ifdef MODEST_HILDON_VERSION_0
1767 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1770 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1771 ModestMsgEditWindowPrivate *priv;
1772 GtkWidget *dialog = NULL;
1774 GdkColor *new_color = NULL;
1776 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1777 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1779 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1780 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1781 g_free (buffer_format);
1783 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1784 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1785 if (new_color != NULL) {
1786 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1787 (gpointer) new_color);
1790 gtk_widget_destroy (dialog);
1795 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1798 ModestMsgEditWindowPrivate *priv;
1799 GtkWidget *dialog = NULL;
1801 GdkColor *old_color = NULL;
1802 const GdkColor *new_color = NULL;
1804 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1805 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1807 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1808 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1810 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1811 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1812 if (new_color != NULL)
1813 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1815 gtk_widget_destroy (dialog);
1821 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1824 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1825 ModestMsgEditWindowPrivate *priv;
1826 GtkWidget *dialog = NULL;
1828 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1829 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1831 dialog = hildon_color_chooser_new ();
1832 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1833 g_free (buffer_format);
1835 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1837 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1838 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1841 gtk_widget_destroy (dialog);
1846 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1849 ModestMsgEditWindowPrivate *priv;
1850 GtkWidget *dialog = NULL;
1851 GdkColor *old_color = NULL;
1853 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1854 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1856 dialog = hildon_color_chooser_new ();
1857 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1859 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1861 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1862 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1864 gtk_widget_destroy (dialog);
1867 #endif /*!MODEST_HILDON_VERSION_0*/
1871 static TnyStream* create_stream_for_uri (const gchar* uri)
1876 TnyStream *result = NULL;
1878 GnomeVFSHandle *handle = NULL;
1879 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1880 if (test == GNOME_VFS_OK) {
1881 /* Create the tinymail stream: */
1882 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1883 result = TNY_STREAM (tny_vfs_stream_new (handle));
1890 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1893 ModestMsgEditWindowPrivate *priv;
1894 GtkWidget *dialog = NULL;
1896 GSList *uris = NULL;
1897 GSList *uri_node = NULL;
1899 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1901 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1902 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1903 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1905 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1907 response = gtk_dialog_run (GTK_DIALOG (dialog));
1909 case GTK_RESPONSE_OK:
1910 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1915 gtk_widget_destroy (dialog);
1917 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1919 GnomeVFSHandle *handle = NULL;
1920 GnomeVFSResult result;
1921 GtkTextIter position;
1922 GtkTextMark *insert_mark;
1924 uri = (const gchar *) uri_node->data;
1925 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1926 if (result == GNOME_VFS_OK) {
1928 GnomeVFSFileInfo info;
1929 gchar *filename, *basename, *escaped_filename;
1930 TnyMimePart *mime_part;
1932 const gchar *mime_type = NULL;
1933 GnomeVFSURI *vfs_uri;
1935 vfs_uri = gnome_vfs_uri_new (uri);
1937 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1938 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1939 g_free (escaped_filename);
1940 gnome_vfs_uri_unref (vfs_uri);
1942 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1943 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1945 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1947 mime_part = tny_platform_factory_new_mime_part
1948 (modest_runtime_get_platform_factory ());
1950 TnyStream *stream = create_stream_for_uri (uri);
1951 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1953 content_id = g_strdup_printf ("%d", priv->last_cid);
1954 tny_mime_part_set_content_id (mime_part, content_id);
1955 g_free (content_id);
1958 basename = g_path_get_basename (filename);
1959 tny_mime_part_set_filename (mime_part, basename);
1962 pixbuf = pixbuf_from_stream (stream, mime_type);
1964 if (pixbuf != NULL) {
1965 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1966 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1967 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1970 priv->images = g_list_prepend (priv->images, mime_part);
1971 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1981 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1983 GtkWidget *dialog = NULL;
1985 GSList *uris = NULL;
1988 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1989 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1990 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1992 response = gtk_dialog_run (GTK_DIALOG (dialog));
1994 case GTK_RESPONSE_OK:
1995 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2000 gtk_widget_destroy (dialog);
2002 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2003 const gchar *uri = (const gchar *) uri_node->data;
2004 modest_msg_edit_window_attach_file_one (window, uri);
2006 g_slist_foreach (uris, (GFunc) g_free, NULL);
2007 g_slist_free (uris);
2011 modest_msg_edit_window_attach_file_one (
2012 ModestMsgEditWindow *window,
2015 g_return_if_fail (window);
2016 g_return_if_fail (uri);
2018 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2021 GnomeVFSHandle *handle = NULL;
2022 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2023 if (result == GNOME_VFS_OK) {
2024 TnyMimePart *mime_part;
2026 const gchar *mime_type = NULL;
2028 gchar *escaped_filename;
2031 GnomeVFSFileInfo info;
2032 GnomeVFSURI *vfs_uri;
2034 vfs_uri = gnome_vfs_uri_new (uri);
2037 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2038 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2039 g_free (escaped_filename);
2040 gnome_vfs_uri_unref (vfs_uri);
2042 if (gnome_vfs_get_file_info (uri,
2044 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2046 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2047 mime_part = tny_platform_factory_new_mime_part
2048 (modest_runtime_get_platform_factory ());
2049 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2051 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2053 content_id = g_strdup_printf ("%d", priv->last_cid);
2054 tny_mime_part_set_content_id (mime_part, content_id);
2055 g_free (content_id);
2058 basename = g_path_get_basename (filename);
2059 tny_mime_part_set_filename (mime_part, basename);
2062 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2063 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2065 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2066 gtk_widget_show_all (priv->attachments_caption);
2067 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2073 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2076 ModestMsgEditWindowPrivate *priv;
2077 gboolean clean_list = FALSE;
2079 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2080 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2082 if (att_list == NULL) {
2083 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2087 if (att_list == NULL) {
2088 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2090 GtkWidget *confirmation_dialog = NULL;
2091 gboolean dialog_response;
2093 gchar *message = NULL;
2094 gchar *filename = NULL;
2096 if (att_list->next == NULL) {
2097 if (TNY_IS_MSG (att_list->data)) {
2098 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2100 filename = g_strdup (tny_header_get_subject (header));
2101 g_object_unref (header);
2103 if (filename == NULL) {
2104 filename = g_strdup (_("mail_va_no_subject"));
2107 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2110 filename = g_strdup ("");
2112 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2113 att_list->next == NULL), filename);
2115 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2117 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2118 gtk_widget_destroy (confirmation_dialog);
2119 if (!dialog_response) {
2121 g_list_free (att_list);
2124 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2126 for (node = att_list; node != NULL; node = g_list_next (node)) {
2127 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2128 const gchar *att_id;
2129 priv->attachments = g_list_remove (priv->attachments, mime_part);
2131 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2133 if (priv->attachments == NULL)
2134 gtk_widget_hide (priv->attachments_caption);
2135 att_id = tny_mime_part_get_content_id (mime_part);
2137 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2139 g_object_unref (mime_part);
2140 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2145 g_list_free (att_list);
2149 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2152 ModestMsgEditWindowPrivate *priv;
2153 GdkColor *new_color;
2154 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2156 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2157 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2160 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2162 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2164 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2166 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2171 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2174 ModestMsgEditWindowPrivate *priv;
2175 gint new_size_index;
2176 ModestMsgEditWindow *window;
2179 window = MODEST_MSG_EDIT_WINDOW (userdata);
2180 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2181 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2183 if (gtk_check_menu_item_get_active (menu_item)) {
2185 WPTextBufferFormat format;
2187 memset (&format, 0, sizeof (format));
2188 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2190 label = gtk_bin_get_child (GTK_BIN (menu_item));
2192 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2193 format.cs.font_size = TRUE;
2194 format.cs.text_position = TRUE;
2195 format.cs.font = TRUE;
2196 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2197 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2199 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2200 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2201 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2203 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2204 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2205 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2211 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2214 ModestMsgEditWindowPrivate *priv;
2215 gint new_font_index;
2216 ModestMsgEditWindow *window;
2219 window = MODEST_MSG_EDIT_WINDOW (userdata);
2220 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2221 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2223 if (gtk_check_menu_item_get_active (menu_item)) {
2226 label = gtk_bin_get_child (GTK_BIN (menu_item));
2228 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2230 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2231 GINT_TO_POINTER(new_font_index)))
2232 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2234 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2235 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2236 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2242 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2244 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2245 ModestWindowPrivate *parent_priv;
2246 ModestWindowMgr *mgr;
2247 gboolean is_fullscreen;
2248 GtkAction *fs_toggle_action;
2251 mgr = modest_runtime_get_window_mgr ();
2252 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2254 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2256 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2257 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2258 if (is_fullscreen != active)
2259 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2267 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2270 ModestMsgEditWindowPrivate *priv = NULL;
2271 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2273 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2274 if (!priv->update_caption_visibility)
2277 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2279 gtk_widget_show (priv->cc_caption);
2281 gtk_widget_hide (priv->cc_caption);
2283 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2287 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2290 ModestMsgEditWindowPrivate *priv = NULL;
2291 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2293 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2294 if (!priv->update_caption_visibility)
2297 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2299 gtk_widget_show (priv->bcc_caption);
2301 gtk_widget_hide (priv->bcc_caption);
2303 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2307 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2308 ModestRecptEditor *editor)
2310 ModestMsgEditWindowPrivate *priv;
2312 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2313 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2314 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2316 if (editor == NULL) {
2317 GtkWidget *view_focus;
2318 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2320 /* This code should be kept in sync with ModestRecptEditor. The
2321 textview inside the recpt editor is the one that really gets the
2322 focus. As it's inside a scrolled window, and this one inside the
2323 hbox recpt editor inherits from, we'll need to go up in the
2324 hierarchy to know if the text view is part of the recpt editor
2325 or if it's a different text entry */
2327 if (gtk_widget_get_parent (view_focus)) {
2328 GtkWidget *first_parent;
2330 first_parent = gtk_widget_get_parent (view_focus);
2331 if (gtk_widget_get_parent (first_parent) &&
2332 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2333 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2338 editor = MODEST_RECPT_EDITOR (priv->to_field);
2342 modest_address_book_select_addresses (editor);
2347 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2349 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2351 modest_msg_edit_window_open_addressbook (window, NULL);
2355 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2356 gboolean show_toolbar)
2358 ModestWindowPrivate *parent_priv;
2359 const gchar *action_name;
2362 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2363 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2365 /* We can not just use the code of
2366 modest_msg_edit_window_setup_toolbar because it has a
2367 mixture of both initialization and creation code. */
2369 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2371 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2373 /* Update also the actions (to update the toggles in the
2374 menus), we have to do it manually because some other window
2375 of the same time could have changed it (remember that the
2376 toolbar fullscreen mode is shared by all the windows of the
2378 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2379 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2381 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2383 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2384 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2390 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2391 TnyHeaderFlags priority_flags)
2393 ModestMsgEditWindowPrivate *priv;
2394 ModestWindowPrivate *parent_priv;
2396 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2398 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2399 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2401 if (priv->priority_flags != priority_flags) {
2402 GtkAction *priority_action = NULL;
2404 priv->priority_flags = priority_flags;
2406 switch (priority_flags) {
2407 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2408 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2409 gtk_widget_show (priv->priority_icon);
2410 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2411 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2413 case TNY_HEADER_FLAG_LOW_PRIORITY:
2414 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2415 gtk_widget_show (priv->priority_icon);
2416 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2417 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2420 gtk_widget_hide (priv->priority_icon);
2421 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2422 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2425 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2426 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2431 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2434 ModestMsgEditWindowPrivate *priv;
2435 ModestWindowPrivate *parent_priv;
2436 gint current_format;
2438 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2440 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2441 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2443 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2444 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2446 if (current_format != file_format) {
2447 switch (file_format) {
2448 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2449 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2450 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2452 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2456 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2457 response = gtk_dialog_run (GTK_DIALOG (dialog));
2458 gtk_widget_destroy (dialog);
2459 if (response == GTK_RESPONSE_OK) {
2460 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2462 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2463 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2468 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2473 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2476 ModestMsgEditWindowPrivate *priv;
2477 WPTextBufferFormat oldfmt, fmt;
2478 gint old_position = 0;
2482 GdkColor *color = NULL;
2483 gboolean bold, bold_set, italic, italic_set;
2484 gboolean underline, underline_set;
2485 gboolean strikethrough, strikethrough_set;
2486 gboolean position_set;
2487 gboolean font_size_set, font_set, color_set;
2490 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2491 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2493 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2495 /* First we get the currently selected font information */
2496 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2498 switch (oldfmt.text_position) {
2499 case TEXT_POSITION_NORMAL:
2502 case TEXT_POSITION_SUPERSCRIPT:
2510 g_object_set (G_OBJECT (dialog),
2511 "bold", oldfmt.bold != FALSE,
2512 "bold-set", !oldfmt.cs.bold,
2513 "underline", oldfmt.underline != FALSE,
2514 "underline-set", !oldfmt.cs.underline,
2515 "italic", oldfmt.italic != FALSE,
2516 "italic-set", !oldfmt.cs.italic,
2517 "strikethrough", oldfmt.strikethrough != FALSE,
2518 "strikethrough-set", !oldfmt.cs.strikethrough,
2519 "color", &oldfmt.color,
2520 "color-set", !oldfmt.cs.color,
2521 "size", wp_font_size[oldfmt.font_size],
2522 "size-set", !oldfmt.cs.font_size,
2523 "position", old_position,
2524 "position-set", !oldfmt.cs.text_position,
2525 "family", wp_get_font_name (oldfmt.font),
2526 "family-set", !oldfmt.cs.font,
2529 gtk_widget_show_all (dialog);
2530 response = gtk_dialog_run (GTK_DIALOG (dialog));
2531 if (response == GTK_RESPONSE_OK) {
2533 g_object_get( dialog,
2535 "bold-set", &bold_set,
2536 "underline", &underline,
2537 "underline-set", &underline_set,
2539 "italic-set", &italic_set,
2540 "strikethrough", &strikethrough,
2541 "strikethrough-set", &strikethrough_set,
2543 "color-set", &color_set,
2545 "size-set", &font_size_set,
2546 "family", &font_name,
2547 "family-set", &font_set,
2548 "position", &position,
2549 "position-set", &position_set,
2554 if (response == GTK_RESPONSE_OK) {
2555 memset(&fmt, 0, sizeof(fmt));
2561 fmt.italic = italic;
2562 fmt.cs.italic = TRUE;
2564 if (underline_set) {
2565 fmt.underline = underline;
2566 fmt.cs.underline = TRUE;
2568 if (strikethrough_set) {
2569 fmt.strikethrough = strikethrough;
2570 fmt.cs.strikethrough = TRUE;
2575 ? TEXT_POSITION_NORMAL
2576 : ( ( position == 1 )
2577 ? TEXT_POSITION_SUPERSCRIPT
2578 : TEXT_POSITION_SUBSCRIPT );
2579 fmt.cs.text_position = TRUE;
2580 fmt.font_size = oldfmt.font_size;
2584 fmt.cs.color = TRUE;
2587 fmt.font = wp_get_font_index(font_name,
2592 if (font_size_set) {
2593 fmt.cs.font_size = TRUE;
2594 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2596 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2597 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2599 gtk_widget_destroy (dialog);
2601 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2605 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2607 ModestMsgEditWindowPrivate *priv;
2609 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2610 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2612 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2614 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2619 modest_msg_edit_window_redo (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_redo (WP_TEXT_BUFFER (priv->text_buffer));
2628 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2633 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2635 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2637 priv->can_undo = can_undo;
2641 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2643 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2645 priv->can_redo = can_redo;
2649 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2651 ModestMsgEditWindowPrivate *priv;
2652 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2653 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2655 return priv->can_undo;
2659 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2661 ModestMsgEditWindowPrivate *priv;
2662 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2663 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2665 return priv->can_redo;
2670 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2673 GtkTextIter match_start, match_end;
2675 if (image_id == NULL)
2678 gtk_text_buffer_get_start_iter (buffer, &iter);
2680 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2681 GSList *tags = gtk_text_iter_get_tags (&match_start);
2683 for (node = tags; node != NULL; node = g_slist_next (node)) {
2684 GtkTextTag *tag = (GtkTextTag *) node->data;
2685 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2686 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2687 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2689 offset = gtk_text_iter_get_offset (&match_start);
2690 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2691 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2695 gtk_text_iter_forward_char (&iter);
2700 message_is_empty (ModestMsgEditWindow *window)
2702 ModestMsgEditWindowPrivate *priv = NULL;
2704 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2705 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2707 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2708 * so we can ignore markup.
2710 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2713 count = gtk_text_buffer_get_char_count (buf);
2719 msg_body_focus (GtkWidget *focus,
2720 GdkEventFocus *event,
2724 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2729 recpt_field_changed (GtkTextBuffer *buffer,
2730 ModestMsgEditWindow *editor)
2732 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2736 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2738 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2742 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2744 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2745 GtkTextBuffer *buffer;
2747 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2748 gtk_text_buffer_set_modified (buffer, FALSE);
2749 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2750 gtk_text_buffer_set_modified (buffer, FALSE);
2751 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2752 gtk_text_buffer_set_modified (buffer, FALSE);
2753 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2757 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2759 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2760 GtkTextBuffer *buffer;
2762 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2763 if (gtk_text_buffer_get_modified (buffer))
2765 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2766 if (gtk_text_buffer_get_modified (buffer))
2768 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2769 if (gtk_text_buffer_get_modified (buffer))
2771 if (gtk_text_buffer_get_modified (priv->text_buffer))
2781 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2783 ModestMsgEditWindowPrivate *priv = NULL;
2785 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2786 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2788 /* check if there's no recipient added */
2789 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2790 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2791 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2792 /* no recipient contents, then select contacts */
2793 modest_msg_edit_window_open_addressbook (window, NULL);
2797 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2798 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2801 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2802 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2805 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2806 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2810 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2811 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2812 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2819 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2820 ModestMsgEditWindow *window)
2822 modest_msg_edit_window_offer_attach_file (window);
2826 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2828 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2830 return priv->clipboard_text;
2834 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2836 ModestMsgEditWindow *window)
2838 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2839 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2841 if (!GTK_WIDGET_VISIBLE (window))
2844 text = gtk_clipboard_wait_for_text (selection_clipboard);
2846 if (priv->clipboard_text != NULL) {
2847 g_free (priv->clipboard_text);
2849 priv->clipboard_text = text;
2851 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2854 subject_field_move_cursor (GtkEntry *entry,
2855 GtkMovementStep step,
2860 if (!GTK_WIDGET_VISIBLE (window))
2863 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2867 update_window_title (ModestMsgEditWindow *window)
2869 ModestMsgEditWindowPrivate *priv = NULL;
2870 const gchar *subject;
2872 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2873 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2874 if (subject == NULL || subject[0] == '\0')
2875 subject = _("mail_va_new_email");
2877 gtk_window_set_title (GTK_WINDOW (window), subject);
2882 subject_field_changed (GtkEditable *editable,
2883 ModestMsgEditWindow *window)
2885 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2886 update_window_title (window);
2887 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2888 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2892 subject_field_insert_text (GtkEditable *editable,
2894 gint new_text_length,
2896 ModestMsgEditWindow *window)
2898 GString *result = g_string_new ("");
2900 gint result_len = 0;
2901 const gchar *entry_text = NULL;
2904 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2905 old_length = g_utf8_strlen (entry_text, -1);
2907 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2908 gunichar c = g_utf8_get_char_validated (current, 8);
2909 /* Invalid unichar, stop */
2915 result = g_string_append_unichar (result, c);
2919 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2920 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2923 /* Prevent endless recursion */
2924 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2925 g_signal_emit_by_name (editable, "insert-text",
2926 (gpointer) result->str, (gpointer) result->len,
2927 (gpointer) position, (gpointer) window);
2928 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2932 if (result_len + old_length > 1000) {
2933 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2934 dgettext("hildon-common-strings",
2935 "ckdg_ib_maximum_characters_reached"));
2938 g_string_free (result, TRUE);
2942 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2945 ModestMsgEditWindowPrivate *priv = NULL;
2947 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2948 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2950 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2953 gtk_widget_show_all (priv->find_toolbar);
2954 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2956 gtk_widget_hide_all (priv->find_toolbar);
2957 gtk_widget_grab_focus (priv->msg_body);
2963 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2965 GtkTextIter *match_start,
2966 GtkTextIter *match_end)
2968 GtkTextIter end_iter;
2969 gchar *str_casefold;
2972 gchar *range_casefold;
2975 gboolean result = FALSE;
2982 gtk_text_iter_forward_to_end (&end_iter);
2984 str_casefold = g_utf8_casefold (str, -1);
2985 str_chars_n = strlen (str);
2987 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2988 range_casefold = g_utf8_casefold (range_text, -1);
2989 range_chars_n = strlen (range_casefold);
2991 if (range_chars_n < str_chars_n) {
2992 g_free (str_casefold);
2993 g_free (range_text);
2994 g_free (range_casefold);
2998 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2999 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3000 if (!g_utf8_collate (range_subtext, str_casefold)) {
3001 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3003 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3004 match_start, match_end, NULL);
3005 g_free (found_text);
3007 g_free (range_subtext);
3011 g_free (str_casefold);
3012 g_free (range_text);
3013 g_free (range_casefold);
3020 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3021 ModestMsgEditWindow *window)
3023 gchar *current_search = NULL;
3024 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3026 GtkTextIter selection_start, selection_end;
3027 GtkTextIter match_start, match_end;
3028 gboolean continue_search = FALSE;
3030 if (message_is_empty (window)) {
3031 g_free (priv->last_search);
3032 priv->last_search = NULL;
3033 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3037 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3038 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3039 g_free (current_search);
3040 g_free (priv->last_search);
3041 priv->last_search = NULL;
3042 /* Information banner about empty search */
3043 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3047 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3048 continue_search = TRUE;
3050 g_free (priv->last_search);
3051 priv->last_search = g_strdup (current_search);
3054 if (continue_search) {
3055 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3056 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3057 &match_start, &match_end);
3059 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3061 GtkTextIter buffer_start;
3062 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3063 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3064 &match_start, &match_end);
3066 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3069 /* Mark as selected the string found in search */
3071 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3072 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3074 g_free (priv->last_search);
3075 priv->last_search = NULL;
3077 g_free (current_search);
3081 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3082 ModestMsgEditWindow *window)
3084 GtkToggleAction *toggle;
3085 ModestWindowPrivate *parent_priv;
3086 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3088 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3089 gtk_toggle_action_set_active (toggle, FALSE);
3093 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3095 ModestMsgEditWindowPrivate *priv;
3097 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3102 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3105 ModestMsgEditWindowPrivate *priv;
3107 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3113 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3116 ModestMsgEditWindowPrivate *priv;
3117 TnyHeader *header = NULL;
3119 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3120 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3122 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3123 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3125 if (priv->draft_msg != NULL) {
3126 g_object_unref (priv->draft_msg);
3129 if (draft != NULL) {
3130 g_object_ref (draft);
3131 header = tny_msg_get_header (draft);
3132 if (priv->msg_uid) {
3133 g_free (priv->msg_uid);
3134 priv->msg_uid = NULL;
3136 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3137 if (GTK_WIDGET_REALIZED (window))
3138 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3141 priv->draft_msg = draft;
3145 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3146 GtkTextIter *start, GtkTextIter *end,
3149 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3150 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3153 if (tag == NULL+13) return;
3154 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3155 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3156 replace_with_images (window, priv->images);
3161 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3164 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3166 g_return_if_fail (TNY_IS_MIME_PART (part));
3167 priv->attachments = g_list_prepend (priv->attachments, part);
3168 g_object_ref (part);
3169 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3170 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3171 gtk_widget_show_all (priv->attachments_caption);
3172 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3176 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3178 ModestMsgEditWindowPrivate *priv;
3180 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3181 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3183 return priv->msg_uid;
3187 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3188 ModestMsgEditWindowWidgetType widget_type)
3190 ModestMsgEditWindowPrivate *priv;
3192 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3193 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3195 switch (widget_type) {
3196 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3197 return priv->msg_body;
3199 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3200 return priv->to_field;
3202 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3203 return priv->cc_field;
3205 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3206 return priv->bcc_field;
3208 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3209 return priv->subject_field;
3211 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3212 return priv->attachments_view;
3220 remove_tags (WPTextBuffer *buffer)
3222 GtkTextIter start, end;
3224 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3225 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3227 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3231 on_account_removed (TnyAccountStore *account_store,
3232 TnyAccount *account,
3235 /* Do nothing if it's a store account, because we use the
3236 transport to send the messages */
3237 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3238 const gchar *parent_acc = NULL;
3239 const gchar *our_acc = NULL;
3241 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3242 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3243 /* Close this window if I'm showing a message of the removed account */
3244 if (strcmp (parent_acc, our_acc) == 0)
3245 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3250 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3252 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3254 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3260 set_zoom_do_nothing (ModestWindow *window,
3266 get_zoom_do_nothing (ModestWindow *window)