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='Serif'>", 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 |
2045 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2047 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2048 mime_part = tny_platform_factory_new_mime_part
2049 (modest_runtime_get_platform_factory ());
2050 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2052 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2054 content_id = g_strdup_printf ("%d", priv->last_cid);
2055 tny_mime_part_set_content_id (mime_part, content_id);
2056 g_free (content_id);
2059 basename = g_path_get_basename (filename);
2060 tny_mime_part_set_filename (mime_part, basename);
2063 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2064 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2066 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2067 gtk_widget_show_all (priv->attachments_caption);
2068 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2074 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2077 ModestMsgEditWindowPrivate *priv;
2078 gboolean clean_list = FALSE;
2080 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2081 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2083 if (att_list == NULL) {
2084 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2088 if (att_list == NULL) {
2089 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2091 GtkWidget *confirmation_dialog = NULL;
2092 gboolean dialog_response;
2094 gchar *message = NULL;
2095 gchar *filename = NULL;
2097 if (att_list->next == NULL) {
2098 if (TNY_IS_MSG (att_list->data)) {
2099 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2101 filename = g_strdup (tny_header_get_subject (header));
2102 g_object_unref (header);
2104 if (filename == NULL) {
2105 filename = g_strdup (_("mail_va_no_subject"));
2108 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2111 filename = g_strdup ("");
2113 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2114 att_list->next == NULL), filename);
2116 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2118 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2119 gtk_widget_destroy (confirmation_dialog);
2120 if (!dialog_response) {
2122 g_list_free (att_list);
2125 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2127 for (node = att_list; node != NULL; node = g_list_next (node)) {
2128 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2129 const gchar *att_id;
2130 priv->attachments = g_list_remove (priv->attachments, mime_part);
2132 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2134 if (priv->attachments == NULL)
2135 gtk_widget_hide (priv->attachments_caption);
2136 att_id = tny_mime_part_get_content_id (mime_part);
2138 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2140 g_object_unref (mime_part);
2141 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2146 g_list_free (att_list);
2150 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2153 ModestMsgEditWindowPrivate *priv;
2154 GdkColor *new_color;
2155 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2157 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2158 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2161 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2163 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2165 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2167 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2172 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2175 ModestMsgEditWindowPrivate *priv;
2176 gint new_size_index;
2177 ModestMsgEditWindow *window;
2180 window = MODEST_MSG_EDIT_WINDOW (userdata);
2181 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2182 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2184 if (gtk_check_menu_item_get_active (menu_item)) {
2186 WPTextBufferFormat format;
2188 memset (&format, 0, sizeof (format));
2189 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2191 label = gtk_bin_get_child (GTK_BIN (menu_item));
2193 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2194 format.cs.font_size = TRUE;
2195 format.cs.text_position = TRUE;
2196 format.cs.font = TRUE;
2197 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2198 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2200 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2201 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2202 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2204 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2205 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2206 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2212 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2215 ModestMsgEditWindowPrivate *priv;
2216 gint new_font_index;
2217 ModestMsgEditWindow *window;
2220 window = MODEST_MSG_EDIT_WINDOW (userdata);
2221 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2222 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2224 if (gtk_check_menu_item_get_active (menu_item)) {
2227 label = gtk_bin_get_child (GTK_BIN (menu_item));
2229 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2231 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2232 GINT_TO_POINTER(new_font_index)))
2233 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2235 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2236 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2237 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2243 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2245 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2246 ModestWindowPrivate *parent_priv;
2247 ModestWindowMgr *mgr;
2248 gboolean is_fullscreen;
2249 GtkAction *fs_toggle_action;
2252 mgr = modest_runtime_get_window_mgr ();
2253 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2255 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2257 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2258 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2259 if (is_fullscreen != active)
2260 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2268 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2271 ModestMsgEditWindowPrivate *priv = NULL;
2272 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2274 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2275 if (!priv->update_caption_visibility)
2278 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2280 gtk_widget_show (priv->cc_caption);
2282 gtk_widget_hide (priv->cc_caption);
2284 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2288 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2291 ModestMsgEditWindowPrivate *priv = NULL;
2292 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2294 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2295 if (!priv->update_caption_visibility)
2298 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2300 gtk_widget_show (priv->bcc_caption);
2302 gtk_widget_hide (priv->bcc_caption);
2304 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2308 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2309 ModestRecptEditor *editor)
2311 ModestMsgEditWindowPrivate *priv;
2313 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2314 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2315 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2317 if (editor == NULL) {
2318 GtkWidget *view_focus;
2319 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2321 /* This code should be kept in sync with ModestRecptEditor. The
2322 textview inside the recpt editor is the one that really gets the
2323 focus. As it's inside a scrolled window, and this one inside the
2324 hbox recpt editor inherits from, we'll need to go up in the
2325 hierarchy to know if the text view is part of the recpt editor
2326 or if it's a different text entry */
2328 if (gtk_widget_get_parent (view_focus)) {
2329 GtkWidget *first_parent;
2331 first_parent = gtk_widget_get_parent (view_focus);
2332 if (gtk_widget_get_parent (first_parent) &&
2333 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2334 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2339 editor = MODEST_RECPT_EDITOR (priv->to_field);
2343 modest_address_book_select_addresses (editor);
2348 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2350 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2352 modest_msg_edit_window_open_addressbook (window, NULL);
2356 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2357 gboolean show_toolbar)
2359 ModestWindowPrivate *parent_priv;
2360 const gchar *action_name;
2363 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2364 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2366 /* We can not just use the code of
2367 modest_msg_edit_window_setup_toolbar because it has a
2368 mixture of both initialization and creation code. */
2370 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2372 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2374 /* Update also the actions (to update the toggles in the
2375 menus), we have to do it manually because some other window
2376 of the same time could have changed it (remember that the
2377 toolbar fullscreen mode is shared by all the windows of the
2379 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2380 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2382 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2384 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2385 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2391 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2392 TnyHeaderFlags priority_flags)
2394 ModestMsgEditWindowPrivate *priv;
2395 ModestWindowPrivate *parent_priv;
2397 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2399 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2400 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2402 if (priv->priority_flags != priority_flags) {
2403 GtkAction *priority_action = NULL;
2405 priv->priority_flags = priority_flags;
2407 switch (priority_flags) {
2408 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2409 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2410 gtk_widget_show (priv->priority_icon);
2411 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2412 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2414 case TNY_HEADER_FLAG_LOW_PRIORITY:
2415 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2416 gtk_widget_show (priv->priority_icon);
2417 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2418 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2421 gtk_widget_hide (priv->priority_icon);
2422 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2423 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2426 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2427 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2432 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2435 ModestMsgEditWindowPrivate *priv;
2436 ModestWindowPrivate *parent_priv;
2437 gint current_format;
2439 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2441 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2442 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2444 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2445 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2447 if (current_format != file_format) {
2448 switch (file_format) {
2449 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2450 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2451 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2453 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2457 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2458 response = gtk_dialog_run (GTK_DIALOG (dialog));
2459 gtk_widget_destroy (dialog);
2460 if (response == GTK_RESPONSE_OK) {
2461 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2463 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2464 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2469 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2474 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2477 ModestMsgEditWindowPrivate *priv;
2478 WPTextBufferFormat oldfmt, fmt;
2479 gint old_position = 0;
2483 GdkColor *color = NULL;
2484 gboolean bold, bold_set, italic, italic_set;
2485 gboolean underline, underline_set;
2486 gboolean strikethrough, strikethrough_set;
2487 gboolean position_set;
2488 gboolean font_size_set, font_set, color_set;
2491 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2492 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2494 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2496 /* First we get the currently selected font information */
2497 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2499 switch (oldfmt.text_position) {
2500 case TEXT_POSITION_NORMAL:
2503 case TEXT_POSITION_SUPERSCRIPT:
2511 g_object_set (G_OBJECT (dialog),
2512 "bold", oldfmt.bold != FALSE,
2513 "bold-set", !oldfmt.cs.bold,
2514 "underline", oldfmt.underline != FALSE,
2515 "underline-set", !oldfmt.cs.underline,
2516 "italic", oldfmt.italic != FALSE,
2517 "italic-set", !oldfmt.cs.italic,
2518 "strikethrough", oldfmt.strikethrough != FALSE,
2519 "strikethrough-set", !oldfmt.cs.strikethrough,
2520 "color", &oldfmt.color,
2521 "color-set", !oldfmt.cs.color,
2522 "size", wp_font_size[oldfmt.font_size],
2523 "size-set", !oldfmt.cs.font_size,
2524 "position", old_position,
2525 "position-set", !oldfmt.cs.text_position,
2526 "family", wp_get_font_name (oldfmt.font),
2527 "family-set", !oldfmt.cs.font,
2530 gtk_widget_show_all (dialog);
2531 response = gtk_dialog_run (GTK_DIALOG (dialog));
2532 if (response == GTK_RESPONSE_OK) {
2534 g_object_get( dialog,
2536 "bold-set", &bold_set,
2537 "underline", &underline,
2538 "underline-set", &underline_set,
2540 "italic-set", &italic_set,
2541 "strikethrough", &strikethrough,
2542 "strikethrough-set", &strikethrough_set,
2544 "color-set", &color_set,
2546 "size-set", &font_size_set,
2547 "family", &font_name,
2548 "family-set", &font_set,
2549 "position", &position,
2550 "position-set", &position_set,
2555 if (response == GTK_RESPONSE_OK) {
2556 memset(&fmt, 0, sizeof(fmt));
2562 fmt.italic = italic;
2563 fmt.cs.italic = TRUE;
2565 if (underline_set) {
2566 fmt.underline = underline;
2567 fmt.cs.underline = TRUE;
2569 if (strikethrough_set) {
2570 fmt.strikethrough = strikethrough;
2571 fmt.cs.strikethrough = TRUE;
2576 ? TEXT_POSITION_NORMAL
2577 : ( ( position == 1 )
2578 ? TEXT_POSITION_SUPERSCRIPT
2579 : TEXT_POSITION_SUBSCRIPT );
2580 fmt.cs.text_position = TRUE;
2581 fmt.font_size = oldfmt.font_size;
2585 fmt.cs.color = TRUE;
2588 fmt.font = wp_get_font_index(font_name,
2593 if (font_size_set) {
2594 fmt.cs.font_size = TRUE;
2595 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2597 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2598 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2600 gtk_widget_destroy (dialog);
2602 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2606 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2608 ModestMsgEditWindowPrivate *priv;
2610 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2611 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2613 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2615 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2620 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2622 ModestMsgEditWindowPrivate *priv;
2624 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2625 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2627 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2629 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2634 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2636 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2638 priv->can_undo = can_undo;
2642 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2644 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2646 priv->can_redo = can_redo;
2650 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2652 ModestMsgEditWindowPrivate *priv;
2653 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2654 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2656 return priv->can_undo;
2660 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2662 ModestMsgEditWindowPrivate *priv;
2663 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2664 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2666 return priv->can_redo;
2671 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2674 GtkTextIter match_start, match_end;
2676 if (image_id == NULL)
2679 gtk_text_buffer_get_start_iter (buffer, &iter);
2681 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2682 GSList *tags = gtk_text_iter_get_tags (&match_start);
2684 for (node = tags; node != NULL; node = g_slist_next (node)) {
2685 GtkTextTag *tag = (GtkTextTag *) node->data;
2686 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2687 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2688 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2690 offset = gtk_text_iter_get_offset (&match_start);
2691 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2692 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2696 gtk_text_iter_forward_char (&iter);
2701 message_is_empty (ModestMsgEditWindow *window)
2703 ModestMsgEditWindowPrivate *priv = NULL;
2705 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2706 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2708 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2709 * so we can ignore markup.
2711 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2714 count = gtk_text_buffer_get_char_count (buf);
2720 msg_body_focus (GtkWidget *focus,
2721 GdkEventFocus *event,
2725 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2730 recpt_field_changed (GtkTextBuffer *buffer,
2731 ModestMsgEditWindow *editor)
2733 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2737 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2739 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2743 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2745 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2746 GtkTextBuffer *buffer;
2748 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2749 gtk_text_buffer_set_modified (buffer, FALSE);
2750 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2751 gtk_text_buffer_set_modified (buffer, FALSE);
2752 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2753 gtk_text_buffer_set_modified (buffer, FALSE);
2754 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2758 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2760 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2761 GtkTextBuffer *buffer;
2763 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2764 if (gtk_text_buffer_get_modified (buffer))
2766 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2767 if (gtk_text_buffer_get_modified (buffer))
2769 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2770 if (gtk_text_buffer_get_modified (buffer))
2772 if (gtk_text_buffer_get_modified (priv->text_buffer))
2782 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2784 ModestMsgEditWindowPrivate *priv = NULL;
2786 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2787 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2789 /* check if there's no recipient added */
2790 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2791 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2792 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2793 /* no recipient contents, then select contacts */
2794 modest_msg_edit_window_open_addressbook (window, NULL);
2798 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2799 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2802 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2803 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2806 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2807 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2811 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2812 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2813 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2820 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2821 ModestMsgEditWindow *window)
2823 modest_msg_edit_window_offer_attach_file (window);
2827 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2829 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2831 return priv->clipboard_text;
2835 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2837 ModestMsgEditWindow *window)
2839 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2840 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2842 if (!GTK_WIDGET_VISIBLE (window))
2845 text = gtk_clipboard_wait_for_text (selection_clipboard);
2847 if (priv->clipboard_text != NULL) {
2848 g_free (priv->clipboard_text);
2850 priv->clipboard_text = text;
2852 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2855 subject_field_move_cursor (GtkEntry *entry,
2856 GtkMovementStep step,
2861 if (!GTK_WIDGET_VISIBLE (window))
2864 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2868 update_window_title (ModestMsgEditWindow *window)
2870 ModestMsgEditWindowPrivate *priv = NULL;
2871 const gchar *subject;
2873 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2874 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2875 if (subject == NULL || subject[0] == '\0')
2876 subject = _("mail_va_new_email");
2878 gtk_window_set_title (GTK_WINDOW (window), subject);
2883 subject_field_changed (GtkEditable *editable,
2884 ModestMsgEditWindow *window)
2886 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2887 update_window_title (window);
2888 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2889 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2893 subject_field_insert_text (GtkEditable *editable,
2895 gint new_text_length,
2897 ModestMsgEditWindow *window)
2899 GString *result = g_string_new ("");
2901 gint result_len = 0;
2902 const gchar *entry_text = NULL;
2905 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2906 old_length = g_utf8_strlen (entry_text, -1);
2908 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2909 gunichar c = g_utf8_get_char_validated (current, 8);
2910 /* Invalid unichar, stop */
2916 result = g_string_append_unichar (result, c);
2920 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2921 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2924 /* Prevent endless recursion */
2925 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2926 g_signal_emit_by_name (editable, "insert-text",
2927 (gpointer) result->str, (gpointer) result->len,
2928 (gpointer) position, (gpointer) window);
2929 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2933 if (result_len + old_length > 1000) {
2934 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2935 dgettext("hildon-common-strings",
2936 "ckdg_ib_maximum_characters_reached"));
2939 g_string_free (result, TRUE);
2943 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2946 ModestMsgEditWindowPrivate *priv = NULL;
2948 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2949 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2951 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2954 gtk_widget_show_all (priv->find_toolbar);
2955 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2957 gtk_widget_hide_all (priv->find_toolbar);
2958 gtk_widget_grab_focus (priv->msg_body);
2964 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2966 GtkTextIter *match_start,
2967 GtkTextIter *match_end)
2969 GtkTextIter end_iter;
2970 gchar *str_casefold;
2973 gchar *range_casefold;
2976 gboolean result = FALSE;
2983 gtk_text_iter_forward_to_end (&end_iter);
2985 str_casefold = g_utf8_casefold (str, -1);
2986 str_chars_n = strlen (str);
2988 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2989 range_casefold = g_utf8_casefold (range_text, -1);
2990 range_chars_n = strlen (range_casefold);
2992 if (range_chars_n < str_chars_n) {
2993 g_free (str_casefold);
2994 g_free (range_text);
2995 g_free (range_casefold);
2999 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3000 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3001 if (!g_utf8_collate (range_subtext, str_casefold)) {
3002 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3004 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3005 match_start, match_end, NULL);
3006 g_free (found_text);
3008 g_free (range_subtext);
3012 g_free (str_casefold);
3013 g_free (range_text);
3014 g_free (range_casefold);
3021 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3022 ModestMsgEditWindow *window)
3024 gchar *current_search = NULL;
3025 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3027 GtkTextIter selection_start, selection_end;
3028 GtkTextIter match_start, match_end;
3029 gboolean continue_search = FALSE;
3031 if (message_is_empty (window)) {
3032 g_free (priv->last_search);
3033 priv->last_search = NULL;
3034 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3038 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3039 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3040 g_free (current_search);
3041 g_free (priv->last_search);
3042 priv->last_search = NULL;
3043 /* Information banner about empty search */
3044 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3048 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3049 continue_search = TRUE;
3051 g_free (priv->last_search);
3052 priv->last_search = g_strdup (current_search);
3055 if (continue_search) {
3056 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3057 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3058 &match_start, &match_end);
3060 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3062 GtkTextIter buffer_start;
3063 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3064 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3065 &match_start, &match_end);
3067 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3070 /* Mark as selected the string found in search */
3072 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3073 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3075 g_free (priv->last_search);
3076 priv->last_search = NULL;
3078 g_free (current_search);
3082 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3083 ModestMsgEditWindow *window)
3085 GtkToggleAction *toggle;
3086 ModestWindowPrivate *parent_priv;
3087 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3089 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3090 gtk_toggle_action_set_active (toggle, FALSE);
3094 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3096 ModestMsgEditWindowPrivate *priv;
3098 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3103 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3106 ModestMsgEditWindowPrivate *priv;
3108 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3114 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3117 ModestMsgEditWindowPrivate *priv;
3118 TnyHeader *header = NULL;
3120 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3121 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3123 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3124 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3126 if (priv->draft_msg != NULL) {
3127 g_object_unref (priv->draft_msg);
3130 if (draft != NULL) {
3131 g_object_ref (draft);
3132 header = tny_msg_get_header (draft);
3133 if (priv->msg_uid) {
3134 g_free (priv->msg_uid);
3135 priv->msg_uid = NULL;
3137 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3138 if (GTK_WIDGET_REALIZED (window))
3139 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3142 priv->draft_msg = draft;
3146 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3147 GtkTextIter *start, GtkTextIter *end,
3150 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3151 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3154 if (tag == NULL+13) return;
3155 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3156 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3157 replace_with_images (window, priv->images);
3162 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3165 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3167 g_return_if_fail (TNY_IS_MIME_PART (part));
3168 priv->attachments = g_list_prepend (priv->attachments, part);
3169 g_object_ref (part);
3170 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3171 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3172 gtk_widget_show_all (priv->attachments_caption);
3173 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3177 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3179 ModestMsgEditWindowPrivate *priv;
3181 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3182 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3184 return priv->msg_uid;
3188 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3189 ModestMsgEditWindowWidgetType widget_type)
3191 ModestMsgEditWindowPrivate *priv;
3193 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3194 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3196 switch (widget_type) {
3197 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3198 return priv->msg_body;
3200 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3201 return priv->to_field;
3203 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3204 return priv->cc_field;
3206 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3207 return priv->bcc_field;
3209 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3210 return priv->subject_field;
3212 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3213 return priv->attachments_view;
3221 remove_tags (WPTextBuffer *buffer)
3223 GtkTextIter start, end;
3225 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3226 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3228 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3232 on_account_removed (TnyAccountStore *account_store,
3233 TnyAccount *account,
3236 /* Do nothing if it's a store account, because we use the
3237 transport to send the messages */
3238 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3239 const gchar *parent_acc = NULL;
3240 const gchar *our_acc = NULL;
3242 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3243 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3244 /* Close this window if I'm showing a message of the removed account */
3245 if (strcmp (parent_acc, our_acc) == 0)
3246 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3251 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3253 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3255 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3261 set_zoom_do_nothing (ModestWindow *window,
3267 get_zoom_do_nothing (ModestWindow *window)