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)
172 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 ();
429 /* FIXME: this is a dup from the one in gtk/ */
432 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
434 static ModestPairList*
435 get_transports (void)
437 GSList *transports = NULL;
439 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
440 GSList *accounts = modest_account_mgr_account_names (account_mgr,
441 TRUE /* only enabled accounts. */);
443 GSList *cursor = accounts;
445 gchar *account_name = cursor->data;
446 gchar *from_string = NULL;
448 from_string = modest_account_mgr_get_from_string (account_mgr,
452 if (from_string && account_name) {
453 gchar *name = account_name;
454 ModestPair *pair = modest_pair_new ((gpointer) name,
455 (gpointer) from_string , TRUE);
456 transports = g_slist_prepend (transports, pair);
459 cursor = cursor->next;
461 g_slist_free (accounts); /* only free the accounts, not the elements,
462 * because they are used in the pairlist */
466 void vadj_changed (GtkAdjustment *adj,
467 ModestMsgEditWindow *window)
469 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
471 GdkRectangle rectangle, cursor_rectangle;
472 GtkTextIter position;
476 /* We detect if cursor is visible using the full height, not only the center. This
478 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
479 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
481 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
482 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
484 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
485 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
487 if (gtk_widget_is_focus (priv->msg_body) &&
489 if (priv->last_vadj_upper != adj->upper) {
492 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
493 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
494 insert, 0.1, FALSE, 0.0, 0.0);
497 priv->last_vadj_upper = adj->upper;
502 connect_signals (ModestMsgEditWindow *obj)
504 ModestMsgEditWindowPrivate *priv;
506 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
508 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
509 G_CALLBACK (text_buffer_refresh_attributes), obj);
510 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
511 G_CALLBACK (text_buffer_can_undo), obj);
512 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
513 G_CALLBACK (text_buffer_can_redo), obj);
514 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
515 G_CALLBACK (body_changed), obj);
516 g_signal_connect (G_OBJECT (obj), "window-state-event",
517 G_CALLBACK (modest_msg_edit_window_window_state_event),
519 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
520 G_CALLBACK (text_buffer_apply_tag), obj);
521 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
522 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
523 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
524 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
525 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
526 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
528 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
529 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
531 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
532 G_CALLBACK (msg_body_focus), obj);
533 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
534 G_CALLBACK (msg_body_focus), obj);
535 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
536 "changed", G_CALLBACK (recpt_field_changed), obj);
537 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
538 "changed", G_CALLBACK (recpt_field_changed), obj);
539 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
540 "changed", G_CALLBACK (recpt_field_changed), obj);
541 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
542 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
543 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
545 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
546 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
548 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
550 G_CALLBACK (vadj_changed),
553 priv->clipboard_change_handler_id =
554 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
555 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
556 priv->default_clipboard_change_handler_id =
557 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
558 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
563 menubar_to_menu (GtkUIManager *ui_manager)
565 GtkWidget *main_menu;
567 /* Get the menubar from the UI manager */
568 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
574 init_window (ModestMsgEditWindow *obj)
576 GtkWidget *from_caption, *to_caption, *subject_caption;
577 GtkWidget *main_vbox;
578 ModestMsgEditWindowPrivate *priv;
579 GtkActionGroup *action_group;
580 ModestWindowPrivate *parent_priv;
581 GdkPixbuf *window_icon = NULL;
582 GError *error = NULL;
584 GtkSizeGroup *size_group;
586 GtkWidget *subject_box;
587 GtkWidget *attachment_icon;
588 GtkWidget *window_box;
589 #if (GTK_MINOR_VERSION >= 10)
590 GdkAtom deserialize_type;
592 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
593 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
595 parent_priv->ui_manager = gtk_ui_manager_new();
596 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
597 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
599 /* Add common actions */
600 gtk_action_group_add_actions (action_group,
601 modest_msg_edit_action_entries,
602 G_N_ELEMENTS (modest_msg_edit_action_entries),
604 gtk_action_group_add_toggle_actions (action_group,
605 modest_msg_edit_toggle_action_entries,
606 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
608 gtk_action_group_add_radio_actions (action_group,
609 modest_msg_edit_alignment_radio_action_entries,
610 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
612 G_CALLBACK (modest_ui_actions_on_change_justify),
614 gtk_action_group_add_radio_actions (action_group,
615 modest_msg_edit_priority_action_entries,
616 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
618 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
620 gtk_action_group_add_radio_actions (action_group,
621 modest_msg_edit_file_format_action_entries,
622 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
623 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
624 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
626 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
627 g_object_unref (action_group);
629 /* Load the UI definition */
630 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
633 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
634 g_clear_error (&error);
637 /* Add accelerators */
638 gtk_window_add_accel_group (GTK_WINDOW (obj),
639 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
641 parent_priv->menubar = NULL;
643 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
645 /* Note: This ModestPairList* must exist for as long as the combo
646 * that uses it, because the ModestComboBox uses the ID opaquely,
647 * so it can't know how to manage its memory. */
648 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
650 priv->to_field = modest_recpt_editor_new ();
651 priv->cc_field = modest_recpt_editor_new ();
652 priv->bcc_field = modest_recpt_editor_new ();
653 subject_box = gtk_hbox_new (FALSE, 0);
654 priv->priority_icon = gtk_image_new ();
655 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
656 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
657 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
658 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
659 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
660 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
661 priv->add_attachment_button = gtk_button_new ();
662 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
663 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
664 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
665 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
666 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
667 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
668 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
669 priv->attachments_view = modest_attachments_view_new (NULL);
671 priv->header_box = gtk_vbox_new (FALSE, 0);
673 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
674 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
675 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
676 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
677 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
678 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
679 g_object_unref (size_group);
681 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
682 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
683 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
684 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
685 gtk_size_group_add_widget (size_group, priv->subject_field);
686 gtk_size_group_add_widget (size_group, priv->attachments_view);
687 g_object_unref (size_group);
689 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
690 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
691 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
692 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
694 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
695 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
698 priv->msg_body = wp_text_view_new ();
699 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
700 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
701 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
702 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
703 #if (GTK_MINOR_VERSION >= 10)
704 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
705 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
707 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
708 deserialize_type, TRUE);
710 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
712 priv->find_toolbar = hildon_find_toolbar_new (NULL);
713 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
715 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
717 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
718 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
719 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
720 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
722 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
724 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
725 frame = gtk_frame_new (NULL);
726 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
728 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
729 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
730 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
732 G_CALLBACK (vadj_changed),
734 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
736 window_box = gtk_vbox_new (FALSE, 0);
737 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
738 gtk_container_add (GTK_CONTAINER(obj), window_box);
739 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
740 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
742 /* Set window icon */
743 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
745 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
746 g_object_unref (window_icon);
752 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
754 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
756 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
757 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
758 priv->clipboard_change_handler_id))
759 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
760 priv->clipboard_change_handler_id);
761 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
762 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
763 priv->default_clipboard_change_handler_id))
764 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
765 priv->default_clipboard_change_handler_id);
767 if (priv->account_removed_handler_id &&
768 g_signal_handler_is_connected (modest_runtime_get_account_store (),
769 priv->account_removed_handler_id))
770 g_signal_handler_disconnect(modest_runtime_get_account_store (),
771 priv->account_removed_handler_id);
775 modest_msg_edit_window_finalize (GObject *obj)
777 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
779 /* Sanity check: shouldn't be needed, the window mgr should
780 call this function before */
781 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
783 if (priv->clipboard_text != NULL) {
784 g_free (priv->clipboard_text);
785 priv->clipboard_text = NULL;
788 if (priv->draft_msg != NULL) {
789 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
790 if (TNY_IS_HEADER (header)) {
791 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
792 modest_window_mgr_unregister_header (mgr, header);
794 g_object_unref (priv->draft_msg);
795 priv->draft_msg = NULL;
797 if (priv->outbox_msg != NULL) {
798 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
799 if (TNY_IS_HEADER (header)) {
800 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
801 modest_window_mgr_unregister_header (mgr, header);
803 g_object_unref (priv->outbox_msg);
804 priv->outbox_msg = NULL;
806 g_free (priv->msg_uid);
807 g_free (priv->last_search);
808 g_slist_free (priv->font_items_group);
809 g_slist_free (priv->size_items_group);
810 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
811 g_list_free (priv->attachments);
812 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
813 g_list_free (priv->images);
815 /* This had to stay alive for as long as the combobox that used it: */
816 modest_pair_list_free (priv->from_field_protos);
818 G_OBJECT_CLASS(parent_class)->finalize (obj);
822 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
824 GdkPixbufLoader *loader;
827 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
832 tny_stream_reset (TNY_STREAM (stream));
833 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
834 unsigned char read_buffer[128];
836 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
837 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
841 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
842 g_object_ref (pixbuf);
843 gdk_pixbuf_loader_close (loader, NULL);
844 g_object_unref (loader);
846 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
847 GdkPixbuf *new_pixbuf;
849 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
850 gdk_pixbuf_get_width (pixbuf);
851 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
852 g_object_unref (pixbuf);
860 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
862 ModestMsgEditWindowPrivate *priv;
865 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
867 for (node = attachments; node != NULL; node = g_list_next (node)) {
868 TnyMimePart *part = (TnyMimePart *) node->data;
869 const gchar *cid = tny_mime_part_get_content_id (part);
870 const gchar *mime_type = tny_mime_part_get_content_type (part);
871 if ((cid != NULL)&&(mime_type != NULL)) {
872 TnyStream *stream = tny_mime_part_get_stream (part);
873 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
874 g_object_unref (stream);
876 if (pixbuf != NULL) {
877 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
878 g_object_unref (pixbuf);
885 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
887 TnyMimePart *parent = NULL;
888 const gchar *content_type = NULL;
889 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
891 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
893 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
894 parent = g_object_ref (msg);
895 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
896 TnyList *parts = TNY_LIST (tny_simple_list_new ());
899 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
900 iter = tny_list_create_iterator (parts);
901 while (!tny_iterator_is_done (iter)) {
903 part = TNY_MIME_PART (tny_iterator_get_current (iter));
904 content_type = tny_mime_part_get_content_type (part);
905 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
909 g_object_unref (part);
911 tny_iterator_next (iter);
913 g_object_unref (iter);
914 g_object_unref (parts);
917 if (parent != NULL) {
918 TnyList *parts = TNY_LIST (tny_simple_list_new ());
921 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
922 iter = tny_list_create_iterator (parts);
923 while (!tny_iterator_is_done (iter)) {
925 part = TNY_MIME_PART (tny_iterator_get_current (iter));
926 content_type = tny_mime_part_get_content_type (part);
927 if (content_type && g_str_has_prefix (content_type, "image/")) {
928 priv->images = g_list_prepend (priv->images, part);
930 g_object_unref (part);
932 tny_iterator_next (iter);
934 g_object_unref (iter);
935 g_object_unref (parts);
936 g_object_unref (parent);
941 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
944 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
946 for (node = attachments; node != NULL; node = g_list_next (node)) {
947 TnyMimePart *part = (TnyMimePart *) node->data;
948 const gchar *cid = tny_mime_part_get_content_id (part);
950 char *invalid = NULL;
951 gint int_cid = strtol (cid, &invalid, 10);
952 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
953 priv->last_cid = int_cid;
961 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
964 const gchar *to, *cc, *bcc, *subject;
966 ModestMsgEditWindowPrivate *priv;
968 TnyHeaderFlags priority_flags;
969 TnyFolder *msg_folder;
970 gboolean is_html = FALSE;
972 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
973 g_return_if_fail (TNY_IS_MSG (msg));
975 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
977 header = tny_msg_get_header (msg);
978 to = tny_header_get_to (header);
979 cc = tny_header_get_cc (header);
980 bcc = tny_header_get_bcc (header);
981 subject = tny_header_get_subject (header);
982 priority_flags = tny_header_get_priority (header);
985 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
987 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
988 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
989 gtk_widget_show (priv->cc_caption);
990 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
991 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
992 gtk_widget_hide (priv->cc_caption);
995 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
996 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
997 gtk_widget_show (priv->bcc_caption);
998 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
999 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1000 gtk_widget_hide (priv->bcc_caption);
1003 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1004 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1007 update_window_title (self);
1009 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1010 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1012 if ((body == NULL)||(body[0] == '\0')) {
1014 body = modest_text_utils_convert_to_html ("");
1017 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1018 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1021 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1024 /* Add attachments to the view */
1025 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1026 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1027 if (priv->attachments == NULL) {
1028 gtk_widget_hide (priv->attachments_caption);
1030 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1031 gtk_widget_show_all (priv->attachments_caption);
1033 get_related_images (self, msg);
1034 update_last_cid (self, priv->attachments);
1035 update_last_cid (self, priv->images);
1036 replace_with_images (self, priv->images);
1038 if (preserve_is_rich && !is_html) {
1039 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1040 /* Get the default format required from configuration */
1041 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1042 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1045 /* Set the default focus depending on having already a To: field or not */
1046 if ((!to)||(*to == '\0')) {
1047 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1049 gtk_widget_grab_focus (priv->msg_body);
1052 /* TODO: lower priority, select in the From: combo to the
1053 value that comes from msg <- not sure, should it be
1056 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1058 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1059 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1061 modest_msg_edit_window_reset_modified (self);
1063 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1064 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1065 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1067 if (priv->msg_uid) {
1068 g_free (priv->msg_uid);
1069 priv->msg_uid = NULL;
1072 /* we should set a reference to the incoming message if it is a draft */
1073 msg_folder = tny_msg_get_folder (msg);
1075 if (modest_tny_folder_is_local_folder (msg_folder)) {
1076 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1077 if (type == TNY_FOLDER_TYPE_INVALID)
1078 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1080 if (type == TNY_FOLDER_TYPE_DRAFTS)
1081 priv->draft_msg = g_object_ref(msg);
1082 if (type == TNY_FOLDER_TYPE_OUTBOX)
1083 priv->outbox_msg = g_object_ref(msg);
1084 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1086 g_object_unref (msg_folder);
1091 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1094 GList *item_children, *node;
1095 GtkWidget *bin_child;
1097 bin_child = gtk_bin_get_child (GTK_BIN(item));
1099 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1101 for (node = item_children; node != NULL; node = g_list_next (node)) {
1102 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1103 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1106 g_list_free (item_children);
1110 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1113 GList *item_children, *node;
1115 box = gtk_bin_get_child (GTK_BIN (item));
1116 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1117 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1119 for (node = item_children; node != NULL; node = g_list_next (node)) {
1120 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1121 if (GTK_IS_TOGGLE_BUTTON (node->data))
1122 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1123 else if (GTK_IS_BUTTON (node->data))
1124 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1126 g_list_free (item_children);
1131 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1133 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1134 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1135 GtkWidget *placeholder;
1136 GtkWidget *tool_item;
1141 GtkWidget *sizes_menu;
1142 GtkWidget *fonts_menu;
1143 GSList *radio_group = NULL;
1144 GSList *node = NULL;
1148 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1149 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1151 /* Font color placeholder */
1152 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1153 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1156 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1157 priv->font_color_button = hildon_color_button_new ();
1158 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1159 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1160 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1161 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1162 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1163 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1164 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1166 G_CALLBACK (modest_msg_edit_window_color_button_change),
1169 /* Font size and face placeholder */
1170 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1171 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1173 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1174 priv->size_tool_button_label = gtk_label_new (NULL);
1175 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1176 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1177 size_text,"</span>", NULL);
1178 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1180 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1181 sizes_menu = gtk_menu_new ();
1182 priv->size_items_group = NULL;
1184 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1185 GtkWidget *size_menu_item;
1187 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1188 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1189 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1190 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1191 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1192 gtk_widget_show (size_menu_item);
1194 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1198 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1199 GtkWidget *item = (GtkWidget *) node->data;
1200 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1204 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1205 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1206 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1207 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1208 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1209 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1210 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1211 priv->font_size_toolitem = tool_item;
1214 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1215 priv->font_tool_button_label = gtk_label_new (NULL);
1216 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1217 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1219 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1220 fonts_menu = gtk_menu_new ();
1221 priv->font_items_group = NULL;
1223 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1224 GtkWidget *font_menu_item;
1225 GtkWidget *child_label;
1227 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1228 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1229 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1230 wp_get_font_name (font_index), "</span>", NULL);
1231 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1234 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1235 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1236 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1237 gtk_widget_show (font_menu_item);
1239 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1242 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1243 GtkWidget *item = (GtkWidget *) node->data;
1244 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1247 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1248 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1249 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1250 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1251 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1252 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1253 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1254 priv->font_face_toolitem = tool_item;
1256 /* Set expand and homogeneous for remaining items */
1257 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1258 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1259 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1260 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1261 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1262 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1263 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1264 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1265 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1267 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1268 will not show the tool items added to the placeholders) */
1269 gtk_widget_show_all (parent_priv->toolbar);
1271 /* Set the no show all *after* showing all items. We do not
1272 want the toolbar to be shown with a show all because it
1273 could go agains the gconf setting regarding showing or not
1274 the toolbar of the editor window */
1275 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1281 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1284 ModestWindowPrivate *parent_priv;
1285 ModestMsgEditWindowPrivate *priv;
1286 ModestPair *account_pair = NULL;
1287 ModestDimmingRulesGroup *menu_rules_group = NULL;
1288 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1289 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1290 ModestWindowMgr *mgr = NULL;
1292 g_return_val_if_fail (msg, NULL);
1293 g_return_val_if_fail (account_name, NULL);
1295 mgr = modest_runtime_get_window_mgr ();
1297 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1299 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1300 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1302 /* Menubar. Update the state of some toggles */
1303 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1304 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1305 priv->from_field_protos = get_transports ();
1306 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1307 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1308 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1311 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1313 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1315 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1317 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1318 if (account_pair != NULL)
1319 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1321 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1322 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1323 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1324 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1325 /* Add common dimming rules */
1326 modest_dimming_rules_group_add_rules (menu_rules_group,
1327 modest_msg_edit_window_menu_dimming_entries,
1328 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1329 MODEST_WINDOW (obj));
1330 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1331 modest_msg_edit_window_toolbar_dimming_entries,
1332 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1333 MODEST_WINDOW (obj));
1334 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1335 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1336 MODEST_WINDOW (obj));
1337 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1338 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1339 MODEST_WINDOW (obj));
1340 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1341 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1342 MODEST_WINDOW (obj));
1343 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1344 modest_msg_edit_window_clipboard_dimming_entries,
1345 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1346 MODEST_WINDOW (obj));
1347 /* Insert dimming rules group for this window */
1348 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1349 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1350 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1351 /* Checks the dimming rules */
1352 g_object_unref (menu_rules_group);
1353 g_object_unref (toolbar_rules_group);
1354 g_object_unref (clipboard_rules_group);
1356 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1358 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1360 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1361 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1362 priv->update_caption_visibility = TRUE;
1364 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1366 /* Track account-removed signal, this window should be closed
1367 in the case we're creating a mail associated to the account
1369 priv->account_removed_handler_id =
1370 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1372 G_CALLBACK(on_account_removed),
1375 return (ModestWindow*) obj;
1379 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1381 GString **string_buffer = (GString **) user_data;
1383 *string_buffer = g_string_append (*string_buffer, buffer);
1389 * @result: A new string which should be freed with g_free().
1392 get_formatted_data (ModestMsgEditWindow *edit_window)
1394 ModestMsgEditWindowPrivate *priv;
1395 GString *string_buffer = g_string_new ("");
1397 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1399 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1401 return g_string_free (string_buffer, FALSE);
1406 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1409 const gchar *account_name;
1410 ModestMsgEditWindowPrivate *priv;
1412 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1414 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1416 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1417 g_return_val_if_fail (account_name, NULL);
1420 /* don't free these (except from) */
1421 data = g_slice_new0 (MsgData);
1422 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1424 data->account_name = g_strdup (account_name);
1425 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1426 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1427 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1428 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1429 if (priv->draft_msg) {
1430 data->draft_msg = g_object_ref (priv->draft_msg);
1431 } else if (priv->outbox_msg) {
1432 data->draft_msg = g_object_ref (priv->outbox_msg);
1434 data->draft_msg = NULL;
1437 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1439 gtk_text_buffer_get_bounds (buf, &b, &e);
1440 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1442 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1443 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1445 data->html_body = NULL;
1447 /* deep-copy the data */
1448 GList *cursor = priv->attachments;
1449 data->attachments = NULL;
1451 if (!(TNY_IS_MIME_PART(cursor->data))) {
1452 g_warning ("strange data in attachment list");
1453 cursor = g_list_next (cursor);
1456 data->attachments = g_list_append (data->attachments,
1457 g_object_ref (cursor->data));
1458 cursor = g_list_next (cursor);
1461 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1462 cursor = priv->images;
1463 data->images = NULL;
1466 if (!(TNY_IS_MIME_PART(cursor->data))) {
1467 g_warning ("strange data in attachment list");
1468 cursor = g_list_next (cursor);
1471 cid = tny_mime_part_get_content_id (cursor->data);
1473 gchar *image_tag_id;
1474 GtkTextTag *image_tag;
1476 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1477 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1478 g_free (image_tag_id);
1480 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1482 ((gtk_text_iter_has_tag (&iter, image_tag))||
1483 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1484 data->images = g_list_append (data->images,
1485 g_object_ref (cursor->data));
1487 cursor = g_list_next (cursor);
1490 data->priority_flags = priv->priority_flags;
1497 unref_gobject (GObject *obj, gpointer data)
1499 if (!G_IS_OBJECT(obj))
1501 g_object_unref (obj);
1505 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1508 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1516 g_free (data->from);
1517 g_free (data->subject);
1518 g_free (data->plain_body);
1519 g_free (data->html_body);
1520 g_free (data->account_name);
1522 if (data->draft_msg != NULL) {
1523 g_object_unref (data->draft_msg);
1524 data->draft_msg = NULL;
1527 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1528 g_list_free (data->attachments);
1529 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1530 g_list_free (data->images);
1532 g_slice_free (MsgData, data);
1536 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1539 ModestMsgEditWindowPrivate *priv = NULL;
1540 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1542 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1544 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1546 return MODEST_MSG_EDIT_FORMAT_HTML;
1548 return MODEST_MSG_EDIT_FORMAT_TEXT;
1552 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1553 ModestMsgEditFormat format)
1555 ModestMsgEditWindowPrivate *priv;
1557 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1558 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1561 case MODEST_MSG_EDIT_FORMAT_HTML:
1562 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1564 case MODEST_MSG_EDIT_FORMAT_TEXT:
1565 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1568 g_return_if_reached ();
1572 ModestMsgEditFormatState *
1573 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1575 ModestMsgEditFormatState *format_state = NULL;
1576 ModestMsgEditWindowPrivate *priv;
1577 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1579 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1580 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1582 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1584 format_state = g_new0 (ModestMsgEditFormatState, 1);
1585 format_state->bold = buffer_format->bold&0x1;
1586 format_state->italics = buffer_format->italic&0x1;
1587 format_state->bullet = buffer_format->bullet&0x1;
1588 format_state->color = buffer_format->color;
1589 format_state->font_size = buffer_format->font_size;
1590 format_state->font_family = wp_get_font_name (buffer_format->font);
1591 format_state->justification = buffer_format->justification;
1592 g_free (buffer_format);
1594 return format_state;
1599 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1600 const ModestMsgEditFormatState *format_state)
1602 ModestMsgEditWindowPrivate *priv;
1603 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1604 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1605 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1606 g_return_if_fail (format_state != NULL);
1608 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1609 gtk_widget_grab_focus (priv->msg_body);
1610 buffer_format->bold = (format_state->bold != FALSE);
1611 buffer_format->italic = (format_state->italics != FALSE);
1612 buffer_format->color = format_state->color;
1613 buffer_format->font_size = format_state->font_size;
1614 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1615 buffer_format->justification = format_state->justification;
1616 buffer_format->bullet = format_state->bullet;
1618 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1620 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1621 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1622 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1623 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1624 buffer_format->cs.font = (buffer_format->font != current_format->font);
1625 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1626 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1628 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1629 if (buffer_format->cs.bold) {
1630 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1631 GINT_TO_POINTER (buffer_format->bold&0x1));
1633 if (buffer_format->cs.italic) {
1634 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1635 GINT_TO_POINTER (buffer_format->italic&0x1));
1637 if (buffer_format->cs.color) {
1638 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1639 GINT_TO_POINTER (&(buffer_format->color)));
1641 if (buffer_format->cs.font_size) {
1642 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1643 GINT_TO_POINTER (buffer_format->font_size));
1645 if (buffer_format->cs.justification) {
1646 switch (buffer_format->justification) {
1647 case GTK_JUSTIFY_LEFT:
1648 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1649 GINT_TO_POINTER(TRUE));
1651 case GTK_JUSTIFY_CENTER:
1652 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1653 GINT_TO_POINTER(TRUE));
1655 case GTK_JUSTIFY_RIGHT:
1656 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1657 GINT_TO_POINTER(TRUE));
1664 if (buffer_format->cs.font) {
1665 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1666 GINT_TO_POINTER (buffer_format->font));
1668 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1669 if (buffer_format->cs.bullet) {
1670 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1671 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1673 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1675 g_free (current_format);
1680 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1682 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1684 ModestWindowPrivate *parent_priv;
1685 ModestMsgEditWindowPrivate *priv;
1686 GtkWidget *new_size_menuitem;
1687 GtkWidget *new_font_menuitem;
1689 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1690 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1692 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1693 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1694 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1695 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1697 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1698 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1699 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1702 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1704 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1705 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1707 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1708 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1710 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1711 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1713 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1714 G_CALLBACK (modest_msg_edit_window_color_button_change),
1716 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1717 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1718 G_CALLBACK (modest_msg_edit_window_color_button_change),
1721 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1722 buffer_format->font_size))->data);
1723 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1727 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1728 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1729 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1731 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1732 G_CALLBACK (modest_msg_edit_window_size_change),
1734 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1735 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1736 G_CALLBACK (modest_msg_edit_window_size_change),
1740 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1741 buffer_format->font))->data);
1742 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1746 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1747 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1748 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1750 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1751 G_CALLBACK (modest_msg_edit_window_font_change),
1753 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1754 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1755 G_CALLBACK (modest_msg_edit_window_font_change),
1759 g_free (buffer_format);
1763 #ifdef MODEST_HILDON_VERSION_0
1765 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1768 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1769 ModestMsgEditWindowPrivate *priv;
1770 GtkWidget *dialog = NULL;
1772 GdkColor *new_color = NULL;
1774 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1775 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1777 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1778 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1779 g_free (buffer_format);
1781 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1782 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1783 if (new_color != NULL) {
1784 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1785 (gpointer) new_color);
1788 gtk_widget_destroy (dialog);
1793 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1796 ModestMsgEditWindowPrivate *priv;
1797 GtkWidget *dialog = NULL;
1799 GdkColor *old_color = NULL;
1800 const GdkColor *new_color = NULL;
1802 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1803 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1805 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1806 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1808 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1809 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1810 if (new_color != NULL)
1811 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1813 gtk_widget_destroy (dialog);
1819 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1822 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1823 ModestMsgEditWindowPrivate *priv;
1824 GtkWidget *dialog = NULL;
1826 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1827 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1829 dialog = hildon_color_chooser_new ();
1830 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1831 g_free (buffer_format);
1833 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1835 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1836 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1839 gtk_widget_destroy (dialog);
1844 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1847 ModestMsgEditWindowPrivate *priv;
1848 GtkWidget *dialog = NULL;
1849 GdkColor *old_color = NULL;
1851 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1852 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1854 dialog = hildon_color_chooser_new ();
1855 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1857 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1859 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1860 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1862 gtk_widget_destroy (dialog);
1865 #endif /*!MODEST_HILDON_VERSION_0*/
1869 static TnyStream* create_stream_for_uri (const gchar* uri)
1874 TnyStream *result = NULL;
1876 GnomeVFSHandle *handle = NULL;
1877 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1878 if (test == GNOME_VFS_OK) {
1879 /* Create the tinymail stream: */
1880 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1881 result = TNY_STREAM (tny_vfs_stream_new (handle));
1888 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1891 ModestMsgEditWindowPrivate *priv;
1892 GtkWidget *dialog = NULL;
1894 GSList *uris = NULL;
1895 GSList *uri_node = NULL;
1897 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1899 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1900 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1901 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1903 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1905 response = gtk_dialog_run (GTK_DIALOG (dialog));
1907 case GTK_RESPONSE_OK:
1908 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1913 gtk_widget_destroy (dialog);
1915 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1917 GnomeVFSHandle *handle = NULL;
1918 GnomeVFSResult result;
1919 GtkTextIter position;
1920 GtkTextMark *insert_mark;
1922 uri = (const gchar *) uri_node->data;
1923 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1924 if (result == GNOME_VFS_OK) {
1926 GnomeVFSFileInfo info;
1927 gchar *filename, *basename, *escaped_filename;
1928 TnyMimePart *mime_part;
1930 const gchar *mime_type = NULL;
1931 GnomeVFSURI *vfs_uri;
1933 vfs_uri = gnome_vfs_uri_new (uri);
1935 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1936 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1937 g_free (escaped_filename);
1938 gnome_vfs_uri_unref (vfs_uri);
1940 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1941 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1943 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1945 mime_part = tny_platform_factory_new_mime_part
1946 (modest_runtime_get_platform_factory ());
1948 TnyStream *stream = create_stream_for_uri (uri);
1949 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1951 content_id = g_strdup_printf ("%d", priv->last_cid);
1952 tny_mime_part_set_content_id (mime_part, content_id);
1953 g_free (content_id);
1956 basename = g_path_get_basename (filename);
1957 tny_mime_part_set_filename (mime_part, basename);
1960 pixbuf = pixbuf_from_stream (stream, mime_type);
1962 if (pixbuf != NULL) {
1963 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1964 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1965 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1968 priv->images = g_list_prepend (priv->images, mime_part);
1969 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1979 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1981 GtkWidget *dialog = NULL;
1983 GSList *uris = NULL;
1986 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1987 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1988 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1990 response = gtk_dialog_run (GTK_DIALOG (dialog));
1992 case GTK_RESPONSE_OK:
1993 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1998 gtk_widget_destroy (dialog);
2000 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2001 const gchar *uri = (const gchar *) uri_node->data;
2002 modest_msg_edit_window_attach_file_one (window, uri);
2004 g_slist_foreach (uris, (GFunc) g_free, NULL);
2005 g_slist_free (uris);
2009 modest_msg_edit_window_attach_file_one (
2010 ModestMsgEditWindow *window,
2013 g_return_if_fail (window);
2014 g_return_if_fail (uri);
2016 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2019 GnomeVFSHandle *handle = NULL;
2020 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2021 if (result == GNOME_VFS_OK) {
2022 TnyMimePart *mime_part;
2024 const gchar *mime_type = NULL;
2026 gchar *escaped_filename;
2029 GnomeVFSFileInfo info;
2030 GnomeVFSURI *vfs_uri;
2032 vfs_uri = gnome_vfs_uri_new (uri);
2035 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2036 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2037 g_free (escaped_filename);
2038 gnome_vfs_uri_unref (vfs_uri);
2040 if (gnome_vfs_get_file_info (uri,
2042 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2043 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2045 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2046 mime_part = tny_platform_factory_new_mime_part
2047 (modest_runtime_get_platform_factory ());
2048 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2050 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2052 content_id = g_strdup_printf ("%d", priv->last_cid);
2053 tny_mime_part_set_content_id (mime_part, content_id);
2054 g_free (content_id);
2057 basename = g_path_get_basename (filename);
2058 tny_mime_part_set_filename (mime_part, basename);
2061 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2062 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2064 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2065 gtk_widget_show_all (priv->attachments_caption);
2066 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2072 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2075 ModestMsgEditWindowPrivate *priv;
2076 gboolean clean_list = FALSE;
2078 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2079 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2081 if (att_list == NULL) {
2082 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2086 if (att_list == NULL) {
2087 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2089 GtkWidget *confirmation_dialog = NULL;
2090 gboolean dialog_response;
2092 gchar *message = NULL;
2093 gchar *filename = NULL;
2095 if (att_list->next == NULL) {
2096 if (TNY_IS_MSG (att_list->data)) {
2097 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2099 filename = g_strdup (tny_header_get_subject (header));
2100 g_object_unref (header);
2102 if (filename == NULL) {
2103 filename = g_strdup (_("mail_va_no_subject"));
2106 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2109 filename = g_strdup ("");
2111 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2112 att_list->next == NULL), filename);
2114 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2116 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2117 gtk_widget_destroy (confirmation_dialog);
2118 if (!dialog_response) {
2120 g_list_free (att_list);
2123 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2125 for (node = att_list; node != NULL; node = g_list_next (node)) {
2126 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2127 const gchar *att_id;
2128 priv->attachments = g_list_remove (priv->attachments, mime_part);
2130 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2132 if (priv->attachments == NULL)
2133 gtk_widget_hide (priv->attachments_caption);
2134 att_id = tny_mime_part_get_content_id (mime_part);
2136 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2138 g_object_unref (mime_part);
2139 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2144 g_list_free (att_list);
2148 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2151 ModestMsgEditWindowPrivate *priv;
2152 GdkColor *new_color;
2153 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2155 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2156 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2159 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2161 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2163 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2165 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2170 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2173 ModestMsgEditWindowPrivate *priv;
2174 gint new_size_index;
2175 ModestMsgEditWindow *window;
2178 window = MODEST_MSG_EDIT_WINDOW (userdata);
2179 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2180 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2182 if (gtk_check_menu_item_get_active (menu_item)) {
2184 WPTextBufferFormat format;
2186 memset (&format, 0, sizeof (format));
2187 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2189 label = gtk_bin_get_child (GTK_BIN (menu_item));
2191 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2192 format.cs.font_size = TRUE;
2193 format.cs.text_position = TRUE;
2194 format.cs.font = TRUE;
2195 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2196 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2198 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2199 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2200 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2202 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2203 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2204 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2210 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2213 ModestMsgEditWindowPrivate *priv;
2214 gint new_font_index;
2215 ModestMsgEditWindow *window;
2218 window = MODEST_MSG_EDIT_WINDOW (userdata);
2219 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2220 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2222 if (gtk_check_menu_item_get_active (menu_item)) {
2225 label = gtk_bin_get_child (GTK_BIN (menu_item));
2227 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2229 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2230 GINT_TO_POINTER(new_font_index)))
2231 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2233 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2234 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2235 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2241 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2243 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2244 ModestWindowPrivate *parent_priv;
2245 ModestWindowMgr *mgr;
2246 gboolean is_fullscreen;
2247 GtkAction *fs_toggle_action;
2250 mgr = modest_runtime_get_window_mgr ();
2251 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2253 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2255 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2256 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2257 if (is_fullscreen != active)
2258 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2266 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2269 ModestMsgEditWindowPrivate *priv = NULL;
2270 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2272 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2273 if (!priv->update_caption_visibility)
2276 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2278 gtk_widget_show (priv->cc_caption);
2280 gtk_widget_hide (priv->cc_caption);
2282 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2286 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2289 ModestMsgEditWindowPrivate *priv = NULL;
2290 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2292 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2293 if (!priv->update_caption_visibility)
2296 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2298 gtk_widget_show (priv->bcc_caption);
2300 gtk_widget_hide (priv->bcc_caption);
2302 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2306 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2307 ModestRecptEditor *editor)
2309 ModestMsgEditWindowPrivate *priv;
2311 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2312 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2313 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2315 if (editor == NULL) {
2316 GtkWidget *view_focus;
2317 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2319 /* This code should be kept in sync with ModestRecptEditor. The
2320 textview inside the recpt editor is the one that really gets the
2321 focus. As it's inside a scrolled window, and this one inside the
2322 hbox recpt editor inherits from, we'll need to go up in the
2323 hierarchy to know if the text view is part of the recpt editor
2324 or if it's a different text entry */
2326 if (gtk_widget_get_parent (view_focus)) {
2327 GtkWidget *first_parent;
2329 first_parent = gtk_widget_get_parent (view_focus);
2330 if (gtk_widget_get_parent (first_parent) &&
2331 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2332 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2337 editor = MODEST_RECPT_EDITOR (priv->to_field);
2341 modest_address_book_select_addresses (editor);
2346 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2348 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2350 modest_msg_edit_window_open_addressbook (window, NULL);
2354 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2355 gboolean show_toolbar)
2357 ModestWindowPrivate *parent_priv;
2358 const gchar *action_name;
2361 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2362 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2364 /* We can not just use the code of
2365 modest_msg_edit_window_setup_toolbar because it has a
2366 mixture of both initialization and creation code. */
2368 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2370 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2372 /* Update also the actions (to update the toggles in the
2373 menus), we have to do it manually because some other window
2374 of the same time could have changed it (remember that the
2375 toolbar fullscreen mode is shared by all the windows of the
2377 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2378 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2380 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2382 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2383 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2389 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2390 TnyHeaderFlags priority_flags)
2392 ModestMsgEditWindowPrivate *priv;
2393 ModestWindowPrivate *parent_priv;
2395 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2397 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2398 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2400 if (priv->priority_flags != priority_flags) {
2401 GtkAction *priority_action = NULL;
2403 priv->priority_flags = priority_flags;
2405 switch (priority_flags) {
2406 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2407 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2408 gtk_widget_show (priv->priority_icon);
2409 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2410 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2412 case TNY_HEADER_FLAG_LOW_PRIORITY:
2413 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2414 gtk_widget_show (priv->priority_icon);
2415 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2416 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2419 gtk_widget_hide (priv->priority_icon);
2420 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2421 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2424 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2425 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2430 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2433 ModestMsgEditWindowPrivate *priv;
2434 ModestWindowPrivate *parent_priv;
2435 gint current_format;
2437 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2439 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2440 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2442 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2443 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2445 if (current_format != file_format) {
2446 switch (file_format) {
2447 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2448 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2449 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2451 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2455 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2456 response = gtk_dialog_run (GTK_DIALOG (dialog));
2457 gtk_widget_destroy (dialog);
2458 if (response == GTK_RESPONSE_OK) {
2459 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2461 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2462 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2467 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2472 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2475 ModestMsgEditWindowPrivate *priv;
2476 WPTextBufferFormat oldfmt, fmt;
2477 gint old_position = 0;
2481 GdkColor *color = NULL;
2482 gboolean bold, bold_set, italic, italic_set;
2483 gboolean underline, underline_set;
2484 gboolean strikethrough, strikethrough_set;
2485 gboolean position_set;
2486 gboolean font_size_set, font_set, color_set;
2489 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2490 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2492 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2494 /* First we get the currently selected font information */
2495 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2497 switch (oldfmt.text_position) {
2498 case TEXT_POSITION_NORMAL:
2501 case TEXT_POSITION_SUPERSCRIPT:
2509 g_object_set (G_OBJECT (dialog),
2510 "bold", oldfmt.bold != FALSE,
2511 "bold-set", !oldfmt.cs.bold,
2512 "underline", oldfmt.underline != FALSE,
2513 "underline-set", !oldfmt.cs.underline,
2514 "italic", oldfmt.italic != FALSE,
2515 "italic-set", !oldfmt.cs.italic,
2516 "strikethrough", oldfmt.strikethrough != FALSE,
2517 "strikethrough-set", !oldfmt.cs.strikethrough,
2518 "color", &oldfmt.color,
2519 "color-set", !oldfmt.cs.color,
2520 "size", wp_font_size[oldfmt.font_size],
2521 "size-set", !oldfmt.cs.font_size,
2522 "position", old_position,
2523 "position-set", !oldfmt.cs.text_position,
2524 "family", wp_get_font_name (oldfmt.font),
2525 "family-set", !oldfmt.cs.font,
2528 gtk_widget_show_all (dialog);
2529 response = gtk_dialog_run (GTK_DIALOG (dialog));
2530 if (response == GTK_RESPONSE_OK) {
2532 g_object_get( dialog,
2534 "bold-set", &bold_set,
2535 "underline", &underline,
2536 "underline-set", &underline_set,
2538 "italic-set", &italic_set,
2539 "strikethrough", &strikethrough,
2540 "strikethrough-set", &strikethrough_set,
2542 "color-set", &color_set,
2544 "size-set", &font_size_set,
2545 "family", &font_name,
2546 "family-set", &font_set,
2547 "position", &position,
2548 "position-set", &position_set,
2553 if (response == GTK_RESPONSE_OK) {
2554 memset(&fmt, 0, sizeof(fmt));
2560 fmt.italic = italic;
2561 fmt.cs.italic = TRUE;
2563 if (underline_set) {
2564 fmt.underline = underline;
2565 fmt.cs.underline = TRUE;
2567 if (strikethrough_set) {
2568 fmt.strikethrough = strikethrough;
2569 fmt.cs.strikethrough = TRUE;
2574 ? TEXT_POSITION_NORMAL
2575 : ( ( position == 1 )
2576 ? TEXT_POSITION_SUPERSCRIPT
2577 : TEXT_POSITION_SUBSCRIPT );
2578 fmt.cs.text_position = TRUE;
2579 fmt.font_size = oldfmt.font_size;
2583 fmt.cs.color = TRUE;
2586 fmt.font = wp_get_font_index(font_name,
2591 if (font_size_set) {
2592 fmt.cs.font_size = TRUE;
2593 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2595 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2596 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2598 gtk_widget_destroy (dialog);
2600 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2604 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2606 ModestMsgEditWindowPrivate *priv;
2608 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2609 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2611 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2613 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2618 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2620 ModestMsgEditWindowPrivate *priv;
2622 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2623 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2625 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2627 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2632 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2634 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2636 priv->can_undo = can_undo;
2640 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2642 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2644 priv->can_redo = can_redo;
2648 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2650 ModestMsgEditWindowPrivate *priv;
2651 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2652 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2654 return priv->can_undo;
2658 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2660 ModestMsgEditWindowPrivate *priv;
2661 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2662 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2664 return priv->can_redo;
2669 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2672 GtkTextIter match_start, match_end;
2674 if (image_id == NULL)
2677 gtk_text_buffer_get_start_iter (buffer, &iter);
2679 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2680 GSList *tags = gtk_text_iter_get_tags (&match_start);
2682 for (node = tags; node != NULL; node = g_slist_next (node)) {
2683 GtkTextTag *tag = (GtkTextTag *) node->data;
2684 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2685 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2686 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2688 offset = gtk_text_iter_get_offset (&match_start);
2689 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2690 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2694 gtk_text_iter_forward_char (&iter);
2699 message_is_empty (ModestMsgEditWindow *window)
2701 ModestMsgEditWindowPrivate *priv = NULL;
2703 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2704 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2706 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2707 * so we can ignore markup.
2709 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2712 count = gtk_text_buffer_get_char_count (buf);
2718 msg_body_focus (GtkWidget *focus,
2719 GdkEventFocus *event,
2723 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2728 recpt_field_changed (GtkTextBuffer *buffer,
2729 ModestMsgEditWindow *editor)
2731 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2735 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2737 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2741 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2743 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2744 GtkTextBuffer *buffer;
2746 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2747 gtk_text_buffer_set_modified (buffer, FALSE);
2748 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2749 gtk_text_buffer_set_modified (buffer, FALSE);
2750 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2751 gtk_text_buffer_set_modified (buffer, FALSE);
2752 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2756 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2758 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2759 GtkTextBuffer *buffer;
2761 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2762 if (gtk_text_buffer_get_modified (buffer))
2764 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2765 if (gtk_text_buffer_get_modified (buffer))
2767 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2768 if (gtk_text_buffer_get_modified (buffer))
2770 if (gtk_text_buffer_get_modified (priv->text_buffer))
2780 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2782 ModestMsgEditWindowPrivate *priv = NULL;
2784 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2785 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2787 /* check if there's no recipient added */
2788 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2789 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2790 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2791 /* no recipient contents, then select contacts */
2792 modest_msg_edit_window_open_addressbook (window, NULL);
2796 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2797 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2800 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2801 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2804 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2805 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2809 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2810 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2811 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2818 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2819 ModestMsgEditWindow *window)
2821 modest_msg_edit_window_offer_attach_file (window);
2825 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2827 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2829 return priv->clipboard_text;
2833 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2835 ModestMsgEditWindow *window)
2837 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2838 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2840 if (!GTK_WIDGET_VISIBLE (window))
2843 text = gtk_clipboard_wait_for_text (selection_clipboard);
2845 if (priv->clipboard_text != NULL) {
2846 g_free (priv->clipboard_text);
2848 priv->clipboard_text = text;
2850 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2853 subject_field_move_cursor (GtkEntry *entry,
2854 GtkMovementStep step,
2859 if (!GTK_WIDGET_VISIBLE (window))
2862 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2866 update_window_title (ModestMsgEditWindow *window)
2868 ModestMsgEditWindowPrivate *priv = NULL;
2869 const gchar *subject;
2871 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2872 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2873 if (subject == NULL || subject[0] == '\0')
2874 subject = _("mail_va_new_email");
2876 gtk_window_set_title (GTK_WINDOW (window), subject);
2881 subject_field_changed (GtkEditable *editable,
2882 ModestMsgEditWindow *window)
2884 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2885 update_window_title (window);
2886 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2887 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2891 subject_field_insert_text (GtkEditable *editable,
2893 gint new_text_length,
2895 ModestMsgEditWindow *window)
2897 GString *result = g_string_new ("");
2899 gint result_len = 0;
2900 const gchar *entry_text = NULL;
2903 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2904 old_length = g_utf8_strlen (entry_text, -1);
2906 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2907 gunichar c = g_utf8_get_char_validated (current, 8);
2908 /* Invalid unichar, stop */
2914 result = g_string_append_unichar (result, c);
2918 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2919 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2922 /* Prevent endless recursion */
2923 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2924 g_signal_emit_by_name (editable, "insert-text",
2925 (gpointer) result->str, (gpointer) result->len,
2926 (gpointer) position, (gpointer) window);
2927 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2931 if (result_len + old_length > 1000) {
2932 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2933 dgettext("hildon-common-strings",
2934 "ckdg_ib_maximum_characters_reached"));
2937 g_string_free (result, TRUE);
2941 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2944 ModestMsgEditWindowPrivate *priv = NULL;
2946 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2947 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2949 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2952 gtk_widget_show_all (priv->find_toolbar);
2953 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2955 gtk_widget_hide_all (priv->find_toolbar);
2956 gtk_widget_grab_focus (priv->msg_body);
2962 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2964 GtkTextIter *match_start,
2965 GtkTextIter *match_end)
2967 GtkTextIter end_iter;
2968 gchar *str_casefold;
2971 gchar *range_casefold;
2974 gboolean result = FALSE;
2981 gtk_text_iter_forward_to_end (&end_iter);
2983 str_casefold = g_utf8_casefold (str, -1);
2984 str_chars_n = strlen (str);
2986 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2987 range_casefold = g_utf8_casefold (range_text, -1);
2988 range_chars_n = strlen (range_casefold);
2990 if (range_chars_n < str_chars_n) {
2991 g_free (str_casefold);
2992 g_free (range_text);
2993 g_free (range_casefold);
2997 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2998 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2999 if (!g_utf8_collate (range_subtext, str_casefold)) {
3000 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3002 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3003 match_start, match_end, NULL);
3004 g_free (found_text);
3006 g_free (range_subtext);
3010 g_free (str_casefold);
3011 g_free (range_text);
3012 g_free (range_casefold);
3019 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3020 ModestMsgEditWindow *window)
3022 gchar *current_search = NULL;
3023 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3025 GtkTextIter selection_start, selection_end;
3026 GtkTextIter match_start, match_end;
3027 gboolean continue_search = FALSE;
3029 if (message_is_empty (window)) {
3030 g_free (priv->last_search);
3031 priv->last_search = NULL;
3032 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3036 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3037 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3038 g_free (current_search);
3039 g_free (priv->last_search);
3040 priv->last_search = NULL;
3041 /* Information banner about empty search */
3042 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3046 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3047 continue_search = TRUE;
3049 g_free (priv->last_search);
3050 priv->last_search = g_strdup (current_search);
3053 if (continue_search) {
3054 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3055 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3056 &match_start, &match_end);
3058 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3060 GtkTextIter buffer_start;
3061 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3062 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3063 &match_start, &match_end);
3065 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3068 /* Mark as selected the string found in search */
3070 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3071 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3073 g_free (priv->last_search);
3074 priv->last_search = NULL;
3076 g_free (current_search);
3080 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3081 ModestMsgEditWindow *window)
3083 GtkToggleAction *toggle;
3084 ModestWindowPrivate *parent_priv;
3085 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3087 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3088 gtk_toggle_action_set_active (toggle, FALSE);
3092 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3094 ModestMsgEditWindowPrivate *priv;
3096 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3101 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3104 ModestMsgEditWindowPrivate *priv;
3106 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3112 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3115 ModestMsgEditWindowPrivate *priv;
3116 TnyHeader *header = NULL;
3118 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3119 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3121 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3122 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3124 if (priv->draft_msg != NULL) {
3125 g_object_unref (priv->draft_msg);
3128 if (draft != NULL) {
3129 g_object_ref (draft);
3130 header = tny_msg_get_header (draft);
3131 if (priv->msg_uid) {
3132 g_free (priv->msg_uid);
3133 priv->msg_uid = NULL;
3135 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3136 if (GTK_WIDGET_REALIZED (window))
3137 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3140 priv->draft_msg = draft;
3144 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3145 GtkTextIter *start, GtkTextIter *end,
3148 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3149 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3152 if (tag == NULL+13) return;
3153 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3154 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3155 replace_with_images (window, priv->images);
3160 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3163 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3165 g_return_if_fail (TNY_IS_MIME_PART (part));
3166 priv->attachments = g_list_prepend (priv->attachments, part);
3167 g_object_ref (part);
3168 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3169 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3170 gtk_widget_show_all (priv->attachments_caption);
3171 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3175 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3177 ModestMsgEditWindowPrivate *priv;
3179 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3180 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3182 return priv->msg_uid;
3186 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3187 ModestMsgEditWindowWidgetType widget_type)
3189 ModestMsgEditWindowPrivate *priv;
3191 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3192 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3194 switch (widget_type) {
3195 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3196 return priv->msg_body;
3198 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3199 return priv->to_field;
3201 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3202 return priv->cc_field;
3204 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3205 return priv->bcc_field;
3207 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3208 return priv->subject_field;
3210 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3211 return priv->attachments_view;
3219 remove_tags (WPTextBuffer *buffer)
3221 GtkTextIter start, end;
3223 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3224 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3226 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3230 on_account_removed (TnyAccountStore *account_store,
3231 TnyAccount *account,
3234 /* Do nothing if it's a store account, because we use the
3235 transport to send the messages */
3236 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3237 const gchar *parent_acc = NULL;
3238 const gchar *our_acc = NULL;
3240 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3241 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3242 /* Close this window if I'm showing a message of the removed account */
3243 if (strcmp (parent_acc, our_acc) == 0)
3244 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3249 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3251 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3253 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3259 set_zoom_do_nothing (ModestWindow *window,
3265 get_zoom_do_nothing (ModestWindow *window)