1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include <modest-utils.h>
79 #include "modest-maemo-utils.h"
82 #define DEFAULT_FONT_SIZE 3
83 #define DEFAULT_FONT 2
84 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
85 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
86 #define DEFAULT_MAIN_VBOX_SPACING 6
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #define DEFAULT_FONT_SCALE 1.5
91 static gboolean is_wp_text_buffer_started = FALSE;
93 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
94 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
95 static void modest_msg_edit_window_finalize (GObject *obj);
97 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
98 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
99 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
101 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
102 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
103 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
104 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
105 GtkTextIter *start, GtkTextIter *end,
107 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
108 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
109 static void subject_field_insert_text (GtkEditable *editable,
111 gint new_text_length,
113 ModestMsgEditWindow *window);
114 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
116 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
118 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
121 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
122 GdkEventWindowState *event,
124 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
125 ModestRecptEditor *editor);
126 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
127 ModestMsgEditWindow *window);
129 /* ModestWindow methods implementation */
130 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
131 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
132 gboolean show_toolbar);
133 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
135 ModestMsgEditWindow *window);
136 static void subject_field_move_cursor (GtkEntry *entry,
137 GtkMovementStep step,
141 static void update_window_title (ModestMsgEditWindow *window);
144 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
145 ModestMsgEditWindow *window);
146 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
147 ModestMsgEditWindow *window);
148 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
150 GtkTextIter *match_start,
151 GtkTextIter *match_end);
153 static void remove_tags (WPTextBuffer *buffer);
155 static void on_account_removed (TnyAccountStore *account_store,
159 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
161 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
163 static gdouble get_zoom_do_nothing (ModestWindow *window);
165 static void init_window (ModestMsgEditWindow *obj);
167 static void DEBUG_BUFFER (WPTextBuffer *buffer)
171 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
173 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
174 while (!gtk_text_iter_is_end (&iter)) {
175 GString *output = g_string_new ("");
176 GSList *toggled_tags;
179 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
180 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
181 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
182 GtkTextTag *tag = (GtkTextTag *) node->data;
184 g_object_get (G_OBJECT (tag), "name", &name, NULL);
185 output = g_string_append (output, name);
186 g_string_append (output, " ");
188 output = g_string_append (output, "] OPENED [ ");
189 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
190 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
191 GtkTextTag *tag = (GtkTextTag *) node->data;
193 g_object_get (G_OBJECT (tag), "name", &name, NULL);
194 output = g_string_append (output, name);
195 g_string_append (output, " ");
197 output = g_string_append (output, "]\n");
198 g_message ("%s", output->str);
199 g_string_free (output, TRUE);
200 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
202 g_message ("END BUFFER");
207 /* static gboolean */
208 /* on_key_pressed (GtkWidget *self, */
209 /* GdkEventKey *event, */
210 /* gpointer user_data); */
212 /* list my signals */
219 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
220 struct _ModestMsgEditWindowPrivate {
222 GtkWidget *header_box;
224 ModestPairList *from_field_protos;
225 GtkWidget *from_field;
229 GtkWidget *bcc_field;
230 GtkWidget *subject_field;
231 GtkWidget *attachments_view;
232 GtkWidget *priority_icon;
233 GtkWidget *add_attachment_button;
235 GtkWidget *cc_caption;
236 GtkWidget *bcc_caption;
237 gboolean update_caption_visibility;
238 GtkWidget *attachments_caption;
240 GtkTextBuffer *text_buffer;
242 GtkWidget *font_size_toolitem;
243 GtkWidget *font_face_toolitem;
244 GtkWidget *font_color_button;
245 GSList *font_items_group;
246 GtkWidget *font_tool_button_label;
247 GSList *size_items_group;
248 GtkWidget *size_tool_button_label;
250 GtkWidget *find_toolbar;
254 GtkWidget *scroll_area;
255 gint last_vadj_upper;
261 TnyHeaderFlags priority_flags;
263 gboolean can_undo, can_redo;
264 gulong clipboard_change_handler_id;
265 gulong default_clipboard_change_handler_id;
266 gulong account_removed_handler_id;
267 gchar *clipboard_text;
276 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
277 MODEST_TYPE_MSG_EDIT_WINDOW, \
278 ModestMsgEditWindowPrivate))
280 static GtkWindowClass *parent_class = NULL;
282 /* uncomment the following if you have defined any signals */
283 /* static guint signals[LAST_SIGNAL] = {0}; */
286 modest_msg_edit_window_get_type (void)
288 static GType my_type = 0;
290 static const GTypeInfo my_info = {
291 sizeof(ModestMsgEditWindowClass),
292 NULL, /* base init */
293 NULL, /* base finalize */
294 (GClassInitFunc) modest_msg_edit_window_class_init,
295 NULL, /* class finalize */
296 NULL, /* class data */
297 sizeof(ModestMsgEditWindow),
299 (GInstanceInitFunc) modest_msg_edit_window_init,
302 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
303 "ModestMsgEditWindow",
311 save_state (ModestWindow *self)
313 modest_widget_memory_save (modest_runtime_get_conf(),
314 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
319 restore_settings (ModestMsgEditWindow *self)
321 ModestConf *conf = NULL;
323 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
325 conf = modest_runtime_get_conf ();
326 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
327 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
328 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
329 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
330 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
331 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
332 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
333 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
335 /* set initial state of cc and bcc */
336 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
337 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
338 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
339 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
340 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
341 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
343 /* Dim at start clipboard actions */
344 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
345 gtk_action_set_sensitive (action, FALSE);
346 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
347 gtk_action_set_sensitive (action, FALSE);
348 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
349 gtk_action_set_sensitive (action, FALSE);
351 modest_widget_memory_restore (conf,
352 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
357 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
359 GObjectClass *gobject_class;
360 ModestWindowClass *modest_window_class;
361 gobject_class = (GObjectClass*) klass;
362 modest_window_class = (ModestWindowClass*) klass;
364 parent_class = g_type_class_peek_parent (klass);
365 gobject_class->finalize = modest_msg_edit_window_finalize;
367 modest_window_class->set_zoom_func = set_zoom_do_nothing;
368 modest_window_class->get_zoom_func = get_zoom_do_nothing;
369 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
370 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
371 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
372 modest_window_class->save_state_func = save_state;
373 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
375 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
379 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
381 ModestMsgEditWindowPrivate *priv;
382 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
384 priv->msg_body = NULL;
385 priv->from_field = NULL;
386 priv->to_field = NULL;
387 priv->cc_field = NULL;
388 priv->bcc_field = NULL;
389 priv->subject_field = NULL;
390 priv->attachments = NULL;
394 priv->cc_caption = NULL;
395 priv->bcc_caption = NULL;
396 priv->update_caption_visibility = FALSE;
398 priv->priority_flags = 0;
400 priv->find_toolbar = NULL;
401 priv->last_search = NULL;
403 priv->draft_msg = NULL;
404 priv->outbox_msg = NULL;
405 priv->msg_uid = NULL;
407 priv->can_undo = FALSE;
408 priv->can_redo = FALSE;
409 priv->clipboard_change_handler_id = 0;
410 priv->default_clipboard_change_handler_id = 0;
411 priv->account_removed_handler_id = 0;
412 priv->clipboard_text = NULL;
415 priv->last_vadj_upper = 0;
417 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
418 GTK_WINDOW(obj),"applications_email_editor");
420 if (!is_wp_text_buffer_started) {
421 is_wp_text_buffer_started = TRUE;
422 wp_text_buffer_library_init ();
427 hildon_program_add_window (hildon_program_get_instance(),
432 /* FIXME: this is a dup from the one in gtk/ */
435 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
437 static ModestPairList*
438 get_transports (void)
440 GSList *transports = NULL;
442 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
443 GSList *accounts = modest_account_mgr_account_names (account_mgr,
444 TRUE /* only enabled accounts. */);
446 GSList *cursor = accounts;
448 gchar *account_name = cursor->data;
449 gchar *from_string = NULL;
451 from_string = modest_account_mgr_get_from_string (account_mgr,
455 if (from_string && account_name) {
456 gchar *name = account_name;
457 ModestPair *pair = modest_pair_new ((gpointer) name,
458 (gpointer) from_string , TRUE);
459 transports = g_slist_prepend (transports, pair);
462 cursor = cursor->next;
464 g_slist_free (accounts); /* only free the accounts, not the elements,
465 * because they are used in the pairlist */
469 void vadj_changed (GtkAdjustment *adj,
470 ModestMsgEditWindow *window)
472 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
474 GdkRectangle rectangle, cursor_rectangle;
475 GtkTextIter position;
479 /* We detect if cursor is visible using the full height, not only the center. This
481 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
482 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
484 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
485 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
487 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
488 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
490 if (gtk_widget_is_focus (priv->msg_body) &&
492 if (priv->last_vadj_upper != adj->upper) {
495 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
496 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
497 insert, 0.1, FALSE, 0.0, 0.0);
500 priv->last_vadj_upper = adj->upper;
505 connect_signals (ModestMsgEditWindow *obj)
507 ModestMsgEditWindowPrivate *priv;
509 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
511 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
512 G_CALLBACK (text_buffer_refresh_attributes), obj);
513 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
514 G_CALLBACK (text_buffer_can_undo), obj);
515 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
516 G_CALLBACK (text_buffer_can_redo), obj);
517 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
518 G_CALLBACK (body_changed), obj);
519 g_signal_connect (G_OBJECT (obj), "window-state-event",
520 G_CALLBACK (modest_msg_edit_window_window_state_event),
522 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
523 G_CALLBACK (text_buffer_apply_tag), obj);
524 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
525 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
526 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
527 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
528 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
529 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
531 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
532 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
534 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
535 G_CALLBACK (msg_body_focus), obj);
536 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
537 G_CALLBACK (msg_body_focus), obj);
538 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
539 "changed", G_CALLBACK (recpt_field_changed), obj);
540 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
541 "changed", G_CALLBACK (recpt_field_changed), obj);
542 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
543 "changed", G_CALLBACK (recpt_field_changed), obj);
544 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
545 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
546 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
548 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
549 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
551 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
553 G_CALLBACK (vadj_changed),
556 priv->clipboard_change_handler_id =
557 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
558 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
559 priv->default_clipboard_change_handler_id =
560 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
561 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
566 menubar_to_menu (GtkUIManager *ui_manager)
568 GtkWidget *main_menu;
570 /* Get the menubar from the UI manager */
571 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
577 init_window (ModestMsgEditWindow *obj)
579 GtkWidget *from_caption, *to_caption, *subject_caption;
580 GtkWidget *main_vbox;
581 ModestMsgEditWindowPrivate *priv;
582 GtkActionGroup *action_group;
583 ModestWindowPrivate *parent_priv;
584 GdkPixbuf *window_icon = NULL;
585 GError *error = NULL;
587 GtkSizeGroup *size_group;
589 GtkWidget *subject_box;
590 GtkWidget *attachment_icon;
591 GtkWidget *window_box;
592 #if (GTK_MINOR_VERSION >= 10)
593 GdkAtom deserialize_type;
595 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
596 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
598 parent_priv->ui_manager = gtk_ui_manager_new();
599 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
600 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
602 /* Add common actions */
603 gtk_action_group_add_actions (action_group,
604 modest_msg_edit_action_entries,
605 G_N_ELEMENTS (modest_msg_edit_action_entries),
607 gtk_action_group_add_toggle_actions (action_group,
608 modest_msg_edit_toggle_action_entries,
609 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
611 gtk_action_group_add_radio_actions (action_group,
612 modest_msg_edit_alignment_radio_action_entries,
613 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
615 G_CALLBACK (modest_ui_actions_on_change_justify),
617 gtk_action_group_add_radio_actions (action_group,
618 modest_msg_edit_priority_action_entries,
619 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
621 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
623 gtk_action_group_add_radio_actions (action_group,
624 modest_msg_edit_file_format_action_entries,
625 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
626 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
627 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
629 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
630 g_object_unref (action_group);
632 /* Load the UI definition */
633 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
636 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
637 g_clear_error (&error);
640 /* Add accelerators */
641 gtk_window_add_accel_group (GTK_WINDOW (obj),
642 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
644 parent_priv->menubar = NULL;
646 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
648 /* Note: This ModestPairList* must exist for as long as the combo
649 * that uses it, because the ModestComboBox uses the ID opaquely,
650 * so it can't know how to manage its memory. */
651 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
653 priv->to_field = modest_recpt_editor_new ();
654 priv->cc_field = modest_recpt_editor_new ();
655 priv->bcc_field = modest_recpt_editor_new ();
656 subject_box = gtk_hbox_new (FALSE, 0);
657 priv->priority_icon = gtk_image_new ();
658 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
659 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
660 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
661 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
662 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
663 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
664 priv->add_attachment_button = gtk_button_new ();
665 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
666 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
667 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
668 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
669 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
670 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
671 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
672 priv->attachments_view = modest_attachments_view_new (NULL);
674 priv->header_box = gtk_vbox_new (FALSE, 0);
676 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
677 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
678 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
679 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
680 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
681 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
682 g_object_unref (size_group);
684 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
685 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
686 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
687 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
688 gtk_size_group_add_widget (size_group, priv->subject_field);
689 gtk_size_group_add_widget (size_group, priv->attachments_view);
690 g_object_unref (size_group);
692 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
694 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
695 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
696 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
697 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
698 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
701 priv->msg_body = wp_text_view_new ();
702 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
703 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
704 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
705 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
706 #if (GTK_MINOR_VERSION >= 10)
707 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
708 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
710 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
711 deserialize_type, TRUE);
713 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
715 priv->find_toolbar = hildon_find_toolbar_new (NULL);
716 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
718 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
720 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
721 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
722 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
723 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
725 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
727 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
728 frame = gtk_frame_new (NULL);
729 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
731 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
732 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
733 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
735 G_CALLBACK (vadj_changed),
737 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
739 window_box = gtk_vbox_new (FALSE, 0);
740 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
741 gtk_container_add (GTK_CONTAINER(obj), window_box);
742 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
743 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
745 /* Set window icon */
746 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
748 /* scale the icon, because it won't be shown unless it's
749 * 64 x 54 -- hildon quirk. this looks a bit ugly now,
750 * so waiting for correctly sized icons, then this scaling
751 * code can disappear -- djcb
754 gdk_pixbuf_scale_simple (window_icon, 64, 54, GDK_INTERP_BILINEAR);
756 gtk_window_set_icon (GTK_WINDOW (obj), scaled);
757 g_object_unref (scaled);
759 g_object_unref (window_icon);
764 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
766 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
768 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
769 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
770 priv->clipboard_change_handler_id))
771 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
772 priv->clipboard_change_handler_id);
773 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
774 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
775 priv->default_clipboard_change_handler_id))
776 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
777 priv->default_clipboard_change_handler_id);
779 if (priv->account_removed_handler_id &&
780 g_signal_handler_is_connected (modest_runtime_get_account_store (),
781 priv->account_removed_handler_id))
782 g_signal_handler_disconnect(modest_runtime_get_account_store (),
783 priv->account_removed_handler_id);
787 modest_msg_edit_window_finalize (GObject *obj)
789 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
791 /* Sanity check: shouldn't be needed, the window mgr should
792 call this function before */
793 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
795 if (priv->clipboard_text != NULL) {
796 g_free (priv->clipboard_text);
797 priv->clipboard_text = NULL;
800 if (priv->draft_msg != NULL) {
801 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
802 if (TNY_IS_HEADER (header)) {
803 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
804 modest_window_mgr_unregister_header (mgr, header);
806 g_object_unref (priv->draft_msg);
807 priv->draft_msg = NULL;
809 if (priv->outbox_msg != NULL) {
810 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
811 if (TNY_IS_HEADER (header)) {
812 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
813 modest_window_mgr_unregister_header (mgr, header);
815 g_object_unref (priv->outbox_msg);
816 priv->outbox_msg = NULL;
818 g_free (priv->msg_uid);
819 g_free (priv->last_search);
820 g_slist_free (priv->font_items_group);
821 g_slist_free (priv->size_items_group);
822 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
823 g_list_free (priv->attachments);
824 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
825 g_list_free (priv->images);
827 /* This had to stay alive for as long as the combobox that used it: */
828 modest_pair_list_free (priv->from_field_protos);
830 G_OBJECT_CLASS(parent_class)->finalize (obj);
834 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
836 GdkPixbufLoader *loader;
839 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
844 tny_stream_reset (TNY_STREAM (stream));
845 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
846 unsigned char read_buffer[128];
848 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
849 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
853 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
854 g_object_ref (pixbuf);
855 gdk_pixbuf_loader_close (loader, NULL);
856 g_object_unref (loader);
858 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
859 GdkPixbuf *new_pixbuf;
861 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
862 gdk_pixbuf_get_width (pixbuf);
863 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
864 g_object_unref (pixbuf);
872 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
874 ModestMsgEditWindowPrivate *priv;
877 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
879 for (node = attachments; node != NULL; node = g_list_next (node)) {
880 TnyMimePart *part = (TnyMimePart *) node->data;
881 const gchar *cid = tny_mime_part_get_content_id (part);
882 const gchar *mime_type = tny_mime_part_get_content_type (part);
883 if ((cid != NULL)&&(mime_type != NULL)) {
884 TnyStream *stream = tny_mime_part_get_stream (part);
885 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
886 g_object_unref (stream);
888 if (pixbuf != NULL) {
889 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
890 g_object_unref (pixbuf);
897 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
899 TnyMimePart *parent = NULL;
900 const gchar *content_type = NULL;
901 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
903 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
905 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
906 parent = g_object_ref (msg);
907 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
908 TnyList *parts = TNY_LIST (tny_simple_list_new ());
911 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
912 iter = tny_list_create_iterator (parts);
913 while (!tny_iterator_is_done (iter)) {
915 part = TNY_MIME_PART (tny_iterator_get_current (iter));
916 content_type = tny_mime_part_get_content_type (part);
917 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
921 g_object_unref (part);
923 tny_iterator_next (iter);
925 g_object_unref (iter);
926 g_object_unref (parts);
929 if (parent != NULL) {
930 TnyList *parts = TNY_LIST (tny_simple_list_new ());
933 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
934 iter = tny_list_create_iterator (parts);
935 while (!tny_iterator_is_done (iter)) {
937 part = TNY_MIME_PART (tny_iterator_get_current (iter));
938 content_type = tny_mime_part_get_content_type (part);
939 if (content_type && g_str_has_prefix (content_type, "image/")) {
940 priv->images = g_list_prepend (priv->images, part);
942 g_object_unref (part);
944 tny_iterator_next (iter);
946 g_object_unref (iter);
947 g_object_unref (parts);
948 g_object_unref (parent);
953 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
956 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
958 for (node = attachments; node != NULL; node = g_list_next (node)) {
959 TnyMimePart *part = (TnyMimePart *) node->data;
960 const gchar *cid = tny_mime_part_get_content_id (part);
962 char *invalid = NULL;
963 gint int_cid = strtol (cid, &invalid, 10);
964 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
965 priv->last_cid = int_cid;
973 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
976 const gchar *to, *cc, *bcc, *subject;
978 ModestMsgEditWindowPrivate *priv;
980 TnyHeaderFlags priority_flags;
981 TnyFolder *msg_folder;
982 gboolean is_html = FALSE;
984 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
985 g_return_if_fail (TNY_IS_MSG (msg));
987 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
989 header = tny_msg_get_header (msg);
990 to = tny_header_get_to (header);
991 cc = tny_header_get_cc (header);
992 bcc = tny_header_get_bcc (header);
993 subject = tny_header_get_subject (header);
994 priority_flags = tny_header_get_priority (header);
997 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
999 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
1000 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1001 gtk_widget_show (priv->cc_caption);
1002 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1003 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1004 gtk_widget_hide (priv->cc_caption);
1007 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1008 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1009 gtk_widget_show (priv->bcc_caption);
1010 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1011 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1012 gtk_widget_hide (priv->bcc_caption);
1015 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1016 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1019 update_window_title (self);
1021 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1022 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1024 if ((body == NULL)||(body[0] == '\0')) {
1026 body = modest_text_utils_convert_to_html ("");
1029 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1030 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1033 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1036 /* Add attachments to the view */
1037 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1038 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1039 if (priv->attachments == NULL) {
1040 gtk_widget_hide (priv->attachments_caption);
1042 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1043 gtk_widget_show_all (priv->attachments_caption);
1045 get_related_images (self, msg);
1046 update_last_cid (self, priv->attachments);
1047 update_last_cid (self, priv->images);
1048 replace_with_images (self, priv->images);
1050 if (preserve_is_rich && !is_html) {
1051 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1052 /* Get the default format required from configuration */
1053 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1054 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1057 /* Set the default focus depending on having already a To: field or not */
1058 if ((!to)||(*to == '\0')) {
1059 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1061 gtk_widget_grab_focus (priv->msg_body);
1064 /* TODO: lower priority, select in the From: combo to the
1065 value that comes from msg <- not sure, should it be
1068 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1070 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1071 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1073 modest_msg_edit_window_reset_modified (self);
1075 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1076 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1077 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1079 if (priv->msg_uid) {
1080 g_free (priv->msg_uid);
1081 priv->msg_uid = NULL;
1084 /* we should set a reference to the incoming message if it is a draft */
1085 msg_folder = tny_msg_get_folder (msg);
1087 if (modest_tny_folder_is_local_folder (msg_folder)) {
1088 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1089 if (type == TNY_FOLDER_TYPE_INVALID)
1090 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1092 if (type == TNY_FOLDER_TYPE_DRAFTS)
1093 priv->draft_msg = g_object_ref(msg);
1094 if (type == TNY_FOLDER_TYPE_OUTBOX)
1095 priv->outbox_msg = g_object_ref(msg);
1096 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1098 g_object_unref (msg_folder);
1103 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1106 GList *item_children, *node;
1107 GtkWidget *bin_child;
1109 bin_child = gtk_bin_get_child (GTK_BIN(item));
1111 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1113 for (node = item_children; node != NULL; node = g_list_next (node)) {
1114 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1115 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1118 g_list_free (item_children);
1122 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1125 GList *item_children, *node;
1127 box = gtk_bin_get_child (GTK_BIN (item));
1128 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1129 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1131 for (node = item_children; node != NULL; node = g_list_next (node)) {
1132 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1133 if (GTK_IS_TOGGLE_BUTTON (node->data))
1134 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1135 else if (GTK_IS_BUTTON (node->data))
1136 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1138 g_list_free (item_children);
1143 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1145 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1146 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1147 GtkWidget *placeholder;
1148 GtkWidget *tool_item;
1153 GtkWidget *sizes_menu;
1154 GtkWidget *fonts_menu;
1155 GSList *radio_group = NULL;
1156 GSList *node = NULL;
1160 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1161 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1163 /* Font color placeholder */
1164 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1165 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1168 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1169 priv->font_color_button = hildon_color_button_new ();
1170 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1171 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1172 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1173 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1174 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1175 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1176 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1178 G_CALLBACK (modest_msg_edit_window_color_button_change),
1181 /* Font size and face placeholder */
1182 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1183 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1185 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1186 priv->size_tool_button_label = gtk_label_new (NULL);
1187 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1188 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1189 size_text,"</span>", NULL);
1190 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1192 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1193 sizes_menu = gtk_menu_new ();
1194 priv->size_items_group = NULL;
1196 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1197 GtkWidget *size_menu_item;
1199 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1200 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1201 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1202 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1203 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1204 gtk_widget_show (size_menu_item);
1206 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1210 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1211 GtkWidget *item = (GtkWidget *) node->data;
1212 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1216 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1217 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1218 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1219 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1220 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1221 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1222 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1223 priv->font_size_toolitem = tool_item;
1226 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1227 priv->font_tool_button_label = gtk_label_new (NULL);
1228 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1229 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1231 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1232 fonts_menu = gtk_menu_new ();
1233 priv->font_items_group = NULL;
1235 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1236 GtkWidget *font_menu_item;
1237 GtkWidget *child_label;
1239 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1240 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1241 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1242 wp_get_font_name (font_index), "</span>", NULL);
1243 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1246 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1247 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1248 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1249 gtk_widget_show (font_menu_item);
1251 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1254 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1255 GtkWidget *item = (GtkWidget *) node->data;
1256 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1259 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1260 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1261 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1262 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
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 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1266 priv->font_face_toolitem = tool_item;
1268 /* Set expand and homogeneous for remaining items */
1269 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1270 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1271 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1272 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1273 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1274 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1275 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1276 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1277 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1279 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1280 will not show the tool items added to the placeholders) */
1281 gtk_widget_show_all (parent_priv->toolbar);
1283 /* Set the no show all *after* showing all items. We do not
1284 want the toolbar to be shown with a show all because it
1285 could go agains the gconf setting regarding showing or not
1286 the toolbar of the editor window */
1287 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1293 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1296 ModestWindowPrivate *parent_priv;
1297 ModestMsgEditWindowPrivate *priv;
1298 ModestPair *account_pair = NULL;
1299 ModestDimmingRulesGroup *menu_rules_group = NULL;
1300 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1301 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1302 ModestWindowMgr *mgr = NULL;
1304 g_return_val_if_fail (msg, NULL);
1305 g_return_val_if_fail (account_name, NULL);
1307 mgr = modest_runtime_get_window_mgr ();
1309 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1311 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1312 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1314 /* Menubar. Update the state of some toggles */
1315 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1316 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1317 priv->from_field_protos = get_transports ();
1318 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1319 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1320 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1323 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1325 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1327 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1329 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1330 if (account_pair != NULL)
1331 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1333 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1334 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1335 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1336 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1337 /* Add common dimming rules */
1338 modest_dimming_rules_group_add_rules (menu_rules_group,
1339 modest_msg_edit_window_menu_dimming_entries,
1340 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1341 MODEST_WINDOW (obj));
1342 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1343 modest_msg_edit_window_toolbar_dimming_entries,
1344 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1345 MODEST_WINDOW (obj));
1346 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1347 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1348 MODEST_WINDOW (obj));
1349 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1350 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1351 MODEST_WINDOW (obj));
1352 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1353 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1354 MODEST_WINDOW (obj));
1355 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1356 modest_msg_edit_window_clipboard_dimming_entries,
1357 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1358 MODEST_WINDOW (obj));
1359 /* Insert dimming rules group for this window */
1360 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1361 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1362 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1363 /* Checks the dimming rules */
1364 g_object_unref (menu_rules_group);
1365 g_object_unref (toolbar_rules_group);
1366 g_object_unref (clipboard_rules_group);
1368 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1370 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1372 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1373 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1374 priv->update_caption_visibility = TRUE;
1376 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1378 /* Track account-removed signal, this window should be closed
1379 in the case we're creating a mail associated to the account
1381 priv->account_removed_handler_id =
1382 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1384 G_CALLBACK(on_account_removed),
1387 return (ModestWindow*) obj;
1391 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1393 GString **string_buffer = (GString **) user_data;
1395 *string_buffer = g_string_append (*string_buffer, buffer);
1401 * @result: A new string which should be freed with g_free().
1404 get_formatted_data (ModestMsgEditWindow *edit_window)
1406 ModestMsgEditWindowPrivate *priv;
1407 GString *string_buffer = g_string_new ("");
1409 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1411 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1413 return g_string_free (string_buffer, FALSE);
1418 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1421 const gchar *account_name;
1422 ModestMsgEditWindowPrivate *priv;
1424 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1426 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1428 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1429 g_return_val_if_fail (account_name, NULL);
1432 /* don't free these (except from) */
1433 data = g_slice_new0 (MsgData);
1434 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1436 data->account_name = g_strdup (account_name);
1437 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1438 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1439 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1440 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1441 if (priv->draft_msg) {
1442 data->draft_msg = g_object_ref (priv->draft_msg);
1443 } else if (priv->outbox_msg) {
1444 data->draft_msg = g_object_ref (priv->outbox_msg);
1446 data->draft_msg = NULL;
1449 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1451 gtk_text_buffer_get_bounds (buf, &b, &e);
1452 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1454 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1455 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1457 data->html_body = NULL;
1459 /* deep-copy the data */
1460 GList *cursor = priv->attachments;
1461 data->attachments = NULL;
1463 if (!(TNY_IS_MIME_PART(cursor->data))) {
1464 g_warning ("strange data in attachment list");
1465 cursor = g_list_next (cursor);
1468 data->attachments = g_list_append (data->attachments,
1469 g_object_ref (cursor->data));
1470 cursor = g_list_next (cursor);
1473 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1474 cursor = priv->images;
1475 data->images = NULL;
1478 if (!(TNY_IS_MIME_PART(cursor->data))) {
1479 g_warning ("strange data in attachment list");
1480 cursor = g_list_next (cursor);
1483 cid = tny_mime_part_get_content_id (cursor->data);
1485 gchar *image_tag_id;
1486 GtkTextTag *image_tag;
1488 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1489 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1490 g_free (image_tag_id);
1492 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1494 ((gtk_text_iter_has_tag (&iter, image_tag))||
1495 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1496 data->images = g_list_append (data->images,
1497 g_object_ref (cursor->data));
1499 cursor = g_list_next (cursor);
1502 data->priority_flags = priv->priority_flags;
1509 unref_gobject (GObject *obj, gpointer data)
1511 if (!G_IS_OBJECT(obj))
1513 g_object_unref (obj);
1517 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1520 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1528 g_free (data->from);
1529 g_free (data->subject);
1530 g_free (data->plain_body);
1531 g_free (data->html_body);
1532 g_free (data->account_name);
1534 if (data->draft_msg != NULL) {
1535 g_object_unref (data->draft_msg);
1536 data->draft_msg = NULL;
1539 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1540 g_list_free (data->attachments);
1541 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1542 g_list_free (data->images);
1544 g_slice_free (MsgData, data);
1548 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1551 ModestMsgEditWindowPrivate *priv = NULL;
1552 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1554 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1556 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1558 return MODEST_MSG_EDIT_FORMAT_HTML;
1560 return MODEST_MSG_EDIT_FORMAT_TEXT;
1564 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1565 ModestMsgEditFormat format)
1567 ModestMsgEditWindowPrivate *priv;
1569 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1570 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1573 case MODEST_MSG_EDIT_FORMAT_HTML:
1574 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1576 case MODEST_MSG_EDIT_FORMAT_TEXT:
1577 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1580 g_return_if_reached ();
1584 ModestMsgEditFormatState *
1585 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1587 ModestMsgEditFormatState *format_state = NULL;
1588 ModestMsgEditWindowPrivate *priv;
1589 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1591 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1592 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1594 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1596 format_state = g_new0 (ModestMsgEditFormatState, 1);
1597 format_state->bold = buffer_format->bold&0x1;
1598 format_state->italics = buffer_format->italic&0x1;
1599 format_state->bullet = buffer_format->bullet&0x1;
1600 format_state->color = buffer_format->color;
1601 format_state->font_size = buffer_format->font_size;
1602 format_state->font_family = wp_get_font_name (buffer_format->font);
1603 format_state->justification = buffer_format->justification;
1604 g_free (buffer_format);
1606 return format_state;
1611 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1612 const ModestMsgEditFormatState *format_state)
1614 ModestMsgEditWindowPrivate *priv;
1615 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1616 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1617 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1618 g_return_if_fail (format_state != NULL);
1620 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1621 gtk_widget_grab_focus (priv->msg_body);
1622 buffer_format->bold = (format_state->bold != FALSE);
1623 buffer_format->italic = (format_state->italics != FALSE);
1624 buffer_format->color = format_state->color;
1625 buffer_format->font_size = format_state->font_size;
1626 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1627 buffer_format->justification = format_state->justification;
1628 buffer_format->bullet = format_state->bullet;
1630 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1632 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1633 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1634 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1635 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1636 buffer_format->cs.font = (buffer_format->font != current_format->font);
1637 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1638 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1640 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1641 if (buffer_format->cs.bold) {
1642 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1643 GINT_TO_POINTER (buffer_format->bold&0x1));
1645 if (buffer_format->cs.italic) {
1646 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1647 GINT_TO_POINTER (buffer_format->italic&0x1));
1649 if (buffer_format->cs.color) {
1650 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1651 GINT_TO_POINTER (&(buffer_format->color)));
1653 if (buffer_format->cs.font_size) {
1654 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1655 GINT_TO_POINTER (buffer_format->font_size));
1657 if (buffer_format->cs.justification) {
1658 switch (buffer_format->justification) {
1659 case GTK_JUSTIFY_LEFT:
1660 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1661 GINT_TO_POINTER(TRUE));
1663 case GTK_JUSTIFY_CENTER:
1664 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1665 GINT_TO_POINTER(TRUE));
1667 case GTK_JUSTIFY_RIGHT:
1668 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1669 GINT_TO_POINTER(TRUE));
1676 if (buffer_format->cs.font) {
1677 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1678 GINT_TO_POINTER (buffer_format->font));
1680 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1681 if (buffer_format->cs.bullet) {
1682 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1683 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1685 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1687 g_free (current_format);
1692 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1694 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1696 ModestWindowPrivate *parent_priv;
1697 ModestMsgEditWindowPrivate *priv;
1698 GtkWidget *new_size_menuitem;
1699 GtkWidget *new_font_menuitem;
1701 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1702 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1704 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1705 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1706 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1707 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1709 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1710 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1711 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1714 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1716 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1717 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1719 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1720 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1722 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1723 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1725 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1726 G_CALLBACK (modest_msg_edit_window_color_button_change),
1728 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1729 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1730 G_CALLBACK (modest_msg_edit_window_color_button_change),
1733 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1734 buffer_format->font_size))->data);
1735 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1739 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1740 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1741 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1743 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1744 G_CALLBACK (modest_msg_edit_window_size_change),
1746 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1747 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1748 G_CALLBACK (modest_msg_edit_window_size_change),
1752 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1753 buffer_format->font))->data);
1754 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1758 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1759 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1760 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1762 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1763 G_CALLBACK (modest_msg_edit_window_font_change),
1765 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1766 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1767 G_CALLBACK (modest_msg_edit_window_font_change),
1771 g_free (buffer_format);
1775 #ifdef MODEST_HILDON_VERSION_0
1777 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1780 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1781 ModestMsgEditWindowPrivate *priv;
1782 GtkWidget *dialog = NULL;
1784 GdkColor *new_color = NULL;
1786 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1787 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1789 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1790 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1791 g_free (buffer_format);
1793 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1794 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1795 if (new_color != NULL) {
1796 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1797 (gpointer) new_color);
1800 gtk_widget_destroy (dialog);
1805 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1808 ModestMsgEditWindowPrivate *priv;
1809 GtkWidget *dialog = NULL;
1811 GdkColor *old_color = NULL;
1812 const GdkColor *new_color = NULL;
1814 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1815 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1817 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1818 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1820 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1821 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1822 if (new_color != NULL)
1823 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1825 gtk_widget_destroy (dialog);
1831 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1834 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1835 ModestMsgEditWindowPrivate *priv;
1836 GtkWidget *dialog = NULL;
1838 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1839 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1841 dialog = hildon_color_chooser_new ();
1842 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1843 g_free (buffer_format);
1845 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1847 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1848 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1851 gtk_widget_destroy (dialog);
1856 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1859 ModestMsgEditWindowPrivate *priv;
1860 GtkWidget *dialog = NULL;
1861 GdkColor *old_color = NULL;
1863 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1864 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1866 dialog = hildon_color_chooser_new ();
1867 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1869 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1871 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1872 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1874 gtk_widget_destroy (dialog);
1877 #endif /*!MODEST_HILDON_VERSION_0*/
1881 static TnyStream* create_stream_for_uri (const gchar* uri)
1886 TnyStream *result = NULL;
1888 GnomeVFSHandle *handle = NULL;
1889 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1890 if (test == GNOME_VFS_OK) {
1891 /* Create the tinymail stream: */
1892 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1893 result = TNY_STREAM (tny_vfs_stream_new (handle));
1900 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1903 ModestMsgEditWindowPrivate *priv;
1904 GtkWidget *dialog = NULL;
1906 GSList *uris = NULL;
1907 GSList *uri_node = NULL;
1909 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1911 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1912 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1913 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1915 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1917 response = gtk_dialog_run (GTK_DIALOG (dialog));
1919 case GTK_RESPONSE_OK:
1920 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1925 gtk_widget_destroy (dialog);
1927 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1929 GnomeVFSHandle *handle = NULL;
1930 GnomeVFSResult result;
1931 GtkTextIter position;
1932 GtkTextMark *insert_mark;
1934 uri = (const gchar *) uri_node->data;
1935 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1936 if (result == GNOME_VFS_OK) {
1938 GnomeVFSFileInfo info;
1939 gchar *filename, *basename, *escaped_filename;
1940 TnyMimePart *mime_part;
1942 const gchar *mime_type = NULL;
1943 GnomeVFSURI *vfs_uri;
1945 vfs_uri = gnome_vfs_uri_new (uri);
1947 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1948 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1949 g_free (escaped_filename);
1950 gnome_vfs_uri_unref (vfs_uri);
1952 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1953 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1955 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1957 mime_part = tny_platform_factory_new_mime_part
1958 (modest_runtime_get_platform_factory ());
1960 TnyStream *stream = create_stream_for_uri (uri);
1961 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1963 content_id = g_strdup_printf ("%d", priv->last_cid);
1964 tny_mime_part_set_content_id (mime_part, content_id);
1965 g_free (content_id);
1968 basename = g_path_get_basename (filename);
1969 tny_mime_part_set_filename (mime_part, basename);
1972 pixbuf = pixbuf_from_stream (stream, mime_type);
1974 if (pixbuf != NULL) {
1975 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1976 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1977 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1980 priv->images = g_list_prepend (priv->images, mime_part);
1981 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1991 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1993 GtkWidget *dialog = NULL;
1995 GSList *uris = NULL;
1998 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1999 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2000 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2002 response = gtk_dialog_run (GTK_DIALOG (dialog));
2004 case GTK_RESPONSE_OK:
2005 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2010 gtk_widget_destroy (dialog);
2012 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2013 const gchar *uri = (const gchar *) uri_node->data;
2014 modest_msg_edit_window_attach_file_one (window, uri);
2016 g_slist_foreach (uris, (GFunc) g_free, NULL);
2017 g_slist_free (uris);
2021 modest_msg_edit_window_attach_file_one (
2022 ModestMsgEditWindow *window,
2025 g_return_if_fail (window);
2026 g_return_if_fail (uri);
2028 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2031 GnomeVFSHandle *handle = NULL;
2032 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2033 if (result == GNOME_VFS_OK) {
2034 TnyMimePart *mime_part;
2036 const gchar *mime_type = NULL;
2038 gchar *escaped_filename;
2041 GnomeVFSFileInfo info;
2042 GnomeVFSURI *vfs_uri;
2044 vfs_uri = gnome_vfs_uri_new (uri);
2047 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2048 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2049 g_free (escaped_filename);
2050 gnome_vfs_uri_unref (vfs_uri);
2052 if (gnome_vfs_get_file_info (uri,
2054 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2055 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2057 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2058 mime_part = tny_platform_factory_new_mime_part
2059 (modest_runtime_get_platform_factory ());
2060 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2062 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2064 content_id = g_strdup_printf ("%d", priv->last_cid);
2065 tny_mime_part_set_content_id (mime_part, content_id);
2066 g_free (content_id);
2069 basename = g_path_get_basename (filename);
2070 tny_mime_part_set_filename (mime_part, basename);
2073 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2074 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2076 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2077 gtk_widget_show_all (priv->attachments_caption);
2078 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2084 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2087 ModestMsgEditWindowPrivate *priv;
2088 gboolean clean_list = FALSE;
2090 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2091 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2093 if (att_list == NULL) {
2094 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2098 if (att_list == NULL) {
2099 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2101 GtkWidget *confirmation_dialog = NULL;
2102 gboolean dialog_response;
2104 gchar *message = NULL;
2105 gchar *filename = NULL;
2107 if (att_list->next == NULL) {
2108 if (TNY_IS_MSG (att_list->data)) {
2109 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2111 filename = g_strdup (tny_header_get_subject (header));
2112 g_object_unref (header);
2114 if (filename == NULL) {
2115 filename = g_strdup (_("mail_va_no_subject"));
2118 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2121 filename = g_strdup ("");
2123 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2124 att_list->next == NULL), filename);
2126 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2128 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2129 gtk_widget_destroy (confirmation_dialog);
2130 if (!dialog_response) {
2132 g_list_free (att_list);
2135 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2137 for (node = att_list; node != NULL; node = g_list_next (node)) {
2138 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2139 const gchar *att_id;
2140 priv->attachments = g_list_remove (priv->attachments, mime_part);
2142 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2144 if (priv->attachments == NULL)
2145 gtk_widget_hide (priv->attachments_caption);
2146 att_id = tny_mime_part_get_content_id (mime_part);
2148 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2150 g_object_unref (mime_part);
2151 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2156 g_list_free (att_list);
2160 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2163 ModestMsgEditWindowPrivate *priv;
2164 GdkColor *new_color;
2165 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2167 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2168 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2171 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2173 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2175 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2177 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2182 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2185 ModestMsgEditWindowPrivate *priv;
2186 gint new_size_index;
2187 ModestMsgEditWindow *window;
2190 window = MODEST_MSG_EDIT_WINDOW (userdata);
2191 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2192 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2194 if (gtk_check_menu_item_get_active (menu_item)) {
2196 WPTextBufferFormat format;
2198 memset (&format, 0, sizeof (format));
2199 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2201 label = gtk_bin_get_child (GTK_BIN (menu_item));
2203 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2204 format.cs.font_size = TRUE;
2205 format.cs.text_position = TRUE;
2206 format.cs.font = TRUE;
2207 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2208 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2210 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2211 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2212 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2214 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2215 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2216 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2222 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2225 ModestMsgEditWindowPrivate *priv;
2226 gint new_font_index;
2227 ModestMsgEditWindow *window;
2230 window = MODEST_MSG_EDIT_WINDOW (userdata);
2231 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2232 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2234 if (gtk_check_menu_item_get_active (menu_item)) {
2237 label = gtk_bin_get_child (GTK_BIN (menu_item));
2239 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2241 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2242 GINT_TO_POINTER(new_font_index)))
2243 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2245 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2246 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2247 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2253 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2255 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2256 ModestWindowPrivate *parent_priv;
2257 ModestWindowMgr *mgr;
2258 gboolean is_fullscreen;
2259 GtkAction *fs_toggle_action;
2262 mgr = modest_runtime_get_window_mgr ();
2263 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2265 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2267 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2268 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2269 if (is_fullscreen != active)
2270 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2278 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2281 ModestMsgEditWindowPrivate *priv = NULL;
2282 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2284 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2285 if (!priv->update_caption_visibility)
2288 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2290 gtk_widget_show (priv->cc_caption);
2292 gtk_widget_hide (priv->cc_caption);
2294 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2298 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2301 ModestMsgEditWindowPrivate *priv = NULL;
2302 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2304 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2305 if (!priv->update_caption_visibility)
2308 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2310 gtk_widget_show (priv->bcc_caption);
2312 gtk_widget_hide (priv->bcc_caption);
2314 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2318 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2319 ModestRecptEditor *editor)
2321 ModestMsgEditWindowPrivate *priv;
2323 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2324 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2325 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2327 if (editor == NULL) {
2328 GtkWidget *view_focus;
2329 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2331 /* This code should be kept in sync with ModestRecptEditor. The
2332 textview inside the recpt editor is the one that really gets the
2333 focus. As it's inside a scrolled window, and this one inside the
2334 hbox recpt editor inherits from, we'll need to go up in the
2335 hierarchy to know if the text view is part of the recpt editor
2336 or if it's a different text entry */
2338 if (gtk_widget_get_parent (view_focus)) {
2339 GtkWidget *first_parent;
2341 first_parent = gtk_widget_get_parent (view_focus);
2342 if (gtk_widget_get_parent (first_parent) &&
2343 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2344 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2349 editor = MODEST_RECPT_EDITOR (priv->to_field);
2353 modest_address_book_select_addresses (editor);
2358 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2360 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2362 modest_msg_edit_window_open_addressbook (window, NULL);
2366 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2367 gboolean show_toolbar)
2369 ModestWindowPrivate *parent_priv;
2370 const gchar *action_name;
2373 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2374 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2376 /* We can not just use the code of
2377 modest_msg_edit_window_setup_toolbar because it has a
2378 mixture of both initialization and creation code. */
2380 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2382 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2384 /* Update also the actions (to update the toggles in the
2385 menus), we have to do it manually because some other window
2386 of the same time could have changed it (remember that the
2387 toolbar fullscreen mode is shared by all the windows of the
2389 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2390 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2392 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2394 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2395 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2401 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2402 TnyHeaderFlags priority_flags)
2404 ModestMsgEditWindowPrivate *priv;
2405 ModestWindowPrivate *parent_priv;
2407 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2409 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2410 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2412 if (priv->priority_flags != priority_flags) {
2413 GtkAction *priority_action = NULL;
2415 priv->priority_flags = priority_flags;
2417 switch (priority_flags) {
2418 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2419 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2420 gtk_widget_show (priv->priority_icon);
2421 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2422 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2424 case TNY_HEADER_FLAG_LOW_PRIORITY:
2425 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2426 gtk_widget_show (priv->priority_icon);
2427 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2428 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2431 gtk_widget_hide (priv->priority_icon);
2432 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2433 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2436 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2437 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2442 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2445 ModestMsgEditWindowPrivate *priv;
2446 ModestWindowPrivate *parent_priv;
2447 gint current_format;
2449 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2451 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2452 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2454 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2455 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2457 if (current_format != file_format) {
2458 switch (file_format) {
2459 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2460 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2461 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2463 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2467 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2468 response = gtk_dialog_run (GTK_DIALOG (dialog));
2469 gtk_widget_destroy (dialog);
2470 if (response == GTK_RESPONSE_OK) {
2471 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2473 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2474 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2479 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2484 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2487 ModestMsgEditWindowPrivate *priv;
2488 WPTextBufferFormat oldfmt, fmt;
2489 gint old_position = 0;
2493 GdkColor *color = NULL;
2494 gboolean bold, bold_set, italic, italic_set;
2495 gboolean underline, underline_set;
2496 gboolean strikethrough, strikethrough_set;
2497 gboolean position_set;
2498 gboolean font_size_set, font_set, color_set;
2501 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2502 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2504 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2506 /* First we get the currently selected font information */
2507 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2509 switch (oldfmt.text_position) {
2510 case TEXT_POSITION_NORMAL:
2513 case TEXT_POSITION_SUPERSCRIPT:
2521 g_object_set (G_OBJECT (dialog),
2522 "bold", oldfmt.bold != FALSE,
2523 "bold-set", !oldfmt.cs.bold,
2524 "underline", oldfmt.underline != FALSE,
2525 "underline-set", !oldfmt.cs.underline,
2526 "italic", oldfmt.italic != FALSE,
2527 "italic-set", !oldfmt.cs.italic,
2528 "strikethrough", oldfmt.strikethrough != FALSE,
2529 "strikethrough-set", !oldfmt.cs.strikethrough,
2530 "color", &oldfmt.color,
2531 "color-set", !oldfmt.cs.color,
2532 "size", wp_font_size[oldfmt.font_size],
2533 "size-set", !oldfmt.cs.font_size,
2534 "position", old_position,
2535 "position-set", !oldfmt.cs.text_position,
2536 "family", wp_get_font_name (oldfmt.font),
2537 "family-set", !oldfmt.cs.font,
2540 gtk_widget_show_all (dialog);
2541 response = gtk_dialog_run (GTK_DIALOG (dialog));
2542 if (response == GTK_RESPONSE_OK) {
2544 g_object_get( dialog,
2546 "bold-set", &bold_set,
2547 "underline", &underline,
2548 "underline-set", &underline_set,
2550 "italic-set", &italic_set,
2551 "strikethrough", &strikethrough,
2552 "strikethrough-set", &strikethrough_set,
2554 "color-set", &color_set,
2556 "size-set", &font_size_set,
2557 "family", &font_name,
2558 "family-set", &font_set,
2559 "position", &position,
2560 "position-set", &position_set,
2565 if (response == GTK_RESPONSE_OK) {
2566 memset(&fmt, 0, sizeof(fmt));
2572 fmt.italic = italic;
2573 fmt.cs.italic = TRUE;
2575 if (underline_set) {
2576 fmt.underline = underline;
2577 fmt.cs.underline = TRUE;
2579 if (strikethrough_set) {
2580 fmt.strikethrough = strikethrough;
2581 fmt.cs.strikethrough = TRUE;
2586 ? TEXT_POSITION_NORMAL
2587 : ( ( position == 1 )
2588 ? TEXT_POSITION_SUPERSCRIPT
2589 : TEXT_POSITION_SUBSCRIPT );
2590 fmt.cs.text_position = TRUE;
2591 fmt.font_size = oldfmt.font_size;
2595 fmt.cs.color = TRUE;
2598 fmt.font = wp_get_font_index(font_name,
2603 if (font_size_set) {
2604 fmt.cs.font_size = TRUE;
2605 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2607 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2608 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2610 gtk_widget_destroy (dialog);
2612 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2616 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2618 ModestMsgEditWindowPrivate *priv;
2620 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2621 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2623 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2625 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2630 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2632 ModestMsgEditWindowPrivate *priv;
2634 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2635 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2637 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2639 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2644 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2646 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2648 priv->can_undo = can_undo;
2652 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2654 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2656 priv->can_redo = can_redo;
2660 modest_msg_edit_window_can_undo (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_undo;
2670 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2672 ModestMsgEditWindowPrivate *priv;
2673 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2674 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2676 return priv->can_redo;
2681 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2684 GtkTextIter match_start, match_end;
2686 if (image_id == NULL)
2689 gtk_text_buffer_get_start_iter (buffer, &iter);
2691 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2692 GSList *tags = gtk_text_iter_get_tags (&match_start);
2694 for (node = tags; node != NULL; node = g_slist_next (node)) {
2695 GtkTextTag *tag = (GtkTextTag *) node->data;
2696 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2697 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2698 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2700 offset = gtk_text_iter_get_offset (&match_start);
2701 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2702 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2706 gtk_text_iter_forward_char (&iter);
2711 message_is_empty (ModestMsgEditWindow *window)
2713 ModestMsgEditWindowPrivate *priv = NULL;
2715 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2716 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2718 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2719 * so we can ignore markup.
2721 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2724 count = gtk_text_buffer_get_char_count (buf);
2730 msg_body_focus (GtkWidget *focus,
2731 GdkEventFocus *event,
2735 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2740 recpt_field_changed (GtkTextBuffer *buffer,
2741 ModestMsgEditWindow *editor)
2743 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2747 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2749 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2753 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2755 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2756 GtkTextBuffer *buffer;
2758 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2759 gtk_text_buffer_set_modified (buffer, FALSE);
2760 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2761 gtk_text_buffer_set_modified (buffer, FALSE);
2762 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2763 gtk_text_buffer_set_modified (buffer, FALSE);
2764 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2768 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2770 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2771 GtkTextBuffer *buffer;
2773 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2774 if (gtk_text_buffer_get_modified (buffer))
2776 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2777 if (gtk_text_buffer_get_modified (buffer))
2779 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2780 if (gtk_text_buffer_get_modified (buffer))
2782 if (gtk_text_buffer_get_modified (priv->text_buffer))
2792 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2794 ModestMsgEditWindowPrivate *priv = NULL;
2796 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2797 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2799 /* check if there's no recipient added */
2800 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2801 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2802 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2803 /* no recipient contents, then select contacts */
2804 modest_msg_edit_window_open_addressbook (window, NULL);
2808 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2809 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2812 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2813 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2816 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2817 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2821 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2822 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2823 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2830 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2831 ModestMsgEditWindow *window)
2833 modest_msg_edit_window_offer_attach_file (window);
2837 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2839 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2841 return priv->clipboard_text;
2845 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2847 ModestMsgEditWindow *window)
2849 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2850 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2852 if (!GTK_WIDGET_VISIBLE (window))
2855 text = gtk_clipboard_wait_for_text (selection_clipboard);
2857 if (priv->clipboard_text != NULL) {
2858 g_free (priv->clipboard_text);
2860 priv->clipboard_text = text;
2862 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2865 subject_field_move_cursor (GtkEntry *entry,
2866 GtkMovementStep step,
2871 if (!GTK_WIDGET_VISIBLE (window))
2874 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2878 update_window_title (ModestMsgEditWindow *window)
2880 ModestMsgEditWindowPrivate *priv = NULL;
2881 const gchar *subject;
2883 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2884 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2885 if (subject == NULL || subject[0] == '\0')
2886 subject = _("mail_va_new_email");
2888 gtk_window_set_title (GTK_WINDOW (window), subject);
2893 subject_field_changed (GtkEditable *editable,
2894 ModestMsgEditWindow *window)
2896 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2897 update_window_title (window);
2898 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2899 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2903 subject_field_insert_text (GtkEditable *editable,
2905 gint new_text_length,
2907 ModestMsgEditWindow *window)
2909 GString *result = g_string_new ("");
2911 gint result_len = 0;
2912 const gchar *entry_text = NULL;
2915 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2916 old_length = g_utf8_strlen (entry_text, -1);
2918 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2919 gunichar c = g_utf8_get_char_validated (current, 8);
2920 /* Invalid unichar, stop */
2926 result = g_string_append_unichar (result, c);
2930 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2931 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2934 /* Prevent endless recursion */
2935 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2936 g_signal_emit_by_name (editable, "insert-text",
2937 (gpointer) result->str, (gpointer) result->len,
2938 (gpointer) position, (gpointer) window);
2939 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2943 if (result_len + old_length > 1000) {
2944 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2945 dgettext("hildon-common-strings",
2946 "ckdg_ib_maximum_characters_reached"));
2949 g_string_free (result, TRUE);
2953 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2956 ModestMsgEditWindowPrivate *priv = NULL;
2958 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2959 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2961 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2964 gtk_widget_show_all (priv->find_toolbar);
2965 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2967 gtk_widget_hide_all (priv->find_toolbar);
2968 gtk_widget_grab_focus (priv->msg_body);
2974 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2976 GtkTextIter *match_start,
2977 GtkTextIter *match_end)
2979 GtkTextIter end_iter;
2980 gchar *str_casefold;
2983 gchar *range_casefold;
2986 gboolean result = FALSE;
2993 gtk_text_iter_forward_to_end (&end_iter);
2995 str_casefold = g_utf8_casefold (str, -1);
2996 str_chars_n = strlen (str);
2998 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2999 range_casefold = g_utf8_casefold (range_text, -1);
3000 range_chars_n = strlen (range_casefold);
3002 if (range_chars_n < str_chars_n) {
3003 g_free (str_casefold);
3004 g_free (range_text);
3005 g_free (range_casefold);
3009 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3010 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3011 if (!g_utf8_collate (range_subtext, str_casefold)) {
3012 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3014 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3015 match_start, match_end, NULL);
3016 g_free (found_text);
3018 g_free (range_subtext);
3022 g_free (str_casefold);
3023 g_free (range_text);
3024 g_free (range_casefold);
3031 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3032 ModestMsgEditWindow *window)
3034 gchar *current_search = NULL;
3035 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3037 GtkTextIter selection_start, selection_end;
3038 GtkTextIter match_start, match_end;
3039 gboolean continue_search = FALSE;
3041 if (message_is_empty (window)) {
3042 g_free (priv->last_search);
3043 priv->last_search = NULL;
3044 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3048 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3049 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3050 g_free (current_search);
3051 g_free (priv->last_search);
3052 priv->last_search = NULL;
3053 /* Information banner about empty search */
3054 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3058 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3059 continue_search = TRUE;
3061 g_free (priv->last_search);
3062 priv->last_search = g_strdup (current_search);
3065 if (continue_search) {
3066 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3067 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3068 &match_start, &match_end);
3070 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3072 GtkTextIter buffer_start;
3073 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3074 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3075 &match_start, &match_end);
3077 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3080 /* Mark as selected the string found in search */
3082 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3083 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3085 g_free (priv->last_search);
3086 priv->last_search = NULL;
3088 g_free (current_search);
3092 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3093 ModestMsgEditWindow *window)
3095 GtkToggleAction *toggle;
3096 ModestWindowPrivate *parent_priv;
3097 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3099 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3100 gtk_toggle_action_set_active (toggle, FALSE);
3104 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3106 ModestMsgEditWindowPrivate *priv;
3108 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3113 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3116 ModestMsgEditWindowPrivate *priv;
3118 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3124 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3127 ModestMsgEditWindowPrivate *priv;
3128 TnyHeader *header = NULL;
3130 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3131 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3133 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3134 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3136 if (priv->draft_msg != NULL) {
3137 g_object_unref (priv->draft_msg);
3140 if (draft != NULL) {
3141 g_object_ref (draft);
3142 header = tny_msg_get_header (draft);
3143 if (priv->msg_uid) {
3144 g_free (priv->msg_uid);
3145 priv->msg_uid = NULL;
3147 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3148 if (GTK_WIDGET_REALIZED (window))
3149 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3152 priv->draft_msg = draft;
3156 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3157 GtkTextIter *start, GtkTextIter *end,
3160 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3161 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3164 if (tag == NULL+13) return;
3165 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3166 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3167 replace_with_images (window, priv->images);
3172 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3175 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3177 g_return_if_fail (TNY_IS_MIME_PART (part));
3178 priv->attachments = g_list_prepend (priv->attachments, part);
3179 g_object_ref (part);
3180 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3181 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3182 gtk_widget_show_all (priv->attachments_caption);
3183 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3187 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3189 ModestMsgEditWindowPrivate *priv;
3191 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3192 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3194 return priv->msg_uid;
3198 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3199 ModestMsgEditWindowWidgetType widget_type)
3201 ModestMsgEditWindowPrivate *priv;
3203 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3204 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3206 switch (widget_type) {
3207 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3208 return priv->msg_body;
3210 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3211 return priv->to_field;
3213 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3214 return priv->cc_field;
3216 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3217 return priv->bcc_field;
3219 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3220 return priv->subject_field;
3222 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3223 return priv->attachments_view;
3231 remove_tags (WPTextBuffer *buffer)
3233 GtkTextIter start, end;
3235 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3236 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3238 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3242 on_account_removed (TnyAccountStore *account_store,
3243 TnyAccount *account,
3246 /* Do nothing if it's a store account, because we use the
3247 transport to send the messages */
3248 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3249 const gchar *parent_acc = NULL;
3250 const gchar *our_acc = NULL;
3252 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3253 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3254 /* Close this window if I'm showing a message of the removed account */
3255 if (strcmp (parent_acc, our_acc) == 0)
3256 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3261 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3263 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3265 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3271 set_zoom_do_nothing (ModestWindow *window,
3277 get_zoom_do_nothing (ModestWindow *window)