1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include <modest-utils.h>
79 #include "modest-maemo-utils.h"
82 #define DEFAULT_FONT_SIZE 3
83 #define DEFAULT_FONT 2
84 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
85 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
86 #define DEFAULT_MAIN_VBOX_SPACING 6
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #define DEFAULT_FONT_SCALE 1.5
91 static gboolean is_wp_text_buffer_started = FALSE;
93 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
94 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
95 static void modest_msg_edit_window_finalize (GObject *obj);
97 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
98 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
99 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
101 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
102 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
103 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
104 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
105 GtkTextIter *start, GtkTextIter *end,
107 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
108 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
109 static void subject_field_insert_text (GtkEditable *editable,
111 gint new_text_length,
113 ModestMsgEditWindow *window);
114 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
116 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
118 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
121 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
122 GdkEventWindowState *event,
124 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
125 ModestRecptEditor *editor);
126 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
127 ModestMsgEditWindow *window);
129 /* ModestWindow methods implementation */
130 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
131 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
132 gboolean show_toolbar);
133 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
135 ModestMsgEditWindow *window);
136 static void subject_field_move_cursor (GtkEntry *entry,
137 GtkMovementStep step,
141 static void update_window_title (ModestMsgEditWindow *window);
144 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
145 ModestMsgEditWindow *window);
146 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
147 ModestMsgEditWindow *window);
148 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
150 GtkTextIter *match_start,
151 GtkTextIter *match_end);
153 static void remove_tags (WPTextBuffer *buffer);
155 static void on_account_removed (TnyAccountStore *account_store,
159 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
161 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
163 static gdouble get_zoom_do_nothing (ModestWindow *window);
165 static void init_window (ModestMsgEditWindow *obj);
167 static void DEBUG_BUFFER (WPTextBuffer *buffer)
171 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
173 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
174 while (!gtk_text_iter_is_end (&iter)) {
175 GString *output = g_string_new ("");
176 GSList *toggled_tags;
179 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
180 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
181 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
182 GtkTextTag *tag = (GtkTextTag *) node->data;
184 g_object_get (G_OBJECT (tag), "name", &name, NULL);
185 output = g_string_append (output, name);
186 g_string_append (output, " ");
188 output = g_string_append (output, "] OPENED [ ");
189 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
190 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
191 GtkTextTag *tag = (GtkTextTag *) node->data;
193 g_object_get (G_OBJECT (tag), "name", &name, NULL);
194 output = g_string_append (output, name);
195 g_string_append (output, " ");
197 output = g_string_append (output, "]\n");
198 g_message ("%s", output->str);
199 g_string_free (output, TRUE);
200 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
202 g_message ("END BUFFER");
207 /* static gboolean */
208 /* on_key_pressed (GtkWidget *self, */
209 /* GdkEventKey *event, */
210 /* gpointer user_data); */
212 /* list my signals */
219 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
220 struct _ModestMsgEditWindowPrivate {
222 GtkWidget *header_box;
224 ModestPairList *from_field_protos;
225 GtkWidget *from_field;
229 GtkWidget *bcc_field;
230 GtkWidget *subject_field;
231 GtkWidget *attachments_view;
232 GtkWidget *priority_icon;
233 GtkWidget *add_attachment_button;
235 GtkWidget *cc_caption;
236 GtkWidget *bcc_caption;
237 gboolean update_caption_visibility;
238 GtkWidget *attachments_caption;
240 GtkTextBuffer *text_buffer;
242 GtkWidget *font_size_toolitem;
243 GtkWidget *font_face_toolitem;
244 GtkWidget *font_color_button;
245 GSList *font_items_group;
246 GtkWidget *font_tool_button_label;
247 GSList *size_items_group;
248 GtkWidget *size_tool_button_label;
250 GtkWidget *find_toolbar;
254 GtkWidget *scroll_area;
255 gint last_vadj_upper;
258 TnyList *attachments;
261 TnyHeaderFlags priority_flags;
263 gboolean can_undo, can_redo;
264 gulong clipboard_change_handler_id;
265 gulong default_clipboard_change_handler_id;
266 gulong account_removed_handler_id;
267 gchar *clipboard_text;
276 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
277 MODEST_TYPE_MSG_EDIT_WINDOW, \
278 ModestMsgEditWindowPrivate))
280 static GtkWindowClass *parent_class = NULL;
282 /* uncomment the following if you have defined any signals */
283 /* static guint signals[LAST_SIGNAL] = {0}; */
286 modest_msg_edit_window_get_type (void)
288 static GType my_type = 0;
290 static const GTypeInfo my_info = {
291 sizeof(ModestMsgEditWindowClass),
292 NULL, /* base init */
293 NULL, /* base finalize */
294 (GClassInitFunc) modest_msg_edit_window_class_init,
295 NULL, /* class finalize */
296 NULL, /* class data */
297 sizeof(ModestMsgEditWindow),
299 (GInstanceInitFunc) modest_msg_edit_window_init,
302 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
303 "ModestMsgEditWindow",
311 save_state (ModestWindow *self)
313 modest_widget_memory_save (modest_runtime_get_conf(),
314 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
319 restore_settings (ModestMsgEditWindow *self)
321 ModestConf *conf = NULL;
323 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
325 conf = modest_runtime_get_conf ();
326 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
327 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
328 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
329 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
330 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
331 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
332 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
333 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
335 /* set initial state of cc and bcc */
336 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
337 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
338 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
339 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
340 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
341 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
343 /* Dim at start clipboard actions */
344 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
345 gtk_action_set_sensitive (action, FALSE);
346 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
347 gtk_action_set_sensitive (action, FALSE);
348 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
349 gtk_action_set_sensitive (action, FALSE);
351 modest_widget_memory_restore (conf,
352 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
357 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
359 GObjectClass *gobject_class;
360 ModestWindowClass *modest_window_class;
361 gobject_class = (GObjectClass*) klass;
362 modest_window_class = (ModestWindowClass*) klass;
364 parent_class = g_type_class_peek_parent (klass);
365 gobject_class->finalize = modest_msg_edit_window_finalize;
367 modest_window_class->set_zoom_func = set_zoom_do_nothing;
368 modest_window_class->get_zoom_func = get_zoom_do_nothing;
369 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
370 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
371 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
372 modest_window_class->save_state_func = save_state;
373 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
375 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
379 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
381 ModestMsgEditWindowPrivate *priv;
382 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
384 priv->msg_body = NULL;
385 priv->from_field = NULL;
386 priv->to_field = NULL;
387 priv->cc_field = NULL;
388 priv->bcc_field = NULL;
389 priv->subject_field = NULL;
390 priv->attachments = TNY_LIST (tny_simple_list_new ());
391 priv->images = TNY_LIST (tny_simple_list_new ());
394 priv->cc_caption = NULL;
395 priv->bcc_caption = NULL;
396 priv->update_caption_visibility = FALSE;
398 priv->priority_flags = 0;
400 priv->find_toolbar = NULL;
401 priv->last_search = NULL;
403 priv->draft_msg = NULL;
404 priv->outbox_msg = NULL;
405 priv->msg_uid = NULL;
407 priv->can_undo = FALSE;
408 priv->can_redo = FALSE;
409 priv->clipboard_change_handler_id = 0;
410 priv->default_clipboard_change_handler_id = 0;
411 priv->account_removed_handler_id = 0;
412 priv->clipboard_text = NULL;
415 priv->last_vadj_upper = 0;
417 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
418 GTK_WINDOW(obj),"applications_email_editor");
420 if (!is_wp_text_buffer_started) {
421 is_wp_text_buffer_started = TRUE;
422 wp_text_buffer_library_init ();
427 hildon_program_add_window (hildon_program_get_instance(),
432 /* FIXME: this is a dup from the one in gtk/ */
435 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
437 static ModestPairList*
438 get_transports (void)
440 GSList *transports = NULL;
442 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
443 GSList *accounts = modest_account_mgr_account_names (account_mgr,
444 TRUE /* only enabled accounts. */);
446 GSList *cursor = accounts;
448 gchar *account_name = cursor->data;
449 gchar *from_string = NULL;
451 from_string = modest_account_mgr_get_from_string (account_mgr,
455 if (from_string && account_name) {
456 gchar *name = account_name;
457 ModestPair *pair = modest_pair_new ((gpointer) name,
458 (gpointer) from_string , TRUE);
459 transports = g_slist_prepend (transports, pair);
462 cursor = cursor->next;
464 g_slist_free (accounts); /* only free the accounts, not the elements,
465 * because they are used in the pairlist */
469 void vadj_changed (GtkAdjustment *adj,
470 ModestMsgEditWindow *window)
472 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
474 GdkRectangle rectangle, cursor_rectangle;
475 GtkTextIter position;
479 /* We detect if cursor is visible using the full height, not only the center. This
481 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
482 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
484 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
485 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
487 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
488 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
490 if (gtk_widget_is_focus (priv->msg_body) &&
492 if (priv->last_vadj_upper != adj->upper) {
495 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
496 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
497 insert, 0.1, FALSE, 0.0, 0.0);
500 priv->last_vadj_upper = adj->upper;
503 static void window_focus (GtkWindow *window,
507 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
512 connect_signals (ModestMsgEditWindow *obj)
514 ModestMsgEditWindowPrivate *priv;
516 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
518 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
519 G_CALLBACK (text_buffer_refresh_attributes), obj);
520 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
521 G_CALLBACK (text_buffer_can_undo), obj);
522 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
523 G_CALLBACK (text_buffer_can_redo), obj);
524 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
525 G_CALLBACK (body_changed), obj);
526 g_signal_connect (G_OBJECT (obj), "window-state-event",
527 G_CALLBACK (modest_msg_edit_window_window_state_event),
529 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
530 G_CALLBACK (text_buffer_apply_tag), obj);
531 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
532 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
533 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
534 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
535 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
536 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
538 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
539 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
541 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
542 G_CALLBACK (msg_body_focus), obj);
543 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
544 G_CALLBACK (msg_body_focus), obj);
545 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
546 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
547 "changed", G_CALLBACK (recpt_field_changed), obj);
548 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
549 "changed", G_CALLBACK (recpt_field_changed), obj);
550 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
551 "changed", G_CALLBACK (recpt_field_changed), obj);
552 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
553 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
554 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
556 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
557 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
559 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
561 G_CALLBACK (vadj_changed),
564 priv->clipboard_change_handler_id =
565 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
566 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
567 priv->default_clipboard_change_handler_id =
568 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
569 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
574 init_window (ModestMsgEditWindow *obj)
576 GtkWidget *from_caption, *to_caption, *subject_caption;
577 GtkWidget *main_vbox;
578 ModestMsgEditWindowPrivate *priv;
579 GtkActionGroup *action_group;
580 ModestWindowPrivate *parent_priv;
581 GdkPixbuf *window_icon = NULL;
582 GError *error = NULL;
584 GtkSizeGroup *size_group;
586 GtkWidget *subject_box;
587 GtkWidget *attachment_icon;
588 GtkWidget *window_box;
589 #if (GTK_MINOR_VERSION >= 10)
590 GdkAtom deserialize_type;
592 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
593 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
595 parent_priv->ui_manager = gtk_ui_manager_new();
596 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
597 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
599 /* Add common actions */
600 gtk_action_group_add_actions (action_group,
601 modest_msg_edit_action_entries,
602 G_N_ELEMENTS (modest_msg_edit_action_entries),
604 gtk_action_group_add_toggle_actions (action_group,
605 modest_msg_edit_toggle_action_entries,
606 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
608 gtk_action_group_add_radio_actions (action_group,
609 modest_msg_edit_alignment_radio_action_entries,
610 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
612 G_CALLBACK (modest_ui_actions_on_change_justify),
614 gtk_action_group_add_radio_actions (action_group,
615 modest_msg_edit_priority_action_entries,
616 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
618 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
620 gtk_action_group_add_radio_actions (action_group,
621 modest_msg_edit_file_format_action_entries,
622 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
623 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
624 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
626 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
627 g_object_unref (action_group);
629 /* Load the UI definition */
630 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
633 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
634 g_clear_error (&error);
637 /* Add accelerators */
638 gtk_window_add_accel_group (GTK_WINDOW (obj),
639 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
641 parent_priv->menubar = NULL;
643 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
645 /* Note: This ModestPairList* must exist for as long as the combo
646 * that uses it, because the ModestComboBox uses the ID opaquely,
647 * so it can't know how to manage its memory. */
648 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
650 priv->to_field = modest_recpt_editor_new ();
651 priv->cc_field = modest_recpt_editor_new ();
652 priv->bcc_field = modest_recpt_editor_new ();
653 subject_box = gtk_hbox_new (FALSE, 0);
654 priv->priority_icon = gtk_image_new ();
655 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
656 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
657 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
658 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
659 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
660 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
661 priv->add_attachment_button = gtk_button_new ();
662 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
663 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
664 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
665 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
666 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
667 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
668 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
669 priv->attachments_view = modest_attachments_view_new (NULL);
671 priv->header_box = gtk_vbox_new (FALSE, 0);
673 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
674 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
675 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
676 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
677 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
678 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
679 g_object_unref (size_group);
681 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
682 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
683 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
684 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
685 gtk_size_group_add_widget (size_group, priv->subject_field);
686 gtk_size_group_add_widget (size_group, priv->attachments_view);
687 g_object_unref (size_group);
689 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
690 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
691 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
692 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
694 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
695 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
698 priv->msg_body = wp_text_view_new ();
699 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
700 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
701 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
702 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
703 #if (GTK_MINOR_VERSION >= 10)
704 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
705 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
707 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
708 deserialize_type, TRUE);
710 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
712 priv->find_toolbar = hildon_find_toolbar_new (NULL);
713 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
715 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
717 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
718 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
719 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
720 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
722 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
724 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
725 frame = gtk_frame_new (NULL);
726 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
728 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
729 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
730 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
732 G_CALLBACK (vadj_changed),
734 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
736 window_box = gtk_vbox_new (FALSE, 0);
737 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
738 gtk_container_add (GTK_CONTAINER(obj), window_box);
739 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
740 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
742 /* Set window icon */
743 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
745 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
746 g_object_unref (window_icon);
751 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
753 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
755 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
756 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
757 priv->clipboard_change_handler_id))
758 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
759 priv->clipboard_change_handler_id);
760 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
761 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
762 priv->default_clipboard_change_handler_id))
763 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
764 priv->default_clipboard_change_handler_id);
766 if (priv->account_removed_handler_id &&
767 g_signal_handler_is_connected (modest_runtime_get_account_store (),
768 priv->account_removed_handler_id))
769 g_signal_handler_disconnect(modest_runtime_get_account_store (),
770 priv->account_removed_handler_id);
774 modest_msg_edit_window_finalize (GObject *obj)
776 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
778 /* Sanity check: shouldn't be needed, the window mgr should
779 call this function before */
780 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
782 if (priv->clipboard_text != NULL) {
783 g_free (priv->clipboard_text);
784 priv->clipboard_text = NULL;
787 if (priv->draft_msg != NULL) {
788 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
789 if (TNY_IS_HEADER (header)) {
790 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
791 modest_window_mgr_unregister_header (mgr, header);
793 g_object_unref (priv->draft_msg);
794 priv->draft_msg = NULL;
796 if (priv->outbox_msg != NULL) {
797 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
798 if (TNY_IS_HEADER (header)) {
799 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
800 modest_window_mgr_unregister_header (mgr, header);
802 g_object_unref (priv->outbox_msg);
803 priv->outbox_msg = NULL;
805 g_free (priv->msg_uid);
806 g_free (priv->last_search);
807 g_slist_free (priv->font_items_group);
808 g_slist_free (priv->size_items_group);
809 g_object_unref (priv->attachments);
810 g_object_unref (priv->images);
812 /* This had to stay alive for as long as the combobox that used it: */
813 modest_pair_list_free (priv->from_field_protos);
815 G_OBJECT_CLASS(parent_class)->finalize (obj);
819 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
821 GdkPixbufLoader *loader;
824 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
829 tny_stream_reset (TNY_STREAM (stream));
830 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
831 unsigned char read_buffer[128];
833 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
834 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
838 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
839 g_object_ref (pixbuf);
840 gdk_pixbuf_loader_close (loader, NULL);
841 g_object_unref (loader);
843 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
844 GdkPixbuf *new_pixbuf;
846 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
847 gdk_pixbuf_get_width (pixbuf);
848 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
849 g_object_unref (pixbuf);
857 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
859 ModestMsgEditWindowPrivate *priv;
862 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
864 for (iter = tny_list_create_iterator (attachments);
865 !tny_iterator_is_done (iter);
866 tny_iterator_next (iter)) {
867 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
868 const gchar *cid = tny_mime_part_get_content_id (part);
869 const gchar *mime_type = tny_mime_part_get_content_type (part);
870 if ((cid != NULL)&&(mime_type != NULL)) {
871 TnyStream *stream = tny_mime_part_get_stream (part);
872 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
873 g_object_unref (stream);
875 if (pixbuf != NULL) {
876 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
877 g_object_unref (pixbuf);
880 g_object_unref (part);
885 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
887 TnyMimePart *parent = NULL;
888 const gchar *content_type = NULL;
889 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
891 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
893 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
894 parent = g_object_ref (msg);
895 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
896 TnyList *parts = TNY_LIST (tny_simple_list_new ());
899 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
900 iter = tny_list_create_iterator (parts);
901 while (!tny_iterator_is_done (iter)) {
903 part = TNY_MIME_PART (tny_iterator_get_current (iter));
904 content_type = tny_mime_part_get_content_type (part);
905 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
909 g_object_unref (part);
911 tny_iterator_next (iter);
913 g_object_unref (iter);
914 g_object_unref (parts);
917 if (parent != NULL) {
918 TnyList *parts = TNY_LIST (tny_simple_list_new ());
921 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
922 iter = tny_list_create_iterator (parts);
923 while (!tny_iterator_is_done (iter)) {
925 part = TNY_MIME_PART (tny_iterator_get_current (iter));
926 content_type = tny_mime_part_get_content_type (part);
927 if (content_type && g_str_has_prefix (content_type, "image/")) {
928 tny_list_prepend (priv->images, (GObject *) part);
930 g_object_unref (part);
931 tny_iterator_next (iter);
933 g_object_unref (iter);
934 g_object_unref (parts);
935 g_object_unref (parent);
940 update_last_cid (ModestMsgEditWindow *self, TnyList *attachments)
943 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
945 for (iter = tny_list_create_iterator (attachments) ;
946 !tny_iterator_is_done (iter);
947 tny_iterator_next (iter)) {
948 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
949 const gchar *cid = tny_mime_part_get_content_id (part);
951 char *invalid = NULL;
952 gint int_cid = strtol (cid, &invalid, 10);
953 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
954 priv->last_cid = int_cid;
957 g_object_unref (part);
962 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
965 const gchar *to, *cc, *bcc, *subject;
967 ModestMsgEditWindowPrivate *priv;
969 TnyHeaderFlags priority_flags;
970 TnyFolder *msg_folder;
971 gboolean is_html = FALSE;
973 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
974 g_return_if_fail (TNY_IS_MSG (msg));
976 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
978 header = tny_msg_get_header (msg);
979 to = tny_header_get_to (header);
980 cc = tny_header_get_cc (header);
981 bcc = tny_header_get_bcc (header);
982 subject = tny_header_get_subject (header);
983 priority_flags = tny_header_get_priority (header);
986 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
988 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
989 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
990 gtk_widget_show (priv->cc_caption);
991 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
992 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
993 gtk_widget_hide (priv->cc_caption);
996 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
997 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
998 gtk_widget_show (priv->bcc_caption);
999 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1000 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1001 gtk_widget_hide (priv->bcc_caption);
1004 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1005 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1008 update_window_title (self);
1010 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1011 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1013 if ((body == NULL)||(body[0] == '\0')) {
1015 body = modest_text_utils_convert_to_html ("");
1018 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1019 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1022 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1025 /* Add attachments to the view */
1026 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1027 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1028 if (tny_list_get_length (priv->attachments) == 0) {
1029 gtk_widget_hide (priv->attachments_caption);
1031 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1032 gtk_widget_show_all (priv->attachments_caption);
1034 get_related_images (self, msg);
1035 update_last_cid (self, priv->attachments);
1036 update_last_cid (self, priv->images);
1037 replace_with_images (self, priv->images);
1039 if (preserve_is_rich && !is_html) {
1040 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1041 /* Get the default format required from configuration */
1042 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1043 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1046 /* Set the default focus depending on having already a To: field or not */
1047 if ((!to)||(*to == '\0')) {
1048 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1050 gtk_widget_grab_focus (priv->msg_body);
1053 /* TODO: lower priority, select in the From: combo to the
1054 value that comes from msg <- not sure, should it be
1057 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1059 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1060 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1062 modest_msg_edit_window_reset_modified (self);
1064 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1065 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1066 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1068 if (priv->msg_uid) {
1069 g_free (priv->msg_uid);
1070 priv->msg_uid = NULL;
1073 /* we should set a reference to the incoming message if it is a draft */
1074 msg_folder = tny_msg_get_folder (msg);
1076 if (modest_tny_folder_is_local_folder (msg_folder)) {
1077 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1078 if (type == TNY_FOLDER_TYPE_INVALID)
1079 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1081 if (type == TNY_FOLDER_TYPE_DRAFTS)
1082 priv->draft_msg = g_object_ref(msg);
1083 if (type == TNY_FOLDER_TYPE_OUTBOX)
1084 priv->outbox_msg = g_object_ref(msg);
1085 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1087 g_object_unref (msg_folder);
1092 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1095 GList *item_children, *node;
1096 GtkWidget *bin_child;
1098 bin_child = gtk_bin_get_child (GTK_BIN(item));
1100 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1102 for (node = item_children; node != NULL; node = g_list_next (node)) {
1103 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1104 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1107 g_list_free (item_children);
1111 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1114 GList *item_children, *node;
1116 box = gtk_bin_get_child (GTK_BIN (item));
1117 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1118 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1120 for (node = item_children; node != NULL; node = g_list_next (node)) {
1121 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1122 if (GTK_IS_TOGGLE_BUTTON (node->data))
1123 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1124 else if (GTK_IS_BUTTON (node->data))
1125 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1127 g_list_free (item_children);
1132 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1134 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1135 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1136 GtkWidget *placeholder;
1137 GtkWidget *tool_item;
1142 GtkWidget *sizes_menu;
1143 GtkWidget *fonts_menu;
1144 GSList *radio_group = NULL;
1145 GSList *node = NULL;
1149 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1150 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1152 /* Font color placeholder */
1153 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1154 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1157 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1158 priv->font_color_button = hildon_color_button_new ();
1159 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1160 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1161 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1162 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1163 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1164 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1165 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1167 G_CALLBACK (modest_msg_edit_window_color_button_change),
1170 /* Font size and face placeholder */
1171 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1172 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1174 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1175 priv->size_tool_button_label = gtk_label_new (NULL);
1176 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1177 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1178 size_text,"</span>", NULL);
1179 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1181 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1182 sizes_menu = gtk_menu_new ();
1183 priv->size_items_group = NULL;
1185 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1186 GtkWidget *size_menu_item;
1188 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1189 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1190 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1191 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1192 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1193 gtk_widget_show (size_menu_item);
1195 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1199 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1200 GtkWidget *item = (GtkWidget *) node->data;
1201 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1205 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1206 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1207 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1208 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1209 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1210 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1211 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1212 priv->font_size_toolitem = tool_item;
1215 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1216 priv->font_tool_button_label = gtk_label_new (NULL);
1217 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1218 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1220 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1221 fonts_menu = gtk_menu_new ();
1222 priv->font_items_group = NULL;
1224 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1225 GtkWidget *font_menu_item;
1226 GtkWidget *child_label;
1228 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1229 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1230 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1231 wp_get_font_name (font_index), "</span>", NULL);
1232 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1235 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1236 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1237 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1238 gtk_widget_show (font_menu_item);
1240 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1243 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1244 GtkWidget *item = (GtkWidget *) node->data;
1245 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1248 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1249 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1250 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1251 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1252 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1253 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1254 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1255 priv->font_face_toolitem = tool_item;
1257 /* Set expand and homogeneous for remaining items */
1258 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1259 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1260 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1261 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1262 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1263 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1264 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1265 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1266 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1268 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1269 will not show the tool items added to the placeholders) */
1270 gtk_widget_show_all (parent_priv->toolbar);
1272 /* Set the no show all *after* showing all items. We do not
1273 want the toolbar to be shown with a show all because it
1274 could go agains the gconf setting regarding showing or not
1275 the toolbar of the editor window */
1276 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1282 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1285 ModestWindowPrivate *parent_priv;
1286 ModestMsgEditWindowPrivate *priv;
1287 ModestPair *account_pair = NULL;
1288 ModestDimmingRulesGroup *menu_rules_group = NULL;
1289 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1290 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1291 ModestWindowMgr *mgr = NULL;
1293 g_return_val_if_fail (msg, NULL);
1294 g_return_val_if_fail (account_name, NULL);
1296 mgr = modest_runtime_get_window_mgr ();
1298 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1300 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1301 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1303 /* Menubar. Update the state of some toggles */
1304 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1305 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1306 priv->from_field_protos = get_transports ();
1307 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1308 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1309 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1312 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1314 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1316 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1318 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1319 if (account_pair != NULL)
1320 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1322 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1323 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1324 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1325 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1326 /* Add common dimming rules */
1327 modest_dimming_rules_group_add_rules (menu_rules_group,
1328 modest_msg_edit_window_menu_dimming_entries,
1329 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1330 MODEST_WINDOW (obj));
1331 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1332 modest_msg_edit_window_toolbar_dimming_entries,
1333 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1334 MODEST_WINDOW (obj));
1335 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1336 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1337 MODEST_WINDOW (obj));
1338 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1339 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1340 MODEST_WINDOW (obj));
1341 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1342 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1343 MODEST_WINDOW (obj));
1344 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1345 modest_msg_edit_window_clipboard_dimming_entries,
1346 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1347 MODEST_WINDOW (obj));
1348 /* Insert dimming rules group for this window */
1349 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1350 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1351 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1352 /* Checks the dimming rules */
1353 g_object_unref (menu_rules_group);
1354 g_object_unref (toolbar_rules_group);
1355 g_object_unref (clipboard_rules_group);
1356 gtk_widget_show_all (GTK_WIDGET (obj));
1358 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1360 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1362 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1363 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1364 priv->update_caption_visibility = TRUE;
1366 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1368 /* Track account-removed signal, this window should be closed
1369 in the case we're creating a mail associated to the account
1371 priv->account_removed_handler_id =
1372 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1374 G_CALLBACK(on_account_removed),
1377 return (ModestWindow*) obj;
1381 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1383 GString **string_buffer = (GString **) user_data;
1385 *string_buffer = g_string_append (*string_buffer, buffer);
1391 * @result: A new string which should be freed with g_free().
1394 get_formatted_data (ModestMsgEditWindow *edit_window)
1396 ModestMsgEditWindowPrivate *priv;
1397 GString *string_buffer = g_string_new ("");
1399 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1401 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1403 return g_string_free (string_buffer, FALSE);
1408 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1411 const gchar *account_name;
1412 ModestMsgEditWindowPrivate *priv;
1413 TnyIterator *att_iter;
1415 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1417 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1419 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1420 g_return_val_if_fail (account_name, NULL);
1423 /* don't free these (except from) */
1424 data = g_slice_new0 (MsgData);
1425 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1427 data->account_name = g_strdup (account_name);
1428 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1429 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1430 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1431 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1432 if (priv->draft_msg) {
1433 data->draft_msg = g_object_ref (priv->draft_msg);
1434 } else if (priv->outbox_msg) {
1435 data->draft_msg = g_object_ref (priv->outbox_msg);
1437 data->draft_msg = NULL;
1440 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1442 gtk_text_buffer_get_bounds (buf, &b, &e);
1443 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1445 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1446 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1448 data->html_body = NULL;
1450 /* deep-copy the data */
1451 att_iter = tny_list_create_iterator (priv->attachments);
1452 data->attachments = NULL;
1453 while (!tny_iterator_is_done (att_iter)) {
1454 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1455 if (!(TNY_IS_MIME_PART(part))) {
1456 g_warning ("strange data in attachment list");
1457 g_object_unref (part);
1458 tny_iterator_next (att_iter);
1461 data->attachments = g_list_append (data->attachments,
1463 tny_iterator_next (att_iter);
1465 g_object_unref (att_iter);
1467 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1468 att_iter = tny_list_create_iterator (priv->images);
1469 data->images = NULL;
1470 while (!tny_iterator_is_done (att_iter)) {
1471 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1473 if (!(TNY_IS_MIME_PART(part))) {
1474 g_warning ("strange data in attachment list");
1475 g_object_unref (part);
1476 tny_iterator_next (att_iter);
1479 cid = tny_mime_part_get_content_id (part);
1481 gchar *image_tag_id;
1482 GtkTextTag *image_tag;
1484 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1485 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1486 g_free (image_tag_id);
1488 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1490 ((gtk_text_iter_has_tag (&iter, image_tag))||
1491 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1492 data->images = g_list_append (data->images,
1493 g_object_ref (part));
1495 g_object_unref (part);
1496 tny_iterator_next (att_iter);
1499 data->priority_flags = priv->priority_flags;
1506 unref_gobject (GObject *obj, gpointer data)
1508 if (!G_IS_OBJECT(obj))
1510 g_object_unref (obj);
1514 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1517 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1525 g_free (data->from);
1526 g_free (data->subject);
1527 g_free (data->plain_body);
1528 g_free (data->html_body);
1529 g_free (data->account_name);
1531 if (data->draft_msg != NULL) {
1532 g_object_unref (data->draft_msg);
1533 data->draft_msg = NULL;
1536 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1537 g_list_free (data->attachments);
1538 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1539 g_list_free (data->images);
1541 g_slice_free (MsgData, data);
1545 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1548 ModestMsgEditWindowPrivate *priv = NULL;
1549 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1551 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1553 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1555 return MODEST_MSG_EDIT_FORMAT_HTML;
1557 return MODEST_MSG_EDIT_FORMAT_TEXT;
1561 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1562 ModestMsgEditFormat format)
1564 ModestMsgEditWindowPrivate *priv;
1566 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1567 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1570 case MODEST_MSG_EDIT_FORMAT_HTML:
1571 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1573 case MODEST_MSG_EDIT_FORMAT_TEXT:
1574 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1577 g_return_if_reached ();
1581 ModestMsgEditFormatState *
1582 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1584 ModestMsgEditFormatState *format_state = NULL;
1585 ModestMsgEditWindowPrivate *priv;
1586 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1588 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1589 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1591 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1593 format_state = g_new0 (ModestMsgEditFormatState, 1);
1594 format_state->bold = buffer_format->bold&0x1;
1595 format_state->italics = buffer_format->italic&0x1;
1596 format_state->bullet = buffer_format->bullet&0x1;
1597 format_state->color = buffer_format->color;
1598 format_state->font_size = buffer_format->font_size;
1599 format_state->font_family = wp_get_font_name (buffer_format->font);
1600 format_state->justification = buffer_format->justification;
1601 g_free (buffer_format);
1603 return format_state;
1608 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1609 const ModestMsgEditFormatState *format_state)
1611 ModestMsgEditWindowPrivate *priv;
1612 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1613 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1614 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1615 g_return_if_fail (format_state != NULL);
1617 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1618 gtk_widget_grab_focus (priv->msg_body);
1619 buffer_format->bold = (format_state->bold != FALSE);
1620 buffer_format->italic = (format_state->italics != FALSE);
1621 buffer_format->color = format_state->color;
1622 buffer_format->font_size = format_state->font_size;
1623 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1624 buffer_format->justification = format_state->justification;
1625 buffer_format->bullet = format_state->bullet;
1627 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1629 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1630 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1631 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1632 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1633 buffer_format->cs.font = (buffer_format->font != current_format->font);
1634 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1635 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1637 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1638 if (buffer_format->cs.bold) {
1639 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1640 GINT_TO_POINTER (buffer_format->bold&0x1));
1642 if (buffer_format->cs.italic) {
1643 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1644 GINT_TO_POINTER (buffer_format->italic&0x1));
1646 if (buffer_format->cs.color) {
1647 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1648 GINT_TO_POINTER (&(buffer_format->color)));
1650 if (buffer_format->cs.font_size) {
1651 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1652 GINT_TO_POINTER (buffer_format->font_size));
1654 if (buffer_format->cs.justification) {
1655 switch (buffer_format->justification) {
1656 case GTK_JUSTIFY_LEFT:
1657 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1658 GINT_TO_POINTER(TRUE));
1660 case GTK_JUSTIFY_CENTER:
1661 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1662 GINT_TO_POINTER(TRUE));
1664 case GTK_JUSTIFY_RIGHT:
1665 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1666 GINT_TO_POINTER(TRUE));
1673 if (buffer_format->cs.font) {
1674 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1675 GINT_TO_POINTER (buffer_format->font));
1677 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1678 if (buffer_format->cs.bullet) {
1679 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1680 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1682 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1684 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1686 g_free (current_format);
1691 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1693 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1695 ModestWindowPrivate *parent_priv;
1696 ModestMsgEditWindowPrivate *priv;
1697 GtkWidget *new_size_menuitem;
1698 GtkWidget *new_font_menuitem;
1700 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1701 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1703 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1704 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1705 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1706 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1708 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1709 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1710 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1713 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1715 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1716 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1718 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1719 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1721 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1722 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1725 switch (buffer_format->justification)
1727 case GTK_JUSTIFY_LEFT:
1728 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentLeftMenu");
1730 case GTK_JUSTIFY_CENTER:
1731 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentCenterMenu");
1733 case GTK_JUSTIFY_RIGHT:
1734 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentRightMenu");
1741 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1743 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1744 G_CALLBACK (modest_msg_edit_window_color_button_change),
1746 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1747 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1748 G_CALLBACK (modest_msg_edit_window_color_button_change),
1751 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1752 buffer_format->font_size))->data);
1753 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1757 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1758 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1759 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1761 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1762 G_CALLBACK (modest_msg_edit_window_size_change),
1764 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1765 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1766 G_CALLBACK (modest_msg_edit_window_size_change),
1770 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1771 buffer_format->font))->data);
1772 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1776 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1777 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1778 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1780 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1781 G_CALLBACK (modest_msg_edit_window_font_change),
1783 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1784 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1785 G_CALLBACK (modest_msg_edit_window_font_change),
1789 g_free (buffer_format);
1793 #ifdef MODEST_HILDON_VERSION_0
1795 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1798 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1799 ModestMsgEditWindowPrivate *priv;
1800 GtkWidget *dialog = NULL;
1802 GdkColor *new_color = NULL;
1804 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1805 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1807 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1808 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1809 g_free (buffer_format);
1811 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1812 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1813 if (new_color != NULL) {
1814 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1815 (gpointer) new_color);
1818 gtk_widget_destroy (dialog);
1823 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1826 ModestMsgEditWindowPrivate *priv;
1827 GtkWidget *dialog = NULL;
1829 GdkColor *old_color = NULL;
1830 const GdkColor *new_color = NULL;
1832 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1833 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1835 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1836 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1838 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1839 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1840 if (new_color != NULL)
1841 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1843 gtk_widget_destroy (dialog);
1849 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1852 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1853 ModestMsgEditWindowPrivate *priv;
1854 GtkWidget *dialog = NULL;
1856 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1857 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1859 dialog = hildon_color_chooser_new ();
1860 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1861 g_free (buffer_format);
1863 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1865 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1866 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1869 gtk_widget_destroy (dialog);
1874 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1877 ModestMsgEditWindowPrivate *priv;
1878 GtkWidget *dialog = NULL;
1879 GdkColor *old_color = NULL;
1881 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1882 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1884 dialog = hildon_color_chooser_new ();
1885 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1887 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1889 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1890 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1892 gtk_widget_destroy (dialog);
1895 #endif /*!MODEST_HILDON_VERSION_0*/
1899 static TnyStream* create_stream_for_uri (const gchar* uri)
1904 TnyStream *result = NULL;
1906 GnomeVFSHandle *handle = NULL;
1907 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1908 if (test == GNOME_VFS_OK) {
1909 /* Create the tinymail stream: */
1910 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1911 result = TNY_STREAM (tny_vfs_stream_new (handle));
1918 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1921 ModestMsgEditWindowPrivate *priv;
1922 GtkWidget *dialog = NULL;
1924 GSList *uris = NULL;
1925 GSList *uri_node = NULL;
1927 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1929 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1930 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1931 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1933 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1935 response = gtk_dialog_run (GTK_DIALOG (dialog));
1937 case GTK_RESPONSE_OK:
1938 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1943 gtk_widget_destroy (dialog);
1945 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1947 GnomeVFSHandle *handle = NULL;
1948 GnomeVFSResult result;
1949 GtkTextIter position;
1950 GtkTextMark *insert_mark;
1952 uri = (const gchar *) uri_node->data;
1953 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1954 if (result == GNOME_VFS_OK) {
1956 GnomeVFSFileInfo info;
1957 gchar *filename, *basename, *escaped_filename;
1958 TnyMimePart *mime_part;
1960 const gchar *mime_type = NULL;
1961 GnomeVFSURI *vfs_uri;
1963 vfs_uri = gnome_vfs_uri_new (uri);
1965 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1966 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1967 g_free (escaped_filename);
1968 gnome_vfs_uri_unref (vfs_uri);
1970 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1971 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1973 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1975 mime_part = tny_platform_factory_new_mime_part
1976 (modest_runtime_get_platform_factory ());
1978 TnyStream *stream = create_stream_for_uri (uri);
1979 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
1981 content_id = g_strdup_printf ("%d", priv->last_cid);
1982 tny_mime_part_set_content_id (mime_part, content_id);
1983 g_free (content_id);
1986 basename = g_path_get_basename (filename);
1987 tny_mime_part_set_filename (mime_part, basename);
1990 pixbuf = pixbuf_from_stream (stream, mime_type);
1992 if (pixbuf != NULL) {
1993 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1994 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1995 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1998 tny_list_prepend (priv->images, (GObject *) mime_part);
1999 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2001 g_object_unref (mime_part);
2010 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2012 GtkWidget *dialog = NULL;
2014 GSList *uris = NULL;
2017 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2018 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2019 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2021 response = gtk_dialog_run (GTK_DIALOG (dialog));
2023 case GTK_RESPONSE_OK:
2024 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2029 gtk_widget_destroy (dialog);
2031 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2032 const gchar *uri = (const gchar *) uri_node->data;
2033 modest_msg_edit_window_attach_file_one (window, uri);
2035 g_slist_foreach (uris, (GFunc) g_free, NULL);
2036 g_slist_free (uris);
2040 modest_msg_edit_window_attach_file_one (
2041 ModestMsgEditWindow *window,
2044 g_return_if_fail (window);
2045 g_return_if_fail (uri);
2047 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2050 GnomeVFSHandle *handle = NULL;
2051 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2052 if (result == GNOME_VFS_OK) {
2053 TnyMimePart *mime_part;
2055 const gchar *mime_type = NULL;
2057 gchar *escaped_filename;
2060 GnomeVFSFileInfo info;
2061 GnomeVFSURI *vfs_uri;
2063 vfs_uri = gnome_vfs_uri_new (uri);
2066 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2067 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2068 g_free (escaped_filename);
2069 gnome_vfs_uri_unref (vfs_uri);
2071 if (gnome_vfs_get_file_info (uri,
2073 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2075 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2076 mime_part = tny_platform_factory_new_mime_part
2077 (modest_runtime_get_platform_factory ());
2078 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2080 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2082 g_object_unref (stream);
2084 content_id = g_strdup_printf ("%d", priv->last_cid);
2085 tny_mime_part_set_content_id (mime_part, content_id);
2086 g_free (content_id);
2089 basename = g_path_get_basename (filename);
2090 tny_mime_part_set_filename (mime_part, basename);
2093 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2094 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2096 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2097 gtk_widget_show_all (priv->attachments_caption);
2098 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2100 g_object_unref (mime_part);
2105 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2108 ModestMsgEditWindowPrivate *priv;
2111 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2112 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2114 if (att_list == NULL) {
2115 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2117 g_object_ref (att_list);
2120 if (tny_list_get_length (att_list) == 0) {
2121 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2123 GtkWidget *confirmation_dialog = NULL;
2124 gboolean dialog_response;
2125 gchar *message = NULL;
2126 gchar *filename = NULL;
2128 if (tny_list_get_length (att_list) == 1) {
2130 iter = tny_list_create_iterator (att_list);
2131 part = (TnyMimePart *) tny_iterator_get_current (iter);
2132 g_object_unref (iter);
2133 if (TNY_IS_MSG (part)) {
2134 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2136 filename = g_strdup (tny_header_get_subject (header));
2137 g_object_unref (header);
2139 if (filename == NULL) {
2140 filename = g_strdup (_("mail_va_no_subject"));
2143 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2145 g_object_unref (part);
2147 filename = g_strdup ("");
2149 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2150 (tny_list_get_length (att_list) == 1)), filename);
2152 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2154 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2155 gtk_widget_destroy (confirmation_dialog);
2156 if (!dialog_response) {
2157 g_object_unref (att_list);
2160 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2162 for (iter = tny_list_create_iterator (att_list);
2163 !tny_iterator_is_done (iter);
2164 tny_iterator_next (iter)) {
2165 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2166 const gchar *att_id;
2167 tny_list_remove (priv->attachments, (GObject *) mime_part);
2169 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2171 if (tny_list_get_length (priv->attachments) == 0)
2172 gtk_widget_hide (priv->attachments_caption);
2173 att_id = tny_mime_part_get_content_id (mime_part);
2175 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2177 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2178 g_object_unref (mime_part);
2182 g_object_unref (att_list);
2184 /* if the last attachment has been removed, focus the Subject: field */
2185 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2186 gtk_widget_grab_focus (priv->subject_field);
2190 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2193 ModestMsgEditWindowPrivate *priv;
2194 GdkColor *new_color;
2195 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2197 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2198 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2201 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2203 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2205 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2207 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2212 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2215 ModestMsgEditWindowPrivate *priv;
2216 gint new_size_index;
2217 ModestMsgEditWindow *window;
2220 window = MODEST_MSG_EDIT_WINDOW (userdata);
2221 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2222 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2224 if (gtk_check_menu_item_get_active (menu_item)) {
2226 WPTextBufferFormat format;
2228 memset (&format, 0, sizeof (format));
2229 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2231 label = gtk_bin_get_child (GTK_BIN (menu_item));
2233 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2234 format.cs.font_size = TRUE;
2235 format.cs.text_position = TRUE;
2236 format.cs.font = TRUE;
2237 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2238 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2240 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2241 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2242 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2244 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2245 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2246 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2252 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2255 ModestMsgEditWindowPrivate *priv;
2256 gint new_font_index;
2257 ModestMsgEditWindow *window;
2260 window = MODEST_MSG_EDIT_WINDOW (userdata);
2261 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2262 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2264 if (gtk_check_menu_item_get_active (menu_item)) {
2267 label = gtk_bin_get_child (GTK_BIN (menu_item));
2269 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2271 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2272 GINT_TO_POINTER(new_font_index)))
2273 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2275 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2276 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2277 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2283 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2285 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2286 ModestWindowPrivate *parent_priv;
2287 ModestWindowMgr *mgr;
2288 gboolean is_fullscreen;
2289 GtkAction *fs_toggle_action;
2292 mgr = modest_runtime_get_window_mgr ();
2293 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2295 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2297 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2298 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2299 if (is_fullscreen != active)
2300 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2308 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2311 ModestMsgEditWindowPrivate *priv = NULL;
2312 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2314 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2315 if (!priv->update_caption_visibility)
2318 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2320 gtk_widget_show (priv->cc_caption);
2322 gtk_widget_hide (priv->cc_caption);
2324 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2328 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2331 ModestMsgEditWindowPrivate *priv = NULL;
2332 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2334 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2335 if (!priv->update_caption_visibility)
2338 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2340 gtk_widget_show (priv->bcc_caption);
2342 gtk_widget_hide (priv->bcc_caption);
2344 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2348 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2349 ModestRecptEditor *editor)
2351 ModestMsgEditWindowPrivate *priv;
2353 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2354 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2355 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2357 if (editor == NULL) {
2358 GtkWidget *view_focus;
2359 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2361 /* This code should be kept in sync with ModestRecptEditor. The
2362 textview inside the recpt editor is the one that really gets the
2363 focus. As it's inside a scrolled window, and this one inside the
2364 hbox recpt editor inherits from, we'll need to go up in the
2365 hierarchy to know if the text view is part of the recpt editor
2366 or if it's a different text entry */
2368 if (gtk_widget_get_parent (view_focus)) {
2369 GtkWidget *first_parent;
2371 first_parent = gtk_widget_get_parent (view_focus);
2372 if (gtk_widget_get_parent (first_parent) &&
2373 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2374 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2379 editor = MODEST_RECPT_EDITOR (priv->to_field);
2383 modest_address_book_select_addresses (editor);
2388 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2390 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2392 modest_msg_edit_window_open_addressbook (window, NULL);
2396 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2397 gboolean show_toolbar)
2399 ModestWindowPrivate *parent_priv;
2400 const gchar *action_name;
2403 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2404 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2406 /* We can not just use the code of
2407 modest_msg_edit_window_setup_toolbar because it has a
2408 mixture of both initialization and creation code. */
2410 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2412 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2414 /* Update also the actions (to update the toggles in the
2415 menus), we have to do it manually because some other window
2416 of the same time could have changed it (remember that the
2417 toolbar fullscreen mode is shared by all the windows of the
2419 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2420 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2422 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2424 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2425 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2431 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2432 TnyHeaderFlags priority_flags)
2434 ModestMsgEditWindowPrivate *priv;
2435 ModestWindowPrivate *parent_priv;
2437 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2439 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2440 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2442 if (priv->priority_flags != priority_flags) {
2443 GtkAction *priority_action = NULL;
2445 priv->priority_flags = priority_flags;
2447 switch (priority_flags) {
2448 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2449 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2450 gtk_widget_show (priv->priority_icon);
2451 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2452 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2454 case TNY_HEADER_FLAG_LOW_PRIORITY:
2455 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2456 gtk_widget_show (priv->priority_icon);
2457 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2458 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2461 gtk_widget_hide (priv->priority_icon);
2462 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2463 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2466 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2467 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2472 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2475 ModestMsgEditWindowPrivate *priv;
2476 ModestWindowPrivate *parent_priv;
2477 gint current_format;
2479 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2481 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2482 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2484 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2485 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2487 if (current_format != file_format) {
2488 switch (file_format) {
2489 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2490 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2491 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2493 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2497 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2498 response = gtk_dialog_run (GTK_DIALOG (dialog));
2499 gtk_widget_destroy (dialog);
2500 if (response == GTK_RESPONSE_OK) {
2501 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2503 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2504 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2509 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2514 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2517 ModestMsgEditWindowPrivate *priv;
2518 WPTextBufferFormat oldfmt, fmt;
2519 gint old_position = 0;
2523 GdkColor *color = NULL;
2524 gboolean bold, bold_set, italic, italic_set;
2525 gboolean underline, underline_set;
2526 gboolean strikethrough, strikethrough_set;
2527 gboolean position_set;
2528 gboolean font_size_set, font_set, color_set;
2531 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2532 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2534 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2536 /* First we get the currently selected font information */
2537 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2539 switch (oldfmt.text_position) {
2540 case TEXT_POSITION_NORMAL:
2543 case TEXT_POSITION_SUPERSCRIPT:
2551 g_object_set (G_OBJECT (dialog),
2552 "bold", oldfmt.bold != FALSE,
2553 "bold-set", !oldfmt.cs.bold,
2554 "underline", oldfmt.underline != FALSE,
2555 "underline-set", !oldfmt.cs.underline,
2556 "italic", oldfmt.italic != FALSE,
2557 "italic-set", !oldfmt.cs.italic,
2558 "strikethrough", oldfmt.strikethrough != FALSE,
2559 "strikethrough-set", !oldfmt.cs.strikethrough,
2560 "color", &oldfmt.color,
2561 "color-set", !oldfmt.cs.color,
2562 "size", wp_font_size[oldfmt.font_size],
2563 "size-set", !oldfmt.cs.font_size,
2564 "position", old_position,
2565 "position-set", !oldfmt.cs.text_position,
2566 "family", wp_get_font_name (oldfmt.font),
2567 "family-set", !oldfmt.cs.font,
2570 gtk_widget_show_all (dialog);
2571 response = gtk_dialog_run (GTK_DIALOG (dialog));
2572 if (response == GTK_RESPONSE_OK) {
2574 g_object_get( dialog,
2576 "bold-set", &bold_set,
2577 "underline", &underline,
2578 "underline-set", &underline_set,
2580 "italic-set", &italic_set,
2581 "strikethrough", &strikethrough,
2582 "strikethrough-set", &strikethrough_set,
2584 "color-set", &color_set,
2586 "size-set", &font_size_set,
2587 "family", &font_name,
2588 "family-set", &font_set,
2589 "position", &position,
2590 "position-set", &position_set,
2595 if (response == GTK_RESPONSE_OK) {
2596 memset(&fmt, 0, sizeof(fmt));
2602 fmt.italic = italic;
2603 fmt.cs.italic = TRUE;
2605 if (underline_set) {
2606 fmt.underline = underline;
2607 fmt.cs.underline = TRUE;
2609 if (strikethrough_set) {
2610 fmt.strikethrough = strikethrough;
2611 fmt.cs.strikethrough = TRUE;
2616 ? TEXT_POSITION_NORMAL
2617 : ( ( position == 1 )
2618 ? TEXT_POSITION_SUPERSCRIPT
2619 : TEXT_POSITION_SUBSCRIPT );
2620 fmt.cs.text_position = TRUE;
2621 fmt.font_size = oldfmt.font_size;
2625 fmt.cs.color = TRUE;
2628 fmt.font = wp_get_font_index(font_name,
2633 if (font_size_set) {
2634 fmt.cs.font_size = TRUE;
2635 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2637 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2638 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2640 gtk_widget_destroy (dialog);
2642 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2646 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2648 ModestMsgEditWindowPrivate *priv;
2650 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2651 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2653 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2655 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2660 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2662 ModestMsgEditWindowPrivate *priv;
2664 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2665 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2667 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2669 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2674 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2676 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2678 priv->can_undo = can_undo;
2682 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2684 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2686 priv->can_redo = can_redo;
2690 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2692 ModestMsgEditWindowPrivate *priv;
2693 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2694 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2696 return priv->can_undo;
2700 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2702 ModestMsgEditWindowPrivate *priv;
2703 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2704 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2706 return priv->can_redo;
2711 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2714 GtkTextIter match_start, match_end;
2716 if (image_id == NULL)
2719 gtk_text_buffer_get_start_iter (buffer, &iter);
2721 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2722 GSList *tags = gtk_text_iter_get_tags (&match_start);
2724 for (node = tags; node != NULL; node = g_slist_next (node)) {
2725 GtkTextTag *tag = (GtkTextTag *) node->data;
2726 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2727 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2728 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2730 offset = gtk_text_iter_get_offset (&match_start);
2731 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2732 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2736 gtk_text_iter_forward_char (&iter);
2741 message_is_empty (ModestMsgEditWindow *window)
2743 ModestMsgEditWindowPrivate *priv = NULL;
2745 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2746 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2748 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2749 * so we can ignore markup.
2751 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2754 count = gtk_text_buffer_get_char_count (buf);
2760 msg_body_focus (GtkWidget *focus,
2761 GdkEventFocus *event,
2765 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2766 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
2771 recpt_field_changed (GtkTextBuffer *buffer,
2772 ModestMsgEditWindow *editor)
2774 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2778 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2780 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2784 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2786 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2787 GtkTextBuffer *buffer;
2789 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2790 gtk_text_buffer_set_modified (buffer, FALSE);
2791 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2792 gtk_text_buffer_set_modified (buffer, FALSE);
2793 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2794 gtk_text_buffer_set_modified (buffer, FALSE);
2795 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2799 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2801 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2802 GtkTextBuffer *buffer;
2804 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2805 if (gtk_text_buffer_get_modified (buffer))
2807 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2808 if (gtk_text_buffer_get_modified (buffer))
2810 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2811 if (gtk_text_buffer_get_modified (buffer))
2813 if (gtk_text_buffer_get_modified (priv->text_buffer))
2823 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2825 ModestMsgEditWindowPrivate *priv = NULL;
2827 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2828 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2830 /* check if there's no recipient added */
2831 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2832 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2833 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2834 /* no recipient contents, then select contacts */
2835 modest_msg_edit_window_open_addressbook (window, NULL);
2839 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2840 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2843 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2844 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2847 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2848 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2852 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2853 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2854 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2861 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2862 ModestMsgEditWindow *window)
2864 modest_msg_edit_window_offer_attach_file (window);
2868 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2870 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2872 return priv->clipboard_text;
2876 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2878 ModestMsgEditWindow *window)
2880 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2881 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2883 if (!GTK_WIDGET_VISIBLE (window))
2886 text = gtk_clipboard_wait_for_text (selection_clipboard);
2888 if (priv->clipboard_text != NULL) {
2889 g_free (priv->clipboard_text);
2891 priv->clipboard_text = text;
2893 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2896 subject_field_move_cursor (GtkEntry *entry,
2897 GtkMovementStep step,
2902 if (!GTK_WIDGET_VISIBLE (window))
2905 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2909 update_window_title (ModestMsgEditWindow *window)
2911 ModestMsgEditWindowPrivate *priv = NULL;
2912 const gchar *subject;
2914 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2915 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2916 if (subject == NULL || subject[0] == '\0')
2917 subject = _("mail_va_new_email");
2919 gtk_window_set_title (GTK_WINDOW (window), subject);
2924 subject_field_changed (GtkEditable *editable,
2925 ModestMsgEditWindow *window)
2927 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2928 update_window_title (window);
2929 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2930 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2934 subject_field_insert_text (GtkEditable *editable,
2936 gint new_text_length,
2938 ModestMsgEditWindow *window)
2940 GString *result = g_string_new ("");
2942 gint result_len = 0;
2943 const gchar *entry_text = NULL;
2946 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2947 old_length = g_utf8_strlen (entry_text, -1);
2949 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2950 gunichar c = g_utf8_get_char_validated (current, 8);
2951 /* Invalid unichar, stop */
2957 result = g_string_append_unichar (result, c);
2961 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2962 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2965 /* Prevent endless recursion */
2966 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2967 g_signal_emit_by_name (editable, "insert-text",
2968 (gpointer) result->str, (gpointer) result->len,
2969 (gpointer) position, (gpointer) window);
2970 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2974 if (result_len + old_length > 1000) {
2975 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2976 dgettext("hildon-common-strings",
2977 "ckdg_ib_maximum_characters_reached"));
2980 g_string_free (result, TRUE);
2984 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2987 ModestMsgEditWindowPrivate *priv = NULL;
2989 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2990 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2992 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2995 gtk_widget_show_all (priv->find_toolbar);
2996 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2998 gtk_widget_hide_all (priv->find_toolbar);
2999 gtk_widget_grab_focus (priv->msg_body);
3005 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3007 GtkTextIter *match_start,
3008 GtkTextIter *match_end)
3010 GtkTextIter end_iter;
3011 gchar *str_casefold;
3014 gchar *range_casefold;
3017 gboolean result = FALSE;
3024 gtk_text_iter_forward_to_end (&end_iter);
3026 str_casefold = g_utf8_casefold (str, -1);
3027 str_chars_n = strlen (str);
3029 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3030 range_casefold = g_utf8_casefold (range_text, -1);
3031 range_chars_n = strlen (range_casefold);
3033 if (range_chars_n < str_chars_n) {
3034 g_free (str_casefold);
3035 g_free (range_text);
3036 g_free (range_casefold);
3040 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3041 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3042 if (!g_utf8_collate (range_subtext, str_casefold)) {
3043 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3045 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3046 match_start, match_end, NULL);
3047 g_free (found_text);
3049 g_free (range_subtext);
3053 g_free (str_casefold);
3054 g_free (range_text);
3055 g_free (range_casefold);
3062 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3063 ModestMsgEditWindow *window)
3065 gchar *current_search = NULL;
3066 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3068 GtkTextIter selection_start, selection_end;
3069 GtkTextIter match_start, match_end;
3070 gboolean continue_search = FALSE;
3072 if (message_is_empty (window)) {
3073 g_free (priv->last_search);
3074 priv->last_search = NULL;
3075 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3079 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3080 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3081 g_free (current_search);
3082 g_free (priv->last_search);
3083 priv->last_search = NULL;
3084 /* Information banner about empty search */
3085 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3089 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3090 continue_search = TRUE;
3092 g_free (priv->last_search);
3093 priv->last_search = g_strdup (current_search);
3096 if (continue_search) {
3097 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3098 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3099 &match_start, &match_end);
3101 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3103 GtkTextIter buffer_start;
3104 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3105 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3106 &match_start, &match_end);
3108 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3111 /* Mark as selected the string found in search */
3113 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3114 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3116 g_free (priv->last_search);
3117 priv->last_search = NULL;
3119 g_free (current_search);
3123 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3124 ModestMsgEditWindow *window)
3126 GtkToggleAction *toggle;
3127 ModestWindowPrivate *parent_priv;
3128 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3130 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3131 gtk_toggle_action_set_active (toggle, FALSE);
3135 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3137 ModestMsgEditWindowPrivate *priv;
3139 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3144 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3147 ModestMsgEditWindowPrivate *priv;
3149 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3155 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3158 ModestMsgEditWindowPrivate *priv;
3159 TnyHeader *header = NULL;
3161 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3162 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3164 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3165 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3167 if (priv->draft_msg != NULL) {
3168 g_object_unref (priv->draft_msg);
3171 if (draft != NULL) {
3172 g_object_ref (draft);
3173 header = tny_msg_get_header (draft);
3174 if (priv->msg_uid) {
3175 g_free (priv->msg_uid);
3176 priv->msg_uid = NULL;
3178 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3179 if (GTK_WIDGET_REALIZED (window))
3180 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3183 priv->draft_msg = draft;
3187 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3188 GtkTextIter *start, GtkTextIter *end,
3191 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3192 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3195 if (tag == NULL+13) return;
3196 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3197 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3198 replace_with_images (window, priv->images);
3203 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3206 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3208 g_return_if_fail (TNY_IS_MIME_PART (part));
3209 tny_list_prepend (priv->attachments, (GObject *) part);
3210 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3211 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3212 gtk_widget_show_all (priv->attachments_caption);
3213 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3217 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3219 ModestMsgEditWindowPrivate *priv;
3221 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3222 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3224 return priv->msg_uid;
3228 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3229 ModestMsgEditWindowWidgetType widget_type)
3231 ModestMsgEditWindowPrivate *priv;
3233 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3234 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3236 switch (widget_type) {
3237 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3238 return priv->msg_body;
3240 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3241 return priv->to_field;
3243 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3244 return priv->cc_field;
3246 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3247 return priv->bcc_field;
3249 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3250 return priv->subject_field;
3252 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3253 return priv->attachments_view;
3261 remove_tags (WPTextBuffer *buffer)
3263 GtkTextIter start, end;
3265 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3266 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3268 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3272 on_account_removed (TnyAccountStore *account_store,
3273 TnyAccount *account,
3276 /* Do nothing if it's a store account, because we use the
3277 transport to send the messages */
3278 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3279 const gchar *parent_acc = NULL;
3280 const gchar *our_acc = NULL;
3282 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3283 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3284 /* Close this window if I'm showing a message of the removed account */
3285 if (strcmp (parent_acc, our_acc) == 0)
3286 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3291 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3293 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3295 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3301 set_zoom_do_nothing (ModestWindow *window,
3307 get_zoom_do_nothing (ModestWindow *window)