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-maemo-utils.h"
81 #define DEFAULT_FONT_SIZE 3
82 #define DEFAULT_FONT 2
83 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
84 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
85 #define DEFAULT_MAIN_VBOX_SPACING 6
86 #define SUBJECT_MAX_LENGTH 1000
87 #define IMAGE_MAX_WIDTH 560
88 #define DEFAULT_FONT_SCALE 1.5
90 static gboolean is_wp_text_buffer_started = FALSE;
92 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
93 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
94 static void modest_msg_edit_window_finalize (GObject *obj);
96 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
97 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
98 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
100 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
101 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
102 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
103 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
104 GtkTextIter *start, GtkTextIter *end,
106 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
107 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
108 static void subject_field_insert_text (GtkEditable *editable,
110 gint new_text_length,
112 ModestMsgEditWindow *window);
113 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
115 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
117 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
119 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
120 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
121 GdkEventWindowState *event,
123 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
124 ModestRecptEditor *editor);
125 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
126 ModestMsgEditWindow *window);
128 /* ModestWindow methods implementation */
129 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
130 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
131 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
132 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
133 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
134 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
135 gboolean show_toolbar);
136 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
138 ModestMsgEditWindow *window);
139 static void subject_field_move_cursor (GtkEntry *entry,
140 GtkMovementStep step,
144 static void update_window_title (ModestMsgEditWindow *window);
147 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
148 ModestMsgEditWindow *window);
149 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
150 ModestMsgEditWindow *window);
151 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
153 GtkTextIter *match_start,
154 GtkTextIter *match_end);
156 static void remove_tags (WPTextBuffer *buffer);
158 static void on_account_removed (TnyAccountStore *account_store,
162 static void init_window (ModestMsgEditWindow *obj);
164 static void DEBUG_BUFFER (WPTextBuffer *buffer)
169 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
170 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
171 while (!gtk_text_iter_is_end (&iter)) {
172 GString *output = g_string_new ("");
173 GSList *toggled_tags;
176 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
177 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
178 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
179 GtkTextTag *tag = (GtkTextTag *) node->data;
181 g_object_get (G_OBJECT (tag), "name", &name, NULL);
182 output = g_string_append (output, name);
183 g_string_append (output, " ");
185 output = g_string_append (output, "] OPENED [ ");
186 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
187 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
188 GtkTextTag *tag = (GtkTextTag *) node->data;
190 g_object_get (G_OBJECT (tag), "name", &name, NULL);
191 output = g_string_append (output, name);
192 g_string_append (output, " ");
194 output = g_string_append (output, "]\n");
195 g_message ("%s", output->str);
196 g_string_free (output, TRUE);
197 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
199 g_message ("END BUFFER");
204 /* static gboolean */
205 /* on_key_pressed (GtkWidget *self, */
206 /* GdkEventKey *event, */
207 /* gpointer user_data); */
209 /* list my signals */
216 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
217 struct _ModestMsgEditWindowPrivate {
219 GtkWidget *header_box;
221 ModestPairList *from_field_protos;
222 GtkWidget *from_field;
226 GtkWidget *bcc_field;
227 GtkWidget *subject_field;
228 GtkWidget *attachments_view;
229 GtkWidget *priority_icon;
230 GtkWidget *add_attachment_button;
232 GtkWidget *cc_caption;
233 GtkWidget *bcc_caption;
234 gboolean update_caption_visibility;
235 GtkWidget *attachments_caption;
237 GtkTextBuffer *text_buffer;
239 GtkWidget *font_size_toolitem;
240 GtkWidget *font_face_toolitem;
241 GtkWidget *font_color_button;
242 GSList *font_items_group;
243 GtkWidget *font_tool_button_label;
244 GSList *size_items_group;
245 GtkWidget *size_tool_button_label;
247 GtkWidget *find_toolbar;
251 GtkWidget *scroll_area;
252 gint last_vadj_upper;
258 TnyHeaderFlags priority_flags;
262 gboolean can_undo, can_redo;
263 gulong clipboard_change_handler_id;
264 gulong default_clipboard_change_handler_id;
265 gulong account_removed_handler_id;
266 gchar *clipboard_text;
275 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
276 MODEST_TYPE_MSG_EDIT_WINDOW, \
277 ModestMsgEditWindowPrivate))
279 static GtkWindowClass *parent_class = NULL;
281 /* uncomment the following if you have defined any signals */
282 /* static guint signals[LAST_SIGNAL] = {0}; */
285 modest_msg_edit_window_get_type (void)
287 static GType my_type = 0;
289 static const GTypeInfo my_info = {
290 sizeof(ModestMsgEditWindowClass),
291 NULL, /* base init */
292 NULL, /* base finalize */
293 (GClassInitFunc) modest_msg_edit_window_class_init,
294 NULL, /* class finalize */
295 NULL, /* class data */
296 sizeof(ModestMsgEditWindow),
298 (GInstanceInitFunc) modest_msg_edit_window_init,
301 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
302 "ModestMsgEditWindow",
310 save_state (ModestWindow *self)
312 modest_widget_memory_save (modest_runtime_get_conf(),
313 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
318 restore_settings (ModestMsgEditWindow *self)
320 ModestConf *conf = NULL;
322 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
324 conf = modest_runtime_get_conf ();
325 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
326 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
327 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
328 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
329 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
330 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
331 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
332 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
334 /* set initial state of cc and bcc */
335 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
336 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
337 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
338 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
339 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
340 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
342 /* Dim at start clipboard actions */
343 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
344 gtk_action_set_sensitive (action, FALSE);
345 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
346 gtk_action_set_sensitive (action, FALSE);
347 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
348 gtk_action_set_sensitive (action, FALSE);
350 modest_widget_memory_restore (conf,
351 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
356 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
358 GObjectClass *gobject_class;
359 ModestWindowClass *modest_window_class;
360 gobject_class = (GObjectClass*) klass;
361 modest_window_class = (ModestWindowClass*) klass;
363 parent_class = g_type_class_peek_parent (klass);
364 gobject_class->finalize = modest_msg_edit_window_finalize;
366 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
367 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
368 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
369 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
370 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
371 modest_window_class->save_state_func = save_state;
372 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
374 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
378 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
380 ModestMsgEditWindowPrivate *priv;
381 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
383 priv->msg_body = NULL;
384 priv->from_field = NULL;
385 priv->to_field = NULL;
386 priv->cc_field = NULL;
387 priv->bcc_field = NULL;
388 priv->subject_field = NULL;
389 priv->attachments = NULL;
392 priv->zoom_level = 1.0;
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_zoom_action_entries,
616 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
618 G_CALLBACK (modest_ui_actions_on_change_zoom),
620 gtk_action_group_add_radio_actions (action_group,
621 modest_msg_edit_priority_action_entries,
622 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
624 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
626 gtk_action_group_add_radio_actions (action_group,
627 modest_msg_edit_file_format_action_entries,
628 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
629 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
630 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
632 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
633 g_object_unref (action_group);
635 /* Load the UI definition */
636 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
639 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
640 g_clear_error (&error);
643 /* Add accelerators */
644 gtk_window_add_accel_group (GTK_WINDOW (obj),
645 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
647 parent_priv->menubar = NULL;
649 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
651 /* Note: This ModestPairList* must exist for as long as the combo
652 * that uses it, because the ModestComboBox uses the ID opaquely,
653 * so it can't know how to manage its memory. */
654 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
656 priv->to_field = modest_recpt_editor_new ();
657 priv->cc_field = modest_recpt_editor_new ();
658 priv->bcc_field = modest_recpt_editor_new ();
659 subject_box = gtk_hbox_new (FALSE, 0);
660 priv->priority_icon = gtk_image_new ();
661 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
662 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
663 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
664 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
665 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
666 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
667 priv->add_attachment_button = gtk_button_new ();
668 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
669 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
670 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
671 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
672 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
673 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
674 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
675 priv->attachments_view = modest_attachments_view_new (NULL);
677 priv->header_box = gtk_vbox_new (FALSE, 0);
679 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
680 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
681 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
682 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
683 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
684 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
685 g_object_unref (size_group);
687 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
688 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
689 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
690 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
691 gtk_size_group_add_widget (size_group, priv->subject_field);
692 gtk_size_group_add_widget (size_group, priv->attachments_view);
693 g_object_unref (size_group);
695 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
696 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
697 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
698 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
699 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
700 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
701 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
704 priv->msg_body = wp_text_view_new ();
705 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
706 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
707 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
708 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
709 #if (GTK_MINOR_VERSION >= 10)
710 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
711 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
713 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
714 deserialize_type, TRUE);
716 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
718 priv->find_toolbar = hildon_find_toolbar_new (NULL);
719 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
721 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
723 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
724 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
725 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
726 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
728 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
730 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
731 frame = gtk_frame_new (NULL);
732 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
734 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
735 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
736 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
738 G_CALLBACK (vadj_changed),
740 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
742 window_box = gtk_vbox_new (FALSE, 0);
743 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
744 gtk_container_add (GTK_CONTAINER(obj), window_box);
745 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
746 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
748 /* Set window icon */
749 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
751 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
752 g_object_unref (window_icon);
758 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
760 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
762 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
763 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
764 priv->clipboard_change_handler_id))
765 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
766 priv->clipboard_change_handler_id);
767 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
768 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
769 priv->default_clipboard_change_handler_id))
770 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
771 priv->default_clipboard_change_handler_id);
773 if (priv->account_removed_handler_id &&
774 g_signal_handler_is_connected (modest_runtime_get_account_store (),
775 priv->account_removed_handler_id))
776 g_signal_handler_disconnect(modest_runtime_get_account_store (),
777 priv->account_removed_handler_id);
781 modest_msg_edit_window_finalize (GObject *obj)
783 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
785 /* Sanity check: shouldn't be needed, the window mgr should
786 call this function before */
787 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
789 if (priv->clipboard_text != NULL) {
790 g_free (priv->clipboard_text);
791 priv->clipboard_text = NULL;
794 if (priv->draft_msg != NULL) {
795 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
796 if (TNY_IS_HEADER (header)) {
797 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
798 modest_window_mgr_unregister_header (mgr, header);
800 g_object_unref (priv->draft_msg);
801 priv->draft_msg = NULL;
803 if (priv->outbox_msg != NULL) {
804 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
805 if (TNY_IS_HEADER (header)) {
806 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
807 modest_window_mgr_unregister_header (mgr, header);
809 g_object_unref (priv->outbox_msg);
810 priv->outbox_msg = NULL;
812 g_free (priv->msg_uid);
813 g_free (priv->last_search);
814 g_slist_free (priv->font_items_group);
815 g_slist_free (priv->size_items_group);
816 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
817 g_list_free (priv->attachments);
818 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
819 g_list_free (priv->images);
821 /* This had to stay alive for as long as the combobox that used it: */
822 modest_pair_list_free (priv->from_field_protos);
824 G_OBJECT_CLASS(parent_class)->finalize (obj);
828 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
830 GdkPixbufLoader *loader;
833 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
838 tny_stream_reset (TNY_STREAM (stream));
839 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
840 unsigned char read_buffer[128];
842 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
843 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
847 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
848 g_object_ref (pixbuf);
849 gdk_pixbuf_loader_close (loader, NULL);
850 g_object_unref (loader);
852 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
853 GdkPixbuf *new_pixbuf;
855 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
856 gdk_pixbuf_get_width (pixbuf);
857 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
858 g_object_unref (pixbuf);
866 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
868 ModestMsgEditWindowPrivate *priv;
871 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
873 for (node = attachments; node != NULL; node = g_list_next (node)) {
874 TnyMimePart *part = (TnyMimePart *) node->data;
875 const gchar *cid = tny_mime_part_get_content_id (part);
876 const gchar *mime_type = tny_mime_part_get_content_type (part);
877 if ((cid != NULL)&&(mime_type != NULL)) {
878 TnyStream *stream = tny_mime_part_get_stream (part);
879 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
880 g_object_unref (stream);
882 if (pixbuf != NULL) {
883 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
884 g_object_unref (pixbuf);
891 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
893 TnyMimePart *parent = NULL;
894 const gchar *content_type = NULL;
895 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
897 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
899 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
900 parent = g_object_ref (msg);
901 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
902 TnyList *parts = TNY_LIST (tny_simple_list_new ());
905 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
906 iter = tny_list_create_iterator (parts);
907 while (!tny_iterator_is_done (iter)) {
909 part = TNY_MIME_PART (tny_iterator_get_current (iter));
910 content_type = tny_mime_part_get_content_type (part);
911 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
915 g_object_unref (part);
917 tny_iterator_next (iter);
919 g_object_unref (iter);
920 g_object_unref (parts);
923 if (parent != NULL) {
924 TnyList *parts = TNY_LIST (tny_simple_list_new ());
927 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
928 iter = tny_list_create_iterator (parts);
929 while (!tny_iterator_is_done (iter)) {
931 part = TNY_MIME_PART (tny_iterator_get_current (iter));
932 content_type = tny_mime_part_get_content_type (part);
933 if (content_type && g_str_has_prefix (content_type, "image/")) {
934 priv->images = g_list_prepend (priv->images, part);
936 g_object_unref (part);
938 tny_iterator_next (iter);
940 g_object_unref (iter);
941 g_object_unref (parts);
942 g_object_unref (parent);
947 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
950 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
952 for (node = attachments; node != NULL; node = g_list_next (node)) {
953 TnyMimePart *part = (TnyMimePart *) node->data;
954 const gchar *cid = tny_mime_part_get_content_id (part);
956 char *invalid = NULL;
957 gint int_cid = strtol (cid, &invalid, 10);
958 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
959 priv->last_cid = int_cid;
967 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
970 const gchar *to, *cc, *bcc, *subject;
972 ModestMsgEditWindowPrivate *priv;
974 TnyHeaderFlags priority_flags;
975 TnyFolder *msg_folder;
976 gboolean is_html = FALSE;
978 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
979 g_return_if_fail (TNY_IS_MSG (msg));
981 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
983 header = tny_msg_get_header (msg);
984 to = tny_header_get_to (header);
985 cc = tny_header_get_cc (header);
986 bcc = tny_header_get_bcc (header);
987 subject = tny_header_get_subject (header);
988 priority_flags = tny_header_get_priority (header);
991 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
993 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
994 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
995 gtk_widget_show (priv->cc_caption);
996 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
997 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
998 gtk_widget_hide (priv->cc_caption);
1001 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1002 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1003 gtk_widget_show (priv->bcc_caption);
1004 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1005 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1006 gtk_widget_hide (priv->bcc_caption);
1009 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1010 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1013 update_window_title (self);
1015 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1016 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1018 if ((body == NULL)||(body[0] == '\0')) {
1020 body = modest_text_utils_convert_to_html ("");
1023 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1024 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1027 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1030 /* Add attachments to the view */
1031 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1032 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1033 if (priv->attachments == NULL) {
1034 gtk_widget_hide (priv->attachments_caption);
1036 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1037 gtk_widget_show_all (priv->attachments_caption);
1039 get_related_images (self, msg);
1040 update_last_cid (self, priv->attachments);
1041 update_last_cid (self, priv->images);
1042 replace_with_images (self, priv->images);
1044 if (preserve_is_rich && !is_html) {
1045 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1046 /* Get the default format required from configuration */
1047 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1048 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1051 /* Set the default focus depending on having already a To: field or not */
1052 if ((!to)||(*to == '\0')) {
1053 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1055 gtk_widget_grab_focus (priv->msg_body);
1058 /* TODO: lower priority, select in the From: combo to the
1059 value that comes from msg <- not sure, should it be
1062 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1064 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1065 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1067 modest_msg_edit_window_reset_modified (self);
1069 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1070 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1071 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1073 if (priv->msg_uid) {
1074 g_free (priv->msg_uid);
1075 priv->msg_uid = NULL;
1078 /* we should set a reference to the incoming message if it is a draft */
1079 msg_folder = tny_msg_get_folder (msg);
1081 if (modest_tny_folder_is_local_folder (msg_folder)) {
1082 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1083 if (type == TNY_FOLDER_TYPE_INVALID)
1084 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1086 if (type == TNY_FOLDER_TYPE_DRAFTS)
1087 priv->draft_msg = g_object_ref(msg);
1088 if (type == TNY_FOLDER_TYPE_OUTBOX)
1089 priv->outbox_msg = g_object_ref(msg);
1090 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1092 g_object_unref (msg_folder);
1097 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1100 GList *item_children, *node;
1101 GtkWidget *bin_child;
1103 bin_child = gtk_bin_get_child (GTK_BIN(item));
1105 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1107 for (node = item_children; node != NULL; node = g_list_next (node)) {
1108 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1109 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1112 g_list_free (item_children);
1116 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1119 GList *item_children, *node;
1121 box = gtk_bin_get_child (GTK_BIN (item));
1122 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1123 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1125 for (node = item_children; node != NULL; node = g_list_next (node)) {
1126 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1127 if (GTK_IS_TOGGLE_BUTTON (node->data))
1128 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1129 else if (GTK_IS_BUTTON (node->data))
1130 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1132 g_list_free (item_children);
1137 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1139 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1140 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1141 GtkWidget *placeholder;
1142 GtkWidget *tool_item;
1147 GtkWidget *sizes_menu;
1148 GtkWidget *fonts_menu;
1149 GSList *radio_group = NULL;
1150 GSList *node = NULL;
1154 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1155 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1157 /* Font color placeholder */
1158 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1159 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1162 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1163 priv->font_color_button = hildon_color_button_new ();
1164 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1165 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1166 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1167 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1168 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1169 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1170 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1172 G_CALLBACK (modest_msg_edit_window_color_button_change),
1175 /* Font size and face placeholder */
1176 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1177 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1179 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1180 priv->size_tool_button_label = gtk_label_new (NULL);
1181 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1182 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1183 size_text,"</span>", NULL);
1184 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1186 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1187 sizes_menu = gtk_menu_new ();
1188 priv->size_items_group = NULL;
1190 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1191 GtkWidget *size_menu_item;
1193 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1194 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1195 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1196 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1197 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1198 gtk_widget_show (size_menu_item);
1200 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1204 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1205 GtkWidget *item = (GtkWidget *) node->data;
1206 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1210 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1211 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1212 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1213 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1214 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1215 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1216 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1217 priv->font_size_toolitem = tool_item;
1220 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1221 priv->font_tool_button_label = gtk_label_new (NULL);
1222 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1223 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1225 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1226 fonts_menu = gtk_menu_new ();
1227 priv->font_items_group = NULL;
1229 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1230 GtkWidget *font_menu_item;
1231 GtkWidget *child_label;
1233 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1234 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1235 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1236 wp_get_font_name (font_index), "</span>", NULL);
1237 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1240 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1241 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1242 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1243 gtk_widget_show (font_menu_item);
1245 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1248 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1249 GtkWidget *item = (GtkWidget *) node->data;
1250 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1253 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1254 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1255 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1256 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1257 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1258 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1259 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1260 priv->font_face_toolitem = tool_item;
1262 /* Set expand and homogeneous for remaining items */
1263 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1264 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1265 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1266 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1267 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1268 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1269 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1270 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1271 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1273 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1274 will not show the tool items added to the placeholders) */
1275 gtk_widget_show_all (parent_priv->toolbar);
1277 /* Set the no show all *after* showing all items. We do not
1278 want the toolbar to be shown with a show all because it
1279 could go agains the gconf setting regarding showing or not
1280 the toolbar of the editor window */
1281 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1287 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1290 ModestWindowPrivate *parent_priv;
1291 ModestMsgEditWindowPrivate *priv;
1292 ModestPair *account_pair = NULL;
1293 ModestDimmingRulesGroup *menu_rules_group = NULL;
1294 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1295 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1296 ModestWindowMgr *mgr = NULL;
1298 g_return_val_if_fail (msg, NULL);
1299 g_return_val_if_fail (account_name, NULL);
1301 mgr = modest_runtime_get_window_mgr ();
1303 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1305 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1306 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1308 /* Menubar. Update the state of some toggles */
1309 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1310 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1311 priv->from_field_protos = get_transports ();
1312 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1313 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1314 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1317 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1319 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1321 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1323 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1324 if (account_pair != NULL)
1325 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1327 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1328 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1329 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1330 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1331 /* Add common dimming rules */
1332 modest_dimming_rules_group_add_rules (menu_rules_group,
1333 modest_msg_edit_window_menu_dimming_entries,
1334 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1335 MODEST_WINDOW (obj));
1336 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1337 modest_msg_edit_window_toolbar_dimming_entries,
1338 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1339 MODEST_WINDOW (obj));
1340 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1341 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1342 MODEST_WINDOW (obj));
1343 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1344 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1345 MODEST_WINDOW (obj));
1346 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1347 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1348 MODEST_WINDOW (obj));
1349 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1350 modest_msg_edit_window_clipboard_dimming_entries,
1351 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1352 MODEST_WINDOW (obj));
1353 /* Insert dimming rules group for this window */
1354 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1355 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1356 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1357 /* Checks the dimming rules */
1358 g_object_unref (menu_rules_group);
1359 g_object_unref (toolbar_rules_group);
1360 g_object_unref (clipboard_rules_group);
1362 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1364 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1366 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1367 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1368 priv->update_caption_visibility = TRUE;
1370 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1372 /* Track account-removed signal, this window should be closed
1373 in the case we're creating a mail associated to the account
1375 priv->account_removed_handler_id =
1376 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1378 G_CALLBACK(on_account_removed),
1381 return (ModestWindow*) obj;
1385 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1387 GString **string_buffer = (GString **) user_data;
1389 *string_buffer = g_string_append (*string_buffer, buffer);
1395 * @result: A new string which should be freed with g_free().
1398 get_formatted_data (ModestMsgEditWindow *edit_window)
1400 ModestMsgEditWindowPrivate *priv;
1401 GString *string_buffer = g_string_new ("");
1403 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1405 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1407 return g_string_free (string_buffer, FALSE);
1412 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1415 const gchar *account_name;
1416 ModestMsgEditWindowPrivate *priv;
1418 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1420 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1422 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1423 g_return_val_if_fail (account_name, NULL);
1426 /* don't free these (except from) */
1427 data = g_slice_new0 (MsgData);
1428 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1430 data->account_name = g_strdup (account_name);
1431 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1432 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1433 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1434 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1435 if (priv->draft_msg) {
1436 data->draft_msg = g_object_ref (priv->draft_msg);
1437 } else if (priv->outbox_msg) {
1438 data->draft_msg = g_object_ref (priv->outbox_msg);
1440 data->draft_msg = NULL;
1443 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1445 gtk_text_buffer_get_bounds (buf, &b, &e);
1446 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1448 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1449 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1451 data->html_body = NULL;
1453 /* deep-copy the data */
1454 GList *cursor = priv->attachments;
1455 data->attachments = NULL;
1457 if (!(TNY_IS_MIME_PART(cursor->data))) {
1458 g_warning ("strange data in attachment list");
1459 cursor = g_list_next (cursor);
1462 data->attachments = g_list_append (data->attachments,
1463 g_object_ref (cursor->data));
1464 cursor = g_list_next (cursor);
1467 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1468 cursor = priv->images;
1469 data->images = NULL;
1472 if (!(TNY_IS_MIME_PART(cursor->data))) {
1473 g_warning ("strange data in attachment list");
1474 cursor = g_list_next (cursor);
1477 cid = tny_mime_part_get_content_id (cursor->data);
1479 gchar *image_tag_id;
1480 GtkTextTag *image_tag;
1482 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1483 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1484 g_free (image_tag_id);
1486 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1488 ((gtk_text_iter_has_tag (&iter, image_tag))||
1489 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1490 data->images = g_list_append (data->images,
1491 g_object_ref (cursor->data));
1493 cursor = g_list_next (cursor);
1496 data->priority_flags = priv->priority_flags;
1503 unref_gobject (GObject *obj, gpointer data)
1505 if (!G_IS_OBJECT(obj))
1507 g_object_unref (obj);
1511 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1514 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1522 g_free (data->from);
1523 g_free (data->subject);
1524 g_free (data->plain_body);
1525 g_free (data->html_body);
1526 g_free (data->account_name);
1528 if (data->draft_msg != NULL) {
1529 g_object_unref (data->draft_msg);
1530 data->draft_msg = NULL;
1533 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1534 g_list_free (data->attachments);
1535 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1536 g_list_free (data->images);
1538 g_slice_free (MsgData, data);
1542 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1545 ModestMsgEditWindowPrivate *priv = NULL;
1546 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1548 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1550 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1552 return MODEST_MSG_EDIT_FORMAT_HTML;
1554 return MODEST_MSG_EDIT_FORMAT_TEXT;
1558 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1559 ModestMsgEditFormat format)
1561 ModestMsgEditWindowPrivate *priv;
1563 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1564 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1567 case MODEST_MSG_EDIT_FORMAT_HTML:
1568 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1570 case MODEST_MSG_EDIT_FORMAT_TEXT:
1571 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1574 g_return_if_reached ();
1578 ModestMsgEditFormatState *
1579 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1581 ModestMsgEditFormatState *format_state = NULL;
1582 ModestMsgEditWindowPrivate *priv;
1583 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1585 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1586 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1588 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1590 format_state = g_new0 (ModestMsgEditFormatState, 1);
1591 format_state->bold = buffer_format->bold&0x1;
1592 format_state->italics = buffer_format->italic&0x1;
1593 format_state->bullet = buffer_format->bullet&0x1;
1594 format_state->color = buffer_format->color;
1595 format_state->font_size = buffer_format->font_size;
1596 format_state->font_family = wp_get_font_name (buffer_format->font);
1597 format_state->justification = buffer_format->justification;
1598 g_free (buffer_format);
1600 return format_state;
1605 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1606 const ModestMsgEditFormatState *format_state)
1608 ModestMsgEditWindowPrivate *priv;
1609 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1610 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1611 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1612 g_return_if_fail (format_state != NULL);
1614 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1615 gtk_widget_grab_focus (priv->msg_body);
1616 buffer_format->bold = (format_state->bold != FALSE);
1617 buffer_format->italic = (format_state->italics != FALSE);
1618 buffer_format->color = format_state->color;
1619 buffer_format->font_size = format_state->font_size;
1620 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1621 buffer_format->justification = format_state->justification;
1622 buffer_format->bullet = format_state->bullet;
1624 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1626 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1627 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1628 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1629 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1630 buffer_format->cs.font = (buffer_format->font != current_format->font);
1631 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1632 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1634 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1635 if (buffer_format->cs.bold) {
1636 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1638 if (buffer_format->cs.italic) {
1639 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1641 if (buffer_format->cs.color) {
1642 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1644 if (buffer_format->cs.font_size) {
1645 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1647 if (buffer_format->cs.justification) {
1648 switch (buffer_format->justification) {
1649 case GTK_JUSTIFY_LEFT:
1650 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1652 case GTK_JUSTIFY_CENTER:
1653 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1655 case GTK_JUSTIFY_RIGHT:
1656 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1663 if (buffer_format->cs.font) {
1664 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1666 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1667 if (buffer_format->cs.bullet) {
1668 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1670 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1672 g_free (current_format);
1677 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1679 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1681 ModestWindowPrivate *parent_priv;
1682 ModestMsgEditWindowPrivate *priv;
1683 GtkWidget *new_size_menuitem;
1684 GtkWidget *new_font_menuitem;
1686 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1687 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1689 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1690 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1691 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1692 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1694 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1695 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1696 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1699 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1701 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1702 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1704 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1705 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1707 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1708 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1710 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1711 G_CALLBACK (modest_msg_edit_window_color_button_change),
1713 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1714 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1715 G_CALLBACK (modest_msg_edit_window_color_button_change),
1718 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1719 buffer_format->font_size))->data);
1720 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1724 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1725 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1726 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1728 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1729 G_CALLBACK (modest_msg_edit_window_size_change),
1731 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1732 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1733 G_CALLBACK (modest_msg_edit_window_size_change),
1737 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1738 buffer_format->font))->data);
1739 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1743 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1744 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1745 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1747 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1748 G_CALLBACK (modest_msg_edit_window_font_change),
1750 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1751 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1752 G_CALLBACK (modest_msg_edit_window_font_change),
1756 g_free (buffer_format);
1760 #ifdef MODEST_HILDON_VERSION_0
1762 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1765 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1766 ModestMsgEditWindowPrivate *priv;
1767 GtkWidget *dialog = NULL;
1769 GdkColor *new_color = NULL;
1771 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1772 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1774 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1775 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1776 g_free (buffer_format);
1778 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1779 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1780 if (new_color != NULL) {
1781 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1782 (gpointer) new_color);
1785 gtk_widget_destroy (dialog);
1790 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1793 ModestMsgEditWindowPrivate *priv;
1794 GtkWidget *dialog = NULL;
1796 GdkColor *old_color = NULL;
1797 const GdkColor *new_color = NULL;
1799 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1800 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1802 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1803 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1805 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1806 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1807 if (new_color != NULL)
1808 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1810 gtk_widget_destroy (dialog);
1816 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1819 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1820 ModestMsgEditWindowPrivate *priv;
1821 GtkWidget *dialog = NULL;
1823 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1824 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1826 dialog = hildon_color_chooser_new ();
1827 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1828 g_free (buffer_format);
1830 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1832 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1833 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1836 gtk_widget_destroy (dialog);
1841 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1844 ModestMsgEditWindowPrivate *priv;
1845 GtkWidget *dialog = NULL;
1846 GdkColor *old_color = NULL;
1848 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1849 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1851 dialog = hildon_color_chooser_new ();
1852 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1854 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1856 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1857 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1859 gtk_widget_destroy (dialog);
1862 #endif /*!MODEST_HILDON_VERSION_0*/
1866 static TnyStream* create_stream_for_uri (const gchar* uri)
1871 TnyStream *result = NULL;
1873 GnomeVFSHandle *handle = NULL;
1874 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1875 if (test == GNOME_VFS_OK) {
1876 /* Create the tinymail stream: */
1877 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1878 result = TNY_STREAM (tny_vfs_stream_new (handle));
1885 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1888 ModestMsgEditWindowPrivate *priv;
1889 GtkWidget *dialog = NULL;
1891 GSList *uris = NULL;
1892 GSList *uri_node = NULL;
1894 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1896 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1897 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1898 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1900 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1902 response = gtk_dialog_run (GTK_DIALOG (dialog));
1904 case GTK_RESPONSE_OK:
1905 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1910 gtk_widget_destroy (dialog);
1912 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1914 GnomeVFSHandle *handle = NULL;
1915 GnomeVFSResult result;
1916 GtkTextIter position;
1917 GtkTextMark *insert_mark;
1919 uri = (const gchar *) uri_node->data;
1920 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1921 if (result == GNOME_VFS_OK) {
1923 GnomeVFSFileInfo info;
1924 gchar *filename, *basename, *escaped_filename;
1925 TnyMimePart *mime_part;
1927 const gchar *mime_type = NULL;
1928 GnomeVFSURI *vfs_uri;
1930 vfs_uri = gnome_vfs_uri_new (uri);
1932 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1933 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1934 g_free (escaped_filename);
1935 gnome_vfs_uri_unref (vfs_uri);
1937 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1938 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1940 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1942 mime_part = tny_platform_factory_new_mime_part
1943 (modest_runtime_get_platform_factory ());
1945 TnyStream *stream = create_stream_for_uri (uri);
1946 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1948 content_id = g_strdup_printf ("%d", priv->last_cid);
1949 tny_mime_part_set_content_id (mime_part, content_id);
1950 g_free (content_id);
1953 basename = g_path_get_basename (filename);
1954 tny_mime_part_set_filename (mime_part, basename);
1957 pixbuf = pixbuf_from_stream (stream, mime_type);
1959 if (pixbuf != NULL) {
1960 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1961 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1962 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1965 priv->images = g_list_prepend (priv->images, mime_part);
1966 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1976 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1978 GtkWidget *dialog = NULL;
1980 GSList *uris = NULL;
1983 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1984 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1985 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1987 response = gtk_dialog_run (GTK_DIALOG (dialog));
1989 case GTK_RESPONSE_OK:
1990 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1995 gtk_widget_destroy (dialog);
1997 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1998 const gchar *uri = (const gchar *) uri_node->data;
1999 modest_msg_edit_window_attach_file_one (window, uri);
2001 g_slist_foreach (uris, (GFunc) g_free, NULL);
2002 g_slist_free (uris);
2006 modest_msg_edit_window_attach_file_one (
2007 ModestMsgEditWindow *window,
2010 g_return_if_fail (window);
2011 g_return_if_fail (uri);
2013 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2016 GnomeVFSHandle *handle = NULL;
2017 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2018 if (result == GNOME_VFS_OK) {
2019 TnyMimePart *mime_part;
2021 const gchar *mime_type = NULL;
2023 gchar *escaped_filename;
2026 GnomeVFSFileInfo info;
2027 GnomeVFSURI *vfs_uri;
2029 vfs_uri = gnome_vfs_uri_new (uri);
2032 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2033 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2034 g_free (escaped_filename);
2035 gnome_vfs_uri_unref (vfs_uri);
2037 if (gnome_vfs_get_file_info (uri,
2039 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2040 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2042 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2043 mime_part = tny_platform_factory_new_mime_part
2044 (modest_runtime_get_platform_factory ());
2045 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2047 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2049 content_id = g_strdup_printf ("%d", priv->last_cid);
2050 tny_mime_part_set_content_id (mime_part, content_id);
2051 g_free (content_id);
2054 basename = g_path_get_basename (filename);
2055 tny_mime_part_set_filename (mime_part, basename);
2058 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2059 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2061 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2062 gtk_widget_show_all (priv->attachments_caption);
2063 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2069 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2072 ModestMsgEditWindowPrivate *priv;
2073 gboolean clean_list = FALSE;
2075 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2076 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2078 if (att_list == NULL) {
2079 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2083 if (att_list == NULL) {
2084 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2086 GtkWidget *confirmation_dialog = NULL;
2087 gboolean dialog_response;
2089 gchar *message = NULL;
2090 gchar *filename = NULL;
2092 if (att_list->next == NULL) {
2093 if (TNY_IS_MSG (att_list->data)) {
2094 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2096 filename = g_strdup (tny_header_get_subject (header));
2097 g_object_unref (header);
2099 if (filename == NULL) {
2100 filename = g_strdup (_("mail_va_no_subject"));
2103 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2106 filename = g_strdup ("");
2108 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2109 att_list->next == NULL), filename);
2111 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2113 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2114 gtk_widget_destroy (confirmation_dialog);
2115 if (!dialog_response) {
2117 g_list_free (att_list);
2120 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2122 for (node = att_list; node != NULL; node = g_list_next (node)) {
2123 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2124 const gchar *att_id;
2125 priv->attachments = g_list_remove (priv->attachments, mime_part);
2127 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2129 if (priv->attachments == NULL)
2130 gtk_widget_hide (priv->attachments_caption);
2131 att_id = tny_mime_part_get_content_id (mime_part);
2133 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2135 g_object_unref (mime_part);
2136 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2141 g_list_free (att_list);
2145 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2148 ModestMsgEditWindowPrivate *priv;
2149 GdkColor *new_color;
2150 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2152 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2153 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2156 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2158 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2160 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2162 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2167 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2170 ModestMsgEditWindowPrivate *priv;
2171 gint new_size_index;
2172 ModestMsgEditWindow *window;
2175 window = MODEST_MSG_EDIT_WINDOW (userdata);
2176 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2177 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2179 if (gtk_check_menu_item_get_active (menu_item)) {
2181 WPTextBufferFormat format;
2183 memset (&format, 0, sizeof (format));
2184 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2186 label = gtk_bin_get_child (GTK_BIN (menu_item));
2188 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2189 format.cs.font_size = TRUE;
2190 format.cs.text_position = TRUE;
2191 format.cs.font = TRUE;
2192 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2193 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2195 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2196 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2197 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2199 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2200 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2201 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2207 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2210 ModestMsgEditWindowPrivate *priv;
2211 gint new_font_index;
2212 ModestMsgEditWindow *window;
2215 window = MODEST_MSG_EDIT_WINDOW (userdata);
2216 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2217 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2219 if (gtk_check_menu_item_get_active (menu_item)) {
2222 label = gtk_bin_get_child (GTK_BIN (menu_item));
2224 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2226 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2227 (gpointer) new_font_index))
2228 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2230 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2231 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2232 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2238 modest_msg_edit_window_set_zoom (ModestWindow *window,
2241 ModestMsgEditWindowPrivate *priv;
2242 ModestWindowPrivate *parent_priv;
2243 GtkRadioAction *zoom_radio_action;
2245 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2247 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2248 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2249 priv->zoom_level = zoom;
2250 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2252 /* Zoom level menu options should be updated with the current zoom level */
2253 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2254 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2255 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2256 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2257 /* FIXME: Not availible before Gtk 2.10 */
2259 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2264 modest_msg_edit_window_get_zoom (ModestWindow *window)
2266 ModestMsgEditWindowPrivate *priv;
2268 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2270 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2271 return priv->zoom_level;
2275 zoom_allowed (ModestMsgEditWindow *window)
2279 focus = gtk_window_get_focus (GTK_WINDOW (window));
2280 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2284 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2286 ModestWindowPrivate *parent_priv;
2287 GtkRadioAction *zoom_radio_action;
2288 GSList *group, *node;
2290 /* First we check if the text view is focused. If not, zooming is not allowed */
2291 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2292 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2296 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2297 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2298 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2300 group = gtk_radio_action_get_group (zoom_radio_action);
2302 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2303 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2307 for (node = group; node != NULL; node = g_slist_next (node)) {
2308 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2309 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2317 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2319 ModestWindowPrivate *parent_priv;
2320 GtkRadioAction *zoom_radio_action;
2321 GSList *group, *node;
2323 /* First we check if the text view is focused. If not, zooming is not allowed */
2324 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2325 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2329 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2330 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2331 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2333 group = gtk_radio_action_get_group (zoom_radio_action);
2335 for (node = group; node != NULL; node = g_slist_next (node)) {
2336 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2337 if (node->next != NULL) {
2338 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2341 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2349 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2351 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2352 ModestWindowPrivate *parent_priv;
2353 ModestWindowMgr *mgr;
2354 gboolean is_fullscreen;
2355 GtkAction *fs_toggle_action;
2358 mgr = modest_runtime_get_window_mgr ();
2359 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2361 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2363 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2364 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2365 if (is_fullscreen != active)
2366 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2374 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2377 ModestMsgEditWindowPrivate *priv = NULL;
2378 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2380 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2381 if (!priv->update_caption_visibility)
2384 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2386 gtk_widget_show (priv->cc_caption);
2388 gtk_widget_hide (priv->cc_caption);
2390 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2394 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2397 ModestMsgEditWindowPrivate *priv = NULL;
2398 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2400 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2401 if (!priv->update_caption_visibility)
2404 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2406 gtk_widget_show (priv->bcc_caption);
2408 gtk_widget_hide (priv->bcc_caption);
2410 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2414 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2415 ModestRecptEditor *editor)
2417 ModestMsgEditWindowPrivate *priv;
2419 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2420 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2421 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2423 if (editor == NULL) {
2424 GtkWidget *view_focus;
2425 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2427 /* This code should be kept in sync with ModestRecptEditor. The
2428 textview inside the recpt editor is the one that really gets the
2429 focus. As it's inside a scrolled window, and this one inside the
2430 hbox recpt editor inherits from, we'll need to go up in the
2431 hierarchy to know if the text view is part of the recpt editor
2432 or if it's a different text entry */
2434 if (gtk_widget_get_parent (view_focus)) {
2435 GtkWidget *first_parent;
2437 first_parent = gtk_widget_get_parent (view_focus);
2438 if (gtk_widget_get_parent (first_parent) &&
2439 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2440 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2445 editor = MODEST_RECPT_EDITOR (priv->to_field);
2449 modest_address_book_select_addresses (editor);
2454 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2456 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2458 modest_msg_edit_window_open_addressbook (window, NULL);
2462 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2463 gboolean show_toolbar)
2465 ModestWindowPrivate *parent_priv;
2466 const gchar *action_name;
2469 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2470 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2472 /* We can not just use the code of
2473 modest_msg_edit_window_setup_toolbar because it has a
2474 mixture of both initialization and creation code. */
2476 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2478 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2480 /* Update also the actions (to update the toggles in the
2481 menus), we have to do it manually because some other window
2482 of the same time could have changed it (remember that the
2483 toolbar fullscreen mode is shared by all the windows of the
2485 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2486 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2488 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2490 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2491 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2497 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2498 TnyHeaderFlags priority_flags)
2500 ModestMsgEditWindowPrivate *priv;
2501 ModestWindowPrivate *parent_priv;
2503 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2505 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2506 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2508 if (priv->priority_flags != priority_flags) {
2509 GtkAction *priority_action = NULL;
2511 priv->priority_flags = priority_flags;
2513 switch (priority_flags) {
2514 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2515 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2516 gtk_widget_show (priv->priority_icon);
2517 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2518 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2520 case TNY_HEADER_FLAG_LOW_PRIORITY:
2521 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2522 gtk_widget_show (priv->priority_icon);
2523 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2524 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2527 gtk_widget_hide (priv->priority_icon);
2528 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2529 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2532 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2533 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2538 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2541 ModestMsgEditWindowPrivate *priv;
2542 ModestWindowPrivate *parent_priv;
2543 gint current_format;
2545 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2547 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2548 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2550 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2551 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2553 if (current_format != file_format) {
2554 switch (file_format) {
2555 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2556 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2557 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2559 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2563 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2564 response = gtk_dialog_run (GTK_DIALOG (dialog));
2565 gtk_widget_destroy (dialog);
2566 if (response == GTK_RESPONSE_OK) {
2567 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2569 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2570 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2575 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2580 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2583 ModestMsgEditWindowPrivate *priv;
2584 WPTextBufferFormat oldfmt, fmt;
2585 gint old_position = 0;
2589 GdkColor *color = NULL;
2590 gboolean bold, bold_set, italic, italic_set;
2591 gboolean underline, underline_set;
2592 gboolean strikethrough, strikethrough_set;
2593 gboolean position_set;
2594 gboolean font_size_set, font_set, color_set;
2597 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2598 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2600 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2602 /* First we get the currently selected font information */
2603 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2604 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2606 switch (oldfmt.text_position) {
2607 case TEXT_POSITION_NORMAL:
2610 case TEXT_POSITION_SUPERSCRIPT:
2618 g_object_set (G_OBJECT (dialog),
2619 "bold", oldfmt.bold != FALSE,
2620 "bold-set", !oldfmt.cs.bold,
2621 "underline", oldfmt.underline != FALSE,
2622 "underline-set", !oldfmt.cs.underline,
2623 "italic", oldfmt.italic != FALSE,
2624 "italic-set", !oldfmt.cs.italic,
2625 "strikethrough", oldfmt.strikethrough != FALSE,
2626 "strikethrough-set", !oldfmt.cs.strikethrough,
2627 "color", &oldfmt.color,
2628 "color-set", !oldfmt.cs.color,
2629 "size", wp_font_size[oldfmt.font_size],
2630 "size-set", !oldfmt.cs.font_size,
2631 "position", old_position,
2632 "position-set", !oldfmt.cs.text_position,
2633 "family", wp_get_font_name (oldfmt.font),
2634 "family-set", !oldfmt.cs.font,
2637 gtk_widget_show_all (dialog);
2638 response = gtk_dialog_run (GTK_DIALOG (dialog));
2639 if (response == GTK_RESPONSE_OK) {
2641 g_object_get( dialog,
2643 "bold-set", &bold_set,
2644 "underline", &underline,
2645 "underline-set", &underline_set,
2647 "italic-set", &italic_set,
2648 "strikethrough", &strikethrough,
2649 "strikethrough-set", &strikethrough_set,
2651 "color-set", &color_set,
2653 "size-set", &font_size_set,
2654 "family", &font_name,
2655 "family-set", &font_set,
2656 "position", &position,
2657 "position-set", &position_set,
2662 if (response == GTK_RESPONSE_OK) {
2663 memset(&fmt, 0, sizeof(fmt));
2669 fmt.italic = italic;
2670 fmt.cs.italic = TRUE;
2672 if (underline_set) {
2673 fmt.underline = underline;
2674 fmt.cs.underline = TRUE;
2676 if (strikethrough_set) {
2677 fmt.strikethrough = strikethrough;
2678 fmt.cs.strikethrough = TRUE;
2683 ? TEXT_POSITION_NORMAL
2684 : ( ( position == 1 )
2685 ? TEXT_POSITION_SUPERSCRIPT
2686 : TEXT_POSITION_SUBSCRIPT );
2687 fmt.cs.text_position = TRUE;
2691 fmt.cs.color = TRUE;
2694 fmt.font = wp_get_font_index(font_name,
2699 if (font_size_set) {
2700 fmt.font_size = wp_get_font_size_index(
2701 font_size, DEFAULT_FONT_SIZE);
2702 fmt.cs.font_size = TRUE;
2704 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2705 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2707 gtk_widget_destroy (dialog);
2709 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2713 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2715 ModestMsgEditWindowPrivate *priv;
2717 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2718 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2720 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2722 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2727 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2729 ModestMsgEditWindowPrivate *priv;
2731 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2732 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2734 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2736 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2741 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2743 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2745 priv->can_undo = can_undo;
2749 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2751 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2753 priv->can_redo = can_redo;
2757 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2759 ModestMsgEditWindowPrivate *priv;
2760 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2761 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2763 return priv->can_undo;
2767 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2769 ModestMsgEditWindowPrivate *priv;
2770 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2771 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2773 return priv->can_redo;
2778 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2781 GtkTextIter match_start, match_end;
2783 if (image_id == NULL)
2786 gtk_text_buffer_get_start_iter (buffer, &iter);
2788 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2789 GSList *tags = gtk_text_iter_get_tags (&match_start);
2791 for (node = tags; node != NULL; node = g_slist_next (node)) {
2792 GtkTextTag *tag = (GtkTextTag *) node->data;
2793 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2794 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2795 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2797 offset = gtk_text_iter_get_offset (&match_start);
2798 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2799 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2803 gtk_text_iter_forward_char (&iter);
2808 message_is_empty (ModestMsgEditWindow *window)
2810 ModestMsgEditWindowPrivate *priv = NULL;
2812 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2813 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2815 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2816 * so we can ignore markup.
2818 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2821 count = gtk_text_buffer_get_char_count (buf);
2827 msg_body_focus (GtkWidget *focus,
2828 GdkEventFocus *event,
2832 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2837 recpt_field_changed (GtkTextBuffer *buffer,
2838 ModestMsgEditWindow *editor)
2840 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2844 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2846 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2850 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2852 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2853 GtkTextBuffer *buffer;
2855 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2856 gtk_text_buffer_set_modified (buffer, FALSE);
2857 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2858 gtk_text_buffer_set_modified (buffer, FALSE);
2859 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2860 gtk_text_buffer_set_modified (buffer, FALSE);
2861 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2865 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2867 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2868 GtkTextBuffer *buffer;
2870 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2871 if (gtk_text_buffer_get_modified (buffer))
2873 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2874 if (gtk_text_buffer_get_modified (buffer))
2876 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2877 if (gtk_text_buffer_get_modified (buffer))
2879 if (gtk_text_buffer_get_modified (priv->text_buffer))
2889 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2891 ModestMsgEditWindowPrivate *priv = NULL;
2893 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2894 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2896 /* check if there's no recipient added */
2897 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2898 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2899 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2900 /* no recipient contents, then select contacts */
2901 modest_msg_edit_window_open_addressbook (window, NULL);
2905 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2906 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2909 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2910 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2913 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2914 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2918 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2919 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2920 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2927 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2928 ModestMsgEditWindow *window)
2930 modest_msg_edit_window_offer_attach_file (window);
2934 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2936 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2938 return priv->clipboard_text;
2942 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2944 ModestMsgEditWindow *window)
2946 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2947 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2949 if (!GTK_WIDGET_VISIBLE (window))
2952 text = gtk_clipboard_wait_for_text (selection_clipboard);
2954 if (priv->clipboard_text != NULL) {
2955 g_free (priv->clipboard_text);
2957 priv->clipboard_text = text;
2959 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2962 subject_field_move_cursor (GtkEntry *entry,
2963 GtkMovementStep step,
2968 if (!GTK_WIDGET_VISIBLE (window))
2971 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2975 update_window_title (ModestMsgEditWindow *window)
2977 ModestMsgEditWindowPrivate *priv = NULL;
2978 const gchar *subject;
2980 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2981 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2982 if (subject == NULL || subject[0] == '\0')
2983 subject = _("mail_va_new_email");
2985 gtk_window_set_title (GTK_WINDOW (window), subject);
2990 subject_field_changed (GtkEditable *editable,
2991 ModestMsgEditWindow *window)
2993 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2994 update_window_title (window);
2995 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2996 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3000 subject_field_insert_text (GtkEditable *editable,
3002 gint new_text_length,
3004 ModestMsgEditWindow *window)
3006 GString *result = g_string_new ("");
3008 gint result_len = 0;
3009 const gchar *entry_text = NULL;
3012 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3013 old_length = g_utf8_strlen (entry_text, -1);
3015 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3016 gunichar c = g_utf8_get_char_validated (current, 8);
3017 /* Invalid unichar, stop */
3023 result = g_string_append_unichar (result, c);
3027 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3028 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3031 /* Prevent endless recursion */
3032 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3033 g_signal_emit_by_name (editable, "insert-text",
3034 (gpointer) result->str, (gpointer) result->len,
3035 (gpointer) position, (gpointer) window);
3036 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3040 if (result_len + old_length > 1000) {
3041 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3042 dgettext("hildon-common-strings",
3043 "ckdg_ib_maximum_characters_reached"));
3046 g_string_free (result, TRUE);
3050 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3053 ModestMsgEditWindowPrivate *priv = NULL;
3055 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3056 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3058 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3061 gtk_widget_show_all (priv->find_toolbar);
3062 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3064 gtk_widget_hide_all (priv->find_toolbar);
3065 gtk_widget_grab_focus (priv->msg_body);
3071 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3073 GtkTextIter *match_start,
3074 GtkTextIter *match_end)
3076 GtkTextIter end_iter;
3077 gchar *str_casefold;
3080 gchar *range_casefold;
3083 gboolean result = FALSE;
3090 gtk_text_iter_forward_to_end (&end_iter);
3092 str_casefold = g_utf8_casefold (str, -1);
3093 str_chars_n = strlen (str);
3095 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3096 range_casefold = g_utf8_casefold (range_text, -1);
3097 range_chars_n = strlen (range_casefold);
3099 if (range_chars_n < str_chars_n) {
3100 g_free (str_casefold);
3101 g_free (range_text);
3102 g_free (range_casefold);
3106 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3107 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3108 if (!g_utf8_collate (range_subtext, str_casefold)) {
3109 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3111 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3112 match_start, match_end, NULL);
3113 g_free (found_text);
3115 g_free (range_subtext);
3119 g_free (str_casefold);
3120 g_free (range_text);
3121 g_free (range_casefold);
3128 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3129 ModestMsgEditWindow *window)
3131 gchar *current_search = NULL;
3132 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3134 GtkTextIter selection_start, selection_end;
3135 GtkTextIter match_start, match_end;
3136 gboolean continue_search = FALSE;
3138 if (message_is_empty (window)) {
3139 g_free (priv->last_search);
3140 priv->last_search = NULL;
3141 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3145 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3146 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3147 g_free (current_search);
3148 g_free (priv->last_search);
3149 priv->last_search = NULL;
3150 /* Information banner about empty search */
3151 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3155 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3156 continue_search = TRUE;
3158 g_free (priv->last_search);
3159 priv->last_search = g_strdup (current_search);
3162 if (continue_search) {
3163 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3164 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3165 &match_start, &match_end);
3167 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3169 GtkTextIter buffer_start;
3170 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3171 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3172 &match_start, &match_end);
3174 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3177 /* Mark as selected the string found in search */
3179 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3180 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3182 g_free (priv->last_search);
3183 priv->last_search = NULL;
3185 g_free (current_search);
3189 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3190 ModestMsgEditWindow *window)
3192 GtkToggleAction *toggle;
3193 ModestWindowPrivate *parent_priv;
3194 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3196 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3197 gtk_toggle_action_set_active (toggle, FALSE);
3201 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3203 ModestMsgEditWindowPrivate *priv;
3205 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3210 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3213 ModestMsgEditWindowPrivate *priv;
3215 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3221 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3224 ModestMsgEditWindowPrivate *priv;
3225 TnyHeader *header = NULL;
3227 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3228 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3231 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3233 if (priv->draft_msg != NULL) {
3234 g_object_unref (priv->draft_msg);
3237 if (draft != NULL) {
3238 g_object_ref (draft);
3239 header = tny_msg_get_header (draft);
3240 if (priv->msg_uid) {
3241 g_free (priv->msg_uid);
3242 priv->msg_uid = NULL;
3244 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3245 if (GTK_WIDGET_REALIZED (window))
3246 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3249 priv->draft_msg = draft;
3253 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3254 GtkTextIter *start, GtkTextIter *end,
3257 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3258 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3261 if (tag == NULL+13) return;
3262 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3263 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3264 replace_with_images (window, priv->images);
3269 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3272 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3274 g_return_if_fail (TNY_IS_MIME_PART (part));
3275 priv->attachments = g_list_prepend (priv->attachments, part);
3276 g_object_ref (part);
3277 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3278 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3279 gtk_widget_show_all (priv->attachments_caption);
3280 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3284 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3286 ModestMsgEditWindowPrivate *priv;
3288 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3289 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3291 return priv->msg_uid;
3295 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3296 ModestMsgEditWindowWidgetType widget_type)
3298 ModestMsgEditWindowPrivate *priv;
3300 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3301 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3303 switch (widget_type) {
3304 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3305 return priv->msg_body;
3307 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3308 return priv->to_field;
3310 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3311 return priv->cc_field;
3313 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3314 return priv->bcc_field;
3316 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3317 return priv->subject_field;
3319 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3320 return priv->attachments_view;
3328 remove_tags (WPTextBuffer *buffer)
3330 GtkTextIter start, end;
3332 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3333 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3335 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3339 on_account_removed (TnyAccountStore *account_store,
3340 TnyAccount *account,
3343 /* Do nothing if it's a store account, because we use the
3344 transport to send the messages */
3345 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3346 const gchar *parent_acc = NULL;
3347 const gchar *our_acc = NULL;
3349 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3350 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3351 /* Close this window if I'm showing a message of the removed account */
3352 if (strcmp (parent_acc, our_acc) == 0)
3353 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));