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;
505 connect_signals (ModestMsgEditWindow *obj)
507 ModestMsgEditWindowPrivate *priv;
509 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
511 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
512 G_CALLBACK (text_buffer_refresh_attributes), obj);
513 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
514 G_CALLBACK (text_buffer_can_undo), obj);
515 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
516 G_CALLBACK (text_buffer_can_redo), obj);
517 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
518 G_CALLBACK (body_changed), obj);
519 g_signal_connect (G_OBJECT (obj), "window-state-event",
520 G_CALLBACK (modest_msg_edit_window_window_state_event),
522 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
523 G_CALLBACK (text_buffer_apply_tag), obj);
524 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
525 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
526 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
527 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
528 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
529 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
531 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
532 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
534 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
535 G_CALLBACK (msg_body_focus), obj);
536 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
537 G_CALLBACK (msg_body_focus), obj);
538 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
539 "changed", G_CALLBACK (recpt_field_changed), obj);
540 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
541 "changed", G_CALLBACK (recpt_field_changed), obj);
542 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
543 "changed", G_CALLBACK (recpt_field_changed), obj);
544 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
545 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
546 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
548 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
549 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
551 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
553 G_CALLBACK (vadj_changed),
556 priv->clipboard_change_handler_id =
557 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
558 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
559 priv->default_clipboard_change_handler_id =
560 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
561 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
566 init_window (ModestMsgEditWindow *obj)
568 GtkWidget *from_caption, *to_caption, *subject_caption;
569 GtkWidget *main_vbox;
570 ModestMsgEditWindowPrivate *priv;
571 GtkActionGroup *action_group;
572 ModestWindowPrivate *parent_priv;
573 GdkPixbuf *window_icon = NULL;
574 GError *error = NULL;
576 GtkSizeGroup *size_group;
578 GtkWidget *subject_box;
579 GtkWidget *attachment_icon;
580 GtkWidget *window_box;
581 #if (GTK_MINOR_VERSION >= 10)
582 GdkAtom deserialize_type;
584 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
585 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
587 parent_priv->ui_manager = gtk_ui_manager_new();
588 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
589 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
591 /* Add common actions */
592 gtk_action_group_add_actions (action_group,
593 modest_msg_edit_action_entries,
594 G_N_ELEMENTS (modest_msg_edit_action_entries),
596 gtk_action_group_add_toggle_actions (action_group,
597 modest_msg_edit_toggle_action_entries,
598 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
600 gtk_action_group_add_radio_actions (action_group,
601 modest_msg_edit_alignment_radio_action_entries,
602 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
604 G_CALLBACK (modest_ui_actions_on_change_justify),
606 gtk_action_group_add_radio_actions (action_group,
607 modest_msg_edit_priority_action_entries,
608 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
610 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
612 gtk_action_group_add_radio_actions (action_group,
613 modest_msg_edit_file_format_action_entries,
614 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
615 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
616 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
618 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
619 g_object_unref (action_group);
621 /* Load the UI definition */
622 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
625 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
626 g_clear_error (&error);
629 /* Add accelerators */
630 gtk_window_add_accel_group (GTK_WINDOW (obj),
631 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
633 parent_priv->menubar = NULL;
635 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
637 /* Note: This ModestPairList* must exist for as long as the combo
638 * that uses it, because the ModestComboBox uses the ID opaquely,
639 * so it can't know how to manage its memory. */
640 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
642 priv->to_field = modest_recpt_editor_new ();
643 priv->cc_field = modest_recpt_editor_new ();
644 priv->bcc_field = modest_recpt_editor_new ();
645 subject_box = gtk_hbox_new (FALSE, 0);
646 priv->priority_icon = gtk_image_new ();
647 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
648 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
649 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
650 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
651 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
652 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
653 priv->add_attachment_button = gtk_button_new ();
654 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
655 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
656 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
657 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
658 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
659 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
660 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
661 priv->attachments_view = modest_attachments_view_new (NULL);
663 priv->header_box = gtk_vbox_new (FALSE, 0);
665 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
666 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
667 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
668 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
669 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
670 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
671 g_object_unref (size_group);
673 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
674 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
675 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
676 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
677 gtk_size_group_add_widget (size_group, priv->subject_field);
678 gtk_size_group_add_widget (size_group, priv->attachments_view);
679 g_object_unref (size_group);
681 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
682 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
683 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
684 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
685 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
686 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
687 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
690 priv->msg_body = wp_text_view_new ();
691 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
692 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
693 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
694 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
695 #if (GTK_MINOR_VERSION >= 10)
696 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
697 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
699 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
700 deserialize_type, TRUE);
702 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
704 priv->find_toolbar = hildon_find_toolbar_new (NULL);
705 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
707 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
709 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
710 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
711 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
712 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
714 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
716 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
717 frame = gtk_frame_new (NULL);
718 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
720 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
721 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
722 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
724 G_CALLBACK (vadj_changed),
726 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
728 window_box = gtk_vbox_new (FALSE, 0);
729 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
730 gtk_container_add (GTK_CONTAINER(obj), window_box);
731 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
732 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
734 /* Set window icon */
735 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
737 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
738 g_object_unref (window_icon);
743 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
745 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
747 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
748 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
749 priv->clipboard_change_handler_id))
750 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
751 priv->clipboard_change_handler_id);
752 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
753 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
754 priv->default_clipboard_change_handler_id))
755 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
756 priv->default_clipboard_change_handler_id);
758 if (priv->account_removed_handler_id &&
759 g_signal_handler_is_connected (modest_runtime_get_account_store (),
760 priv->account_removed_handler_id))
761 g_signal_handler_disconnect(modest_runtime_get_account_store (),
762 priv->account_removed_handler_id);
766 modest_msg_edit_window_finalize (GObject *obj)
768 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
770 /* Sanity check: shouldn't be needed, the window mgr should
771 call this function before */
772 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
774 if (priv->clipboard_text != NULL) {
775 g_free (priv->clipboard_text);
776 priv->clipboard_text = NULL;
779 if (priv->draft_msg != NULL) {
780 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
781 if (TNY_IS_HEADER (header)) {
782 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
783 modest_window_mgr_unregister_header (mgr, header);
785 g_object_unref (priv->draft_msg);
786 priv->draft_msg = NULL;
788 if (priv->outbox_msg != NULL) {
789 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
790 if (TNY_IS_HEADER (header)) {
791 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
792 modest_window_mgr_unregister_header (mgr, header);
794 g_object_unref (priv->outbox_msg);
795 priv->outbox_msg = NULL;
797 g_free (priv->msg_uid);
798 g_free (priv->last_search);
799 g_slist_free (priv->font_items_group);
800 g_slist_free (priv->size_items_group);
801 g_object_unref (priv->attachments);
802 g_object_unref (priv->images);
804 /* This had to stay alive for as long as the combobox that used it: */
805 modest_pair_list_free (priv->from_field_protos);
807 G_OBJECT_CLASS(parent_class)->finalize (obj);
811 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
813 GdkPixbufLoader *loader;
816 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
821 tny_stream_reset (TNY_STREAM (stream));
822 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
823 unsigned char read_buffer[128];
825 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
826 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
830 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
831 g_object_ref (pixbuf);
832 gdk_pixbuf_loader_close (loader, NULL);
833 g_object_unref (loader);
835 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
836 GdkPixbuf *new_pixbuf;
838 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
839 gdk_pixbuf_get_width (pixbuf);
840 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
841 g_object_unref (pixbuf);
849 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
851 ModestMsgEditWindowPrivate *priv;
854 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
856 for (iter = tny_list_create_iterator (attachments);
857 !tny_iterator_is_done (iter);
858 tny_iterator_next (iter)) {
859 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
860 const gchar *cid = tny_mime_part_get_content_id (part);
861 const gchar *mime_type = tny_mime_part_get_content_type (part);
862 if ((cid != NULL)&&(mime_type != NULL)) {
863 TnyStream *stream = tny_mime_part_get_stream (part);
864 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
865 g_object_unref (stream);
867 if (pixbuf != NULL) {
868 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
869 g_object_unref (pixbuf);
872 g_object_unref (part);
877 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
879 TnyMimePart *parent = NULL;
880 const gchar *content_type = NULL;
881 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
883 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
885 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
886 parent = g_object_ref (msg);
887 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
888 TnyList *parts = TNY_LIST (tny_simple_list_new ());
891 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
892 iter = tny_list_create_iterator (parts);
893 while (!tny_iterator_is_done (iter)) {
895 part = TNY_MIME_PART (tny_iterator_get_current (iter));
896 content_type = tny_mime_part_get_content_type (part);
897 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
901 g_object_unref (part);
903 tny_iterator_next (iter);
905 g_object_unref (iter);
906 g_object_unref (parts);
909 if (parent != NULL) {
910 TnyList *parts = TNY_LIST (tny_simple_list_new ());
913 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
914 iter = tny_list_create_iterator (parts);
915 while (!tny_iterator_is_done (iter)) {
917 part = TNY_MIME_PART (tny_iterator_get_current (iter));
918 content_type = tny_mime_part_get_content_type (part);
919 if (content_type && g_str_has_prefix (content_type, "image/")) {
920 tny_list_prepend (priv->images, (GObject *) part);
922 g_object_unref (part);
923 tny_iterator_next (iter);
925 g_object_unref (iter);
926 g_object_unref (parts);
927 g_object_unref (parent);
932 update_last_cid (ModestMsgEditWindow *self, TnyList *attachments)
935 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
937 for (iter = tny_list_create_iterator (attachments) ;
938 !tny_iterator_is_done (iter);
939 tny_iterator_next (iter)) {
940 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
941 const gchar *cid = tny_mime_part_get_content_id (part);
943 char *invalid = NULL;
944 gint int_cid = strtol (cid, &invalid, 10);
945 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
946 priv->last_cid = int_cid;
949 g_object_unref (part);
954 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
957 const gchar *to, *cc, *bcc, *subject;
959 ModestMsgEditWindowPrivate *priv;
961 TnyHeaderFlags priority_flags;
962 TnyFolder *msg_folder;
963 gboolean is_html = FALSE;
965 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
966 g_return_if_fail (TNY_IS_MSG (msg));
968 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
970 header = tny_msg_get_header (msg);
971 to = tny_header_get_to (header);
972 cc = tny_header_get_cc (header);
973 bcc = tny_header_get_bcc (header);
974 subject = tny_header_get_subject (header);
975 priority_flags = tny_header_get_priority (header);
978 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
980 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
981 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
982 gtk_widget_show (priv->cc_caption);
983 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
984 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
985 gtk_widget_hide (priv->cc_caption);
988 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
989 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
990 gtk_widget_show (priv->bcc_caption);
991 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
992 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
993 gtk_widget_hide (priv->bcc_caption);
996 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
997 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1000 update_window_title (self);
1002 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1003 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1005 if ((body == NULL)||(body[0] == '\0')) {
1007 body = modest_text_utils_convert_to_html ("");
1010 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1011 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1014 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1017 /* Add attachments to the view */
1018 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1019 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1020 if (tny_list_get_length (priv->attachments) == 0) {
1021 gtk_widget_hide (priv->attachments_caption);
1023 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1024 gtk_widget_show_all (priv->attachments_caption);
1026 get_related_images (self, msg);
1027 update_last_cid (self, priv->attachments);
1028 update_last_cid (self, priv->images);
1029 replace_with_images (self, priv->images);
1031 if (preserve_is_rich && !is_html) {
1032 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1033 /* Get the default format required from configuration */
1034 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1035 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1038 /* Set the default focus depending on having already a To: field or not */
1039 if ((!to)||(*to == '\0')) {
1040 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1042 gtk_widget_grab_focus (priv->msg_body);
1045 /* TODO: lower priority, select in the From: combo to the
1046 value that comes from msg <- not sure, should it be
1049 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1051 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1052 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1054 modest_msg_edit_window_reset_modified (self);
1056 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (self));
1057 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1058 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1060 if (priv->msg_uid) {
1061 g_free (priv->msg_uid);
1062 priv->msg_uid = NULL;
1065 /* we should set a reference to the incoming message if it is a draft */
1066 msg_folder = tny_msg_get_folder (msg);
1068 if (modest_tny_folder_is_local_folder (msg_folder)) {
1069 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1070 if (type == TNY_FOLDER_TYPE_INVALID)
1071 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1073 if (type == TNY_FOLDER_TYPE_DRAFTS)
1074 priv->draft_msg = g_object_ref(msg);
1075 if (type == TNY_FOLDER_TYPE_OUTBOX)
1076 priv->outbox_msg = g_object_ref(msg);
1077 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1079 g_object_unref (msg_folder);
1084 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1087 GList *item_children, *node;
1088 GtkWidget *bin_child;
1090 bin_child = gtk_bin_get_child (GTK_BIN(item));
1092 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1094 for (node = item_children; node != NULL; node = g_list_next (node)) {
1095 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1096 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1099 g_list_free (item_children);
1103 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1106 GList *item_children, *node;
1108 box = gtk_bin_get_child (GTK_BIN (item));
1109 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1110 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1112 for (node = item_children; node != NULL; node = g_list_next (node)) {
1113 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1114 if (GTK_IS_TOGGLE_BUTTON (node->data))
1115 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1116 else if (GTK_IS_BUTTON (node->data))
1117 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1119 g_list_free (item_children);
1124 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1126 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1127 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1128 GtkWidget *placeholder;
1129 GtkWidget *tool_item;
1134 GtkWidget *sizes_menu;
1135 GtkWidget *fonts_menu;
1136 GSList *radio_group = NULL;
1137 GSList *node = NULL;
1141 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1142 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1144 /* Font color placeholder */
1145 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1146 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1149 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1150 priv->font_color_button = hildon_color_button_new ();
1151 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1152 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1153 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1154 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1155 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1156 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1157 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1159 G_CALLBACK (modest_msg_edit_window_color_button_change),
1162 /* Font size and face placeholder */
1163 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1164 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1166 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1167 priv->size_tool_button_label = gtk_label_new (NULL);
1168 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1169 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1170 size_text,"</span>", NULL);
1171 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1173 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1174 sizes_menu = gtk_menu_new ();
1175 priv->size_items_group = NULL;
1177 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1178 GtkWidget *size_menu_item;
1180 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1181 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1182 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1183 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1184 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1185 gtk_widget_show (size_menu_item);
1187 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1191 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1192 GtkWidget *item = (GtkWidget *) node->data;
1193 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1197 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1198 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1199 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1200 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1201 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1202 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1203 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1204 priv->font_size_toolitem = tool_item;
1207 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1208 priv->font_tool_button_label = gtk_label_new (NULL);
1209 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1210 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1212 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1213 fonts_menu = gtk_menu_new ();
1214 priv->font_items_group = NULL;
1216 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1217 GtkWidget *font_menu_item;
1218 GtkWidget *child_label;
1220 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1221 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1222 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1223 wp_get_font_name (font_index), "</span>", NULL);
1224 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1227 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1228 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1229 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1230 gtk_widget_show (font_menu_item);
1232 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1235 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1236 GtkWidget *item = (GtkWidget *) node->data;
1237 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1240 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1241 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1242 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1243 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1244 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1245 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1246 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1247 priv->font_face_toolitem = tool_item;
1249 /* Set expand and homogeneous for remaining items */
1250 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1251 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1252 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1253 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1254 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1255 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1256 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1257 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1258 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1260 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1261 will not show the tool items added to the placeholders) */
1262 gtk_widget_show_all (parent_priv->toolbar);
1264 /* Set the no show all *after* showing all items. We do not
1265 want the toolbar to be shown with a show all because it
1266 could go agains the gconf setting regarding showing or not
1267 the toolbar of the editor window */
1268 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1274 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1277 ModestWindowPrivate *parent_priv;
1278 ModestMsgEditWindowPrivate *priv;
1279 ModestPair *account_pair = NULL;
1280 ModestDimmingRulesGroup *window_rules_group = NULL;
1281 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1282 ModestWindowMgr *mgr = NULL;
1284 g_return_val_if_fail (msg, NULL);
1285 g_return_val_if_fail (account_name, NULL);
1287 mgr = modest_runtime_get_window_mgr ();
1289 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1291 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1292 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1294 /* Menubar. Update the state of some toggles */
1295 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1296 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1297 priv->from_field_protos = get_transports ();
1298 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1299 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1300 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1303 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1305 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1307 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1309 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1310 if (account_pair != NULL)
1311 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1313 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1314 window_rules_group = modest_dimming_rules_group_new ("ModestWindowDimmingRules", TRUE);
1315 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1316 /* Add common dimming rules */
1317 modest_dimming_rules_group_add_rules (window_rules_group,
1318 modest_msg_edit_window_toolbar_dimming_entries,
1319 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1320 MODEST_WINDOW (obj));
1321 modest_dimming_rules_group_add_rules (window_rules_group,
1322 modest_msg_edit_window_menu_dimming_entries,
1323 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1324 MODEST_WINDOW (obj));
1325 modest_dimming_rules_group_add_widget_rule (window_rules_group, priv->font_color_button,
1326 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1327 MODEST_WINDOW (obj));
1328 modest_dimming_rules_group_add_widget_rule (window_rules_group, priv->font_size_toolitem,
1329 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1330 MODEST_WINDOW (obj));
1331 modest_dimming_rules_group_add_widget_rule (window_rules_group, priv->font_face_toolitem,
1332 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1333 MODEST_WINDOW (obj));
1334 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1335 modest_msg_edit_window_clipboard_dimming_entries,
1336 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1337 MODEST_WINDOW (obj));
1338 /* Insert dimming rules group for this window */
1339 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, window_rules_group);
1340 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1341 /* Checks the dimming rules */
1342 g_object_unref (window_rules_group);
1343 g_object_unref (clipboard_rules_group);
1344 gtk_widget_show_all (GTK_WIDGET (obj));
1346 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1348 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1350 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (obj));
1351 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1352 priv->update_caption_visibility = TRUE;
1354 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1356 /* Track account-removed signal, this window should be closed
1357 in the case we're creating a mail associated to the account
1359 priv->account_removed_handler_id =
1360 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1362 G_CALLBACK(on_account_removed),
1365 return (ModestWindow*) obj;
1369 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1371 GString **string_buffer = (GString **) user_data;
1373 *string_buffer = g_string_append (*string_buffer, buffer);
1379 * @result: A new string which should be freed with g_free().
1382 get_formatted_data (ModestMsgEditWindow *edit_window)
1384 ModestMsgEditWindowPrivate *priv;
1385 GString *string_buffer = g_string_new ("");
1387 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1389 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1391 return g_string_free (string_buffer, FALSE);
1396 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1399 const gchar *account_name;
1400 ModestMsgEditWindowPrivate *priv;
1401 TnyIterator *att_iter;
1403 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1405 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1407 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1408 g_return_val_if_fail (account_name, NULL);
1411 /* don't free these (except from) */
1412 data = g_slice_new0 (MsgData);
1413 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1415 data->account_name = g_strdup (account_name);
1416 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1417 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1418 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1419 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1420 if (priv->draft_msg) {
1421 data->draft_msg = g_object_ref (priv->draft_msg);
1422 } else if (priv->outbox_msg) {
1423 data->draft_msg = g_object_ref (priv->outbox_msg);
1425 data->draft_msg = NULL;
1428 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1430 gtk_text_buffer_get_bounds (buf, &b, &e);
1431 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1433 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1434 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1436 data->html_body = NULL;
1438 /* deep-copy the data */
1439 att_iter = tny_list_create_iterator (priv->attachments);
1440 data->attachments = NULL;
1441 while (!tny_iterator_is_done (att_iter)) {
1442 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1443 if (!(TNY_IS_MIME_PART(part))) {
1444 g_warning ("strange data in attachment list");
1445 g_object_unref (part);
1446 tny_iterator_next (att_iter);
1449 data->attachments = g_list_append (data->attachments,
1451 tny_iterator_next (att_iter);
1453 g_object_unref (att_iter);
1455 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1456 att_iter = tny_list_create_iterator (priv->images);
1457 data->images = NULL;
1458 while (!tny_iterator_is_done (att_iter)) {
1459 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1461 if (!(TNY_IS_MIME_PART(part))) {
1462 g_warning ("strange data in attachment list");
1463 g_object_unref (part);
1464 tny_iterator_next (att_iter);
1467 cid = tny_mime_part_get_content_id (part);
1469 gchar *image_tag_id;
1470 GtkTextTag *image_tag;
1472 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1473 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1474 g_free (image_tag_id);
1476 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1478 ((gtk_text_iter_has_tag (&iter, image_tag))||
1479 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1480 data->images = g_list_append (data->images,
1481 g_object_ref (part));
1483 g_object_unref (part);
1484 tny_iterator_next (att_iter);
1487 data->priority_flags = priv->priority_flags;
1494 unref_gobject (GObject *obj, gpointer data)
1496 if (!G_IS_OBJECT(obj))
1498 g_object_unref (obj);
1502 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1505 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1513 g_free (data->from);
1514 g_free (data->subject);
1515 g_free (data->plain_body);
1516 g_free (data->html_body);
1517 g_free (data->account_name);
1519 if (data->draft_msg != NULL) {
1520 g_object_unref (data->draft_msg);
1521 data->draft_msg = NULL;
1524 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1525 g_list_free (data->attachments);
1526 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1527 g_list_free (data->images);
1529 g_slice_free (MsgData, data);
1533 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1536 ModestMsgEditWindowPrivate *priv = NULL;
1537 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1539 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1541 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1543 return MODEST_MSG_EDIT_FORMAT_HTML;
1545 return MODEST_MSG_EDIT_FORMAT_TEXT;
1549 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1550 ModestMsgEditFormat format)
1552 ModestMsgEditWindowPrivate *priv;
1554 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1555 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1558 case MODEST_MSG_EDIT_FORMAT_HTML:
1559 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1561 case MODEST_MSG_EDIT_FORMAT_TEXT:
1562 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1565 g_return_if_reached ();
1569 ModestMsgEditFormatState *
1570 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1572 ModestMsgEditFormatState *format_state = NULL;
1573 ModestMsgEditWindowPrivate *priv;
1574 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1576 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1577 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1579 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1581 format_state = g_new0 (ModestMsgEditFormatState, 1);
1582 format_state->bold = buffer_format->bold&0x1;
1583 format_state->italics = buffer_format->italic&0x1;
1584 format_state->bullet = buffer_format->bullet&0x1;
1585 format_state->color = buffer_format->color;
1586 format_state->font_size = buffer_format->font_size;
1587 format_state->font_family = wp_get_font_name (buffer_format->font);
1588 format_state->justification = buffer_format->justification;
1589 g_free (buffer_format);
1591 return format_state;
1596 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1597 const ModestMsgEditFormatState *format_state)
1599 ModestMsgEditWindowPrivate *priv;
1600 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1601 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1602 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1603 g_return_if_fail (format_state != NULL);
1605 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1606 gtk_widget_grab_focus (priv->msg_body);
1607 buffer_format->bold = (format_state->bold != FALSE);
1608 buffer_format->italic = (format_state->italics != FALSE);
1609 buffer_format->color = format_state->color;
1610 buffer_format->font_size = format_state->font_size;
1611 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1612 buffer_format->justification = format_state->justification;
1613 buffer_format->bullet = format_state->bullet;
1615 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1617 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1618 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1619 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1620 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1621 buffer_format->cs.font = (buffer_format->font != current_format->font);
1622 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1623 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1625 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1626 if (buffer_format->cs.bold) {
1627 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1628 GINT_TO_POINTER (buffer_format->bold&0x1));
1630 if (buffer_format->cs.italic) {
1631 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1632 GINT_TO_POINTER (buffer_format->italic&0x1));
1634 if (buffer_format->cs.color) {
1635 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1636 GINT_TO_POINTER (&(buffer_format->color)));
1638 if (buffer_format->cs.font_size) {
1639 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1640 GINT_TO_POINTER (buffer_format->font_size));
1642 if (buffer_format->cs.justification) {
1643 switch (buffer_format->justification) {
1644 case GTK_JUSTIFY_LEFT:
1645 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1646 GINT_TO_POINTER(TRUE));
1648 case GTK_JUSTIFY_CENTER:
1649 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1650 GINT_TO_POINTER(TRUE));
1652 case GTK_JUSTIFY_RIGHT:
1653 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1654 GINT_TO_POINTER(TRUE));
1661 if (buffer_format->cs.font) {
1662 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1663 GINT_TO_POINTER (buffer_format->font));
1665 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1666 if (buffer_format->cs.bullet) {
1667 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1668 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1670 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1672 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1674 g_free (current_format);
1679 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1681 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1683 ModestWindowPrivate *parent_priv;
1684 ModestMsgEditWindowPrivate *priv;
1685 GtkWidget *new_size_menuitem;
1686 GtkWidget *new_font_menuitem;
1688 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1689 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1691 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1692 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1693 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1694 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1696 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1697 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1698 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1701 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1703 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1704 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1706 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1707 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1709 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1710 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1713 switch (buffer_format->justification)
1715 case GTK_JUSTIFY_LEFT:
1716 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentLeftMenu");
1718 case GTK_JUSTIFY_CENTER:
1719 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentCenterMenu");
1721 case GTK_JUSTIFY_RIGHT:
1722 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentRightMenu");
1729 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1731 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1732 G_CALLBACK (modest_msg_edit_window_color_button_change),
1734 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1735 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1736 G_CALLBACK (modest_msg_edit_window_color_button_change),
1739 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1740 buffer_format->font_size))->data);
1741 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1745 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1746 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1747 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1749 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1750 G_CALLBACK (modest_msg_edit_window_size_change),
1752 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1753 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1754 G_CALLBACK (modest_msg_edit_window_size_change),
1758 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1759 buffer_format->font))->data);
1760 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1764 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1765 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1766 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1768 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1769 G_CALLBACK (modest_msg_edit_window_font_change),
1771 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1772 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1773 G_CALLBACK (modest_msg_edit_window_font_change),
1777 g_free (buffer_format);
1781 #ifdef MODEST_HILDON_VERSION_0
1783 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1786 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1787 ModestMsgEditWindowPrivate *priv;
1788 GtkWidget *dialog = NULL;
1790 GdkColor *new_color = NULL;
1792 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1793 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1795 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1796 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1797 g_free (buffer_format);
1799 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1800 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1801 if (new_color != NULL) {
1802 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1803 (gpointer) new_color);
1806 gtk_widget_destroy (dialog);
1811 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1814 ModestMsgEditWindowPrivate *priv;
1815 GtkWidget *dialog = NULL;
1817 GdkColor *old_color = NULL;
1818 const GdkColor *new_color = NULL;
1820 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1821 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1823 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1824 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1826 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1827 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1828 if (new_color != NULL)
1829 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1831 gtk_widget_destroy (dialog);
1837 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1840 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1841 ModestMsgEditWindowPrivate *priv;
1842 GtkWidget *dialog = NULL;
1844 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1845 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1847 dialog = hildon_color_chooser_new ();
1848 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1849 g_free (buffer_format);
1851 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1853 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1854 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1857 gtk_widget_destroy (dialog);
1862 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1865 ModestMsgEditWindowPrivate *priv;
1866 GtkWidget *dialog = NULL;
1867 GdkColor *old_color = NULL;
1869 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1870 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1872 dialog = hildon_color_chooser_new ();
1873 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1875 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1877 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1878 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1880 gtk_widget_destroy (dialog);
1883 #endif /*!MODEST_HILDON_VERSION_0*/
1887 static TnyStream* create_stream_for_uri (const gchar* uri)
1892 TnyStream *result = NULL;
1894 GnomeVFSHandle *handle = NULL;
1895 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1896 if (test == GNOME_VFS_OK) {
1897 /* Create the tinymail stream: */
1898 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1899 result = TNY_STREAM (tny_vfs_stream_new (handle));
1906 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1909 ModestMsgEditWindowPrivate *priv;
1910 GtkWidget *dialog = NULL;
1912 GSList *uris = NULL;
1913 GSList *uri_node = NULL;
1915 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1917 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1918 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1919 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1921 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1923 response = gtk_dialog_run (GTK_DIALOG (dialog));
1925 case GTK_RESPONSE_OK:
1926 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1931 gtk_widget_destroy (dialog);
1933 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1935 GnomeVFSHandle *handle = NULL;
1936 GnomeVFSResult result;
1937 GtkTextIter position;
1938 GtkTextMark *insert_mark;
1940 uri = (const gchar *) uri_node->data;
1941 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1942 if (result == GNOME_VFS_OK) {
1944 GnomeVFSFileInfo info;
1945 gchar *filename, *basename, *escaped_filename;
1946 TnyMimePart *mime_part;
1948 const gchar *mime_type = NULL;
1949 GnomeVFSURI *vfs_uri;
1951 vfs_uri = gnome_vfs_uri_new (uri);
1953 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1954 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1955 g_free (escaped_filename);
1956 gnome_vfs_uri_unref (vfs_uri);
1958 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1959 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1961 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1963 mime_part = tny_platform_factory_new_mime_part
1964 (modest_runtime_get_platform_factory ());
1966 TnyStream *stream = create_stream_for_uri (uri);
1967 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1969 content_id = g_strdup_printf ("%d", priv->last_cid);
1970 tny_mime_part_set_content_id (mime_part, content_id);
1971 g_free (content_id);
1974 basename = g_path_get_basename (filename);
1975 tny_mime_part_set_filename (mime_part, basename);
1978 pixbuf = pixbuf_from_stream (stream, mime_type);
1980 if (pixbuf != NULL) {
1981 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1982 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1983 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1986 tny_list_prepend (priv->images, (GObject *) mime_part);
1987 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1989 g_object_unref (mime_part);
1998 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2000 GtkWidget *dialog = NULL;
2002 GSList *uris = NULL;
2005 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2006 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2007 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2009 response = gtk_dialog_run (GTK_DIALOG (dialog));
2011 case GTK_RESPONSE_OK:
2012 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2017 gtk_widget_destroy (dialog);
2019 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2020 const gchar *uri = (const gchar *) uri_node->data;
2021 modest_msg_edit_window_attach_file_one (window, uri);
2023 g_slist_foreach (uris, (GFunc) g_free, NULL);
2024 g_slist_free (uris);
2028 modest_msg_edit_window_attach_file_one (
2029 ModestMsgEditWindow *window,
2032 g_return_if_fail (window);
2033 g_return_if_fail (uri);
2035 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2038 GnomeVFSHandle *handle = NULL;
2039 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2040 if (result == GNOME_VFS_OK) {
2041 TnyMimePart *mime_part;
2043 const gchar *mime_type = NULL;
2045 gchar *escaped_filename;
2048 GnomeVFSFileInfo info;
2049 GnomeVFSURI *vfs_uri;
2051 vfs_uri = gnome_vfs_uri_new (uri);
2054 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2055 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2056 g_free (escaped_filename);
2057 gnome_vfs_uri_unref (vfs_uri);
2059 if (gnome_vfs_get_file_info (uri,
2061 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2063 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2064 mime_part = tny_platform_factory_new_mime_part
2065 (modest_runtime_get_platform_factory ());
2066 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2068 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2070 g_object_unref (stream);
2072 content_id = g_strdup_printf ("%d", priv->last_cid);
2073 tny_mime_part_set_content_id (mime_part, content_id);
2074 g_free (content_id);
2077 basename = g_path_get_basename (filename);
2078 tny_mime_part_set_filename (mime_part, basename);
2081 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2082 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2084 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2085 gtk_widget_show_all (priv->attachments_caption);
2086 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2088 g_object_unref (mime_part);
2093 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2096 ModestMsgEditWindowPrivate *priv;
2099 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2100 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2102 if (att_list == NULL) {
2103 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2105 g_object_ref (att_list);
2108 if (tny_list_get_length (att_list) == 0) {
2109 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2111 GtkWidget *confirmation_dialog = NULL;
2112 gboolean dialog_response;
2113 gchar *message = NULL;
2114 gchar *filename = NULL;
2116 if (tny_list_get_length (att_list) == 1) {
2118 iter = tny_list_create_iterator (att_list);
2119 part = (TnyMimePart *) tny_iterator_get_current (iter);
2120 g_object_unref (iter);
2121 if (TNY_IS_MSG (part)) {
2122 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2124 filename = g_strdup (tny_header_get_subject (header));
2125 g_object_unref (header);
2127 if (filename == NULL) {
2128 filename = g_strdup (_("mail_va_no_subject"));
2131 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2133 g_object_unref (part);
2135 filename = g_strdup ("");
2137 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2138 (tny_list_get_length (att_list) == 1)), filename);
2140 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2142 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2143 gtk_widget_destroy (confirmation_dialog);
2144 if (!dialog_response) {
2145 g_object_unref (att_list);
2148 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2150 for (iter = tny_list_create_iterator (att_list);
2151 !tny_iterator_is_done (iter);
2152 tny_iterator_next (iter)) {
2153 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2154 const gchar *att_id;
2155 tny_list_remove (priv->attachments, (GObject *) mime_part);
2157 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2159 if (tny_list_get_length (priv->attachments) == 0)
2160 gtk_widget_hide (priv->attachments_caption);
2161 att_id = tny_mime_part_get_content_id (mime_part);
2163 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2165 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2166 g_object_unref (mime_part);
2170 g_object_unref (att_list);
2172 /* if the last attachment has been removed, focus the Subject: field */
2173 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2174 gtk_widget_grab_focus (priv->subject_field);
2178 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2181 ModestMsgEditWindowPrivate *priv;
2182 GdkColor *new_color;
2183 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2185 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2186 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2189 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2191 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2193 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2195 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2200 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2203 ModestMsgEditWindowPrivate *priv;
2204 gint new_size_index;
2205 ModestMsgEditWindow *window;
2208 window = MODEST_MSG_EDIT_WINDOW (userdata);
2209 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2210 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2212 if (gtk_check_menu_item_get_active (menu_item)) {
2214 WPTextBufferFormat format;
2216 memset (&format, 0, sizeof (format));
2217 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2219 label = gtk_bin_get_child (GTK_BIN (menu_item));
2221 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2222 format.cs.font_size = TRUE;
2223 format.cs.text_position = TRUE;
2224 format.cs.font = TRUE;
2225 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2226 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2228 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2229 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2230 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2232 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2233 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2234 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2240 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2243 ModestMsgEditWindowPrivate *priv;
2244 gint new_font_index;
2245 ModestMsgEditWindow *window;
2248 window = MODEST_MSG_EDIT_WINDOW (userdata);
2249 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2250 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2252 if (gtk_check_menu_item_get_active (menu_item)) {
2255 label = gtk_bin_get_child (GTK_BIN (menu_item));
2257 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2259 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2260 GINT_TO_POINTER(new_font_index)))
2261 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2263 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2264 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2265 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2271 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2273 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2274 ModestWindowPrivate *parent_priv;
2275 ModestWindowMgr *mgr;
2276 gboolean is_fullscreen;
2277 GtkAction *fs_toggle_action;
2280 mgr = modest_runtime_get_window_mgr ();
2281 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2283 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2285 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2286 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2287 if (is_fullscreen != active)
2288 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2296 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2299 ModestMsgEditWindowPrivate *priv = NULL;
2300 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2302 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2303 if (!priv->update_caption_visibility)
2306 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2308 gtk_widget_show (priv->cc_caption);
2310 gtk_widget_hide (priv->cc_caption);
2312 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2316 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2319 ModestMsgEditWindowPrivate *priv = NULL;
2320 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2322 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2323 if (!priv->update_caption_visibility)
2326 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2328 gtk_widget_show (priv->bcc_caption);
2330 gtk_widget_hide (priv->bcc_caption);
2332 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2336 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2337 ModestRecptEditor *editor)
2339 ModestMsgEditWindowPrivate *priv;
2341 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2342 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2343 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2345 if (editor == NULL) {
2346 GtkWidget *view_focus;
2347 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2349 /* This code should be kept in sync with ModestRecptEditor. The
2350 textview inside the recpt editor is the one that really gets the
2351 focus. As it's inside a scrolled window, and this one inside the
2352 hbox recpt editor inherits from, we'll need to go up in the
2353 hierarchy to know if the text view is part of the recpt editor
2354 or if it's a different text entry */
2356 if (gtk_widget_get_parent (view_focus)) {
2357 GtkWidget *first_parent;
2359 first_parent = gtk_widget_get_parent (view_focus);
2360 if (gtk_widget_get_parent (first_parent) &&
2361 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2362 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2367 editor = MODEST_RECPT_EDITOR (priv->to_field);
2371 modest_address_book_select_addresses (editor);
2376 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2378 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2380 modest_msg_edit_window_open_addressbook (window, NULL);
2384 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2385 gboolean show_toolbar)
2387 ModestWindowPrivate *parent_priv;
2388 const gchar *action_name;
2391 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2392 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2394 /* We can not just use the code of
2395 modest_msg_edit_window_setup_toolbar because it has a
2396 mixture of both initialization and creation code. */
2398 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2400 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2402 /* Update also the actions (to update the toggles in the
2403 menus), we have to do it manually because some other window
2404 of the same time could have changed it (remember that the
2405 toolbar fullscreen mode is shared by all the windows of the
2407 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2408 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2410 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2412 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2413 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2419 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2420 TnyHeaderFlags priority_flags)
2422 ModestMsgEditWindowPrivate *priv;
2423 ModestWindowPrivate *parent_priv;
2425 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2427 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2428 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2430 if (priv->priority_flags != priority_flags) {
2431 GtkAction *priority_action = NULL;
2433 priv->priority_flags = priority_flags;
2435 switch (priority_flags) {
2436 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2437 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2438 gtk_widget_show (priv->priority_icon);
2439 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2440 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2442 case TNY_HEADER_FLAG_LOW_PRIORITY:
2443 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2444 gtk_widget_show (priv->priority_icon);
2445 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2446 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2449 gtk_widget_hide (priv->priority_icon);
2450 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2451 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2454 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2455 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2460 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2463 ModestMsgEditWindowPrivate *priv;
2464 ModestWindowPrivate *parent_priv;
2465 gint current_format;
2467 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2469 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2470 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2472 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2473 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2475 if (current_format != file_format) {
2476 switch (file_format) {
2477 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2478 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2479 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2481 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2485 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2486 response = gtk_dialog_run (GTK_DIALOG (dialog));
2487 gtk_widget_destroy (dialog);
2488 if (response == GTK_RESPONSE_OK) {
2489 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2491 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2492 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2497 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2502 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2505 ModestMsgEditWindowPrivate *priv;
2506 WPTextBufferFormat oldfmt, fmt;
2507 gint old_position = 0;
2511 GdkColor *color = NULL;
2512 gboolean bold, bold_set, italic, italic_set;
2513 gboolean underline, underline_set;
2514 gboolean strikethrough, strikethrough_set;
2515 gboolean position_set;
2516 gboolean font_size_set, font_set, color_set;
2519 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2520 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2522 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2524 /* First we get the currently selected font information */
2525 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2527 switch (oldfmt.text_position) {
2528 case TEXT_POSITION_NORMAL:
2531 case TEXT_POSITION_SUPERSCRIPT:
2539 g_object_set (G_OBJECT (dialog),
2540 "bold", oldfmt.bold != FALSE,
2541 "bold-set", !oldfmt.cs.bold,
2542 "underline", oldfmt.underline != FALSE,
2543 "underline-set", !oldfmt.cs.underline,
2544 "italic", oldfmt.italic != FALSE,
2545 "italic-set", !oldfmt.cs.italic,
2546 "strikethrough", oldfmt.strikethrough != FALSE,
2547 "strikethrough-set", !oldfmt.cs.strikethrough,
2548 "color", &oldfmt.color,
2549 "color-set", !oldfmt.cs.color,
2550 "size", wp_font_size[oldfmt.font_size],
2551 "size-set", !oldfmt.cs.font_size,
2552 "position", old_position,
2553 "position-set", !oldfmt.cs.text_position,
2554 "family", wp_get_font_name (oldfmt.font),
2555 "family-set", !oldfmt.cs.font,
2558 gtk_widget_show_all (dialog);
2559 response = gtk_dialog_run (GTK_DIALOG (dialog));
2560 if (response == GTK_RESPONSE_OK) {
2562 g_object_get( dialog,
2564 "bold-set", &bold_set,
2565 "underline", &underline,
2566 "underline-set", &underline_set,
2568 "italic-set", &italic_set,
2569 "strikethrough", &strikethrough,
2570 "strikethrough-set", &strikethrough_set,
2572 "color-set", &color_set,
2574 "size-set", &font_size_set,
2575 "family", &font_name,
2576 "family-set", &font_set,
2577 "position", &position,
2578 "position-set", &position_set,
2583 if (response == GTK_RESPONSE_OK) {
2584 memset(&fmt, 0, sizeof(fmt));
2590 fmt.italic = italic;
2591 fmt.cs.italic = TRUE;
2593 if (underline_set) {
2594 fmt.underline = underline;
2595 fmt.cs.underline = TRUE;
2597 if (strikethrough_set) {
2598 fmt.strikethrough = strikethrough;
2599 fmt.cs.strikethrough = TRUE;
2604 ? TEXT_POSITION_NORMAL
2605 : ( ( position == 1 )
2606 ? TEXT_POSITION_SUPERSCRIPT
2607 : TEXT_POSITION_SUBSCRIPT );
2608 fmt.cs.text_position = TRUE;
2609 fmt.font_size = oldfmt.font_size;
2613 fmt.cs.color = TRUE;
2616 fmt.font = wp_get_font_index(font_name,
2621 if (font_size_set) {
2622 fmt.cs.font_size = TRUE;
2623 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2625 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2626 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2628 gtk_widget_destroy (dialog);
2630 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2634 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2636 ModestMsgEditWindowPrivate *priv;
2638 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2639 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2641 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2643 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2648 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2650 ModestMsgEditWindowPrivate *priv;
2652 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2653 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2655 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2657 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2662 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2664 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2666 priv->can_undo = can_undo;
2670 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2672 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2674 priv->can_redo = can_redo;
2678 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2680 ModestMsgEditWindowPrivate *priv;
2681 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2682 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2684 return priv->can_undo;
2688 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2690 ModestMsgEditWindowPrivate *priv;
2691 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2692 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2694 return priv->can_redo;
2699 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2702 GtkTextIter match_start, match_end;
2704 if (image_id == NULL)
2707 gtk_text_buffer_get_start_iter (buffer, &iter);
2709 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2710 GSList *tags = gtk_text_iter_get_tags (&match_start);
2712 for (node = tags; node != NULL; node = g_slist_next (node)) {
2713 GtkTextTag *tag = (GtkTextTag *) node->data;
2714 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2715 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2716 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2718 offset = gtk_text_iter_get_offset (&match_start);
2719 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2720 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2724 gtk_text_iter_forward_char (&iter);
2729 message_is_empty (ModestMsgEditWindow *window)
2731 ModestMsgEditWindowPrivate *priv = NULL;
2733 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2734 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2736 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2737 * so we can ignore markup.
2739 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2742 count = gtk_text_buffer_get_char_count (buf);
2748 msg_body_focus (GtkWidget *focus,
2749 GdkEventFocus *event,
2753 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (userdata));
2758 recpt_field_changed (GtkTextBuffer *buffer,
2759 ModestMsgEditWindow *editor)
2761 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (editor));
2765 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2767 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (editor));
2771 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2773 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2774 GtkTextBuffer *buffer;
2776 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2777 gtk_text_buffer_set_modified (buffer, FALSE);
2778 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2779 gtk_text_buffer_set_modified (buffer, FALSE);
2780 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2781 gtk_text_buffer_set_modified (buffer, FALSE);
2782 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2786 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2788 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2789 GtkTextBuffer *buffer;
2791 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2792 if (gtk_text_buffer_get_modified (buffer))
2794 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2795 if (gtk_text_buffer_get_modified (buffer))
2797 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2798 if (gtk_text_buffer_get_modified (buffer))
2800 if (gtk_text_buffer_get_modified (priv->text_buffer))
2810 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2812 ModestMsgEditWindowPrivate *priv = NULL;
2814 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2815 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2817 /* check if there's no recipient added */
2818 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2819 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2820 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2821 /* no recipient contents, then select contacts */
2822 modest_msg_edit_window_open_addressbook (window, NULL);
2826 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2827 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2830 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2831 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2834 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2835 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2839 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2840 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2841 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2848 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2849 ModestMsgEditWindow *window)
2851 modest_msg_edit_window_offer_attach_file (window);
2855 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2857 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2859 return priv->clipboard_text;
2863 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2865 ModestMsgEditWindow *window)
2867 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2868 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2870 if (!GTK_WIDGET_VISIBLE (window))
2873 text = gtk_clipboard_wait_for_text (selection_clipboard);
2875 if (priv->clipboard_text != NULL) {
2876 g_free (priv->clipboard_text);
2878 priv->clipboard_text = text;
2880 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2883 subject_field_move_cursor (GtkEntry *entry,
2884 GtkMovementStep step,
2889 if (!GTK_WIDGET_VISIBLE (window))
2892 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2896 update_window_title (ModestMsgEditWindow *window)
2898 ModestMsgEditWindowPrivate *priv = NULL;
2899 const gchar *subject;
2901 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2902 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2903 if (subject == NULL || subject[0] == '\0')
2904 subject = _("mail_va_new_email");
2906 gtk_window_set_title (GTK_WINDOW (window), subject);
2911 subject_field_changed (GtkEditable *editable,
2912 ModestMsgEditWindow *window)
2914 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2915 update_window_title (window);
2916 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2917 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2921 subject_field_insert_text (GtkEditable *editable,
2923 gint new_text_length,
2925 ModestMsgEditWindow *window)
2927 GString *result = g_string_new ("");
2929 gint result_len = 0;
2930 const gchar *entry_text = NULL;
2933 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2934 old_length = g_utf8_strlen (entry_text, -1);
2936 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2937 gunichar c = g_utf8_get_char_validated (current, 8);
2938 /* Invalid unichar, stop */
2944 result = g_string_append_unichar (result, c);
2948 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2949 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2952 /* Prevent endless recursion */
2953 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2954 g_signal_emit_by_name (editable, "insert-text",
2955 (gpointer) result->str, (gpointer) result->len,
2956 (gpointer) position, (gpointer) window);
2957 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2961 if (result_len + old_length > 1000) {
2962 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2963 dgettext("hildon-common-strings",
2964 "ckdg_ib_maximum_characters_reached"));
2967 g_string_free (result, TRUE);
2971 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2974 ModestMsgEditWindowPrivate *priv = NULL;
2976 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2977 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2979 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2982 gtk_widget_show_all (priv->find_toolbar);
2983 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2985 gtk_widget_hide_all (priv->find_toolbar);
2986 gtk_widget_grab_focus (priv->msg_body);
2992 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2994 GtkTextIter *match_start,
2995 GtkTextIter *match_end)
2997 GtkTextIter end_iter;
2998 gchar *str_casefold;
3001 gchar *range_casefold;
3004 gboolean result = FALSE;
3011 gtk_text_iter_forward_to_end (&end_iter);
3013 str_casefold = g_utf8_casefold (str, -1);
3014 str_chars_n = strlen (str);
3016 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3017 range_casefold = g_utf8_casefold (range_text, -1);
3018 range_chars_n = strlen (range_casefold);
3020 if (range_chars_n < str_chars_n) {
3021 g_free (str_casefold);
3022 g_free (range_text);
3023 g_free (range_casefold);
3027 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3028 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3029 if (!g_utf8_collate (range_subtext, str_casefold)) {
3030 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3032 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3033 match_start, match_end, NULL);
3034 g_free (found_text);
3036 g_free (range_subtext);
3040 g_free (str_casefold);
3041 g_free (range_text);
3042 g_free (range_casefold);
3049 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3050 ModestMsgEditWindow *window)
3052 gchar *current_search = NULL;
3053 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3055 GtkTextIter selection_start, selection_end;
3056 GtkTextIter match_start, match_end;
3057 gboolean continue_search = FALSE;
3059 if (message_is_empty (window)) {
3060 g_free (priv->last_search);
3061 priv->last_search = NULL;
3062 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3066 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3067 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3068 g_free (current_search);
3069 g_free (priv->last_search);
3070 priv->last_search = NULL;
3071 /* Information banner about empty search */
3072 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3076 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3077 continue_search = TRUE;
3079 g_free (priv->last_search);
3080 priv->last_search = g_strdup (current_search);
3083 if (continue_search) {
3084 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3085 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3086 &match_start, &match_end);
3088 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3090 GtkTextIter buffer_start;
3091 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3092 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3093 &match_start, &match_end);
3095 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3098 /* Mark as selected the string found in search */
3100 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3101 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3103 g_free (priv->last_search);
3104 priv->last_search = NULL;
3106 g_free (current_search);
3110 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3111 ModestMsgEditWindow *window)
3113 GtkToggleAction *toggle;
3114 ModestWindowPrivate *parent_priv;
3115 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3117 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3118 gtk_toggle_action_set_active (toggle, FALSE);
3122 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3124 ModestMsgEditWindowPrivate *priv;
3126 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3131 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3134 ModestMsgEditWindowPrivate *priv;
3136 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3142 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3145 ModestMsgEditWindowPrivate *priv;
3146 TnyHeader *header = NULL;
3148 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3149 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3151 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3152 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3154 if (priv->draft_msg != NULL) {
3155 g_object_unref (priv->draft_msg);
3158 if (draft != NULL) {
3159 g_object_ref (draft);
3160 header = tny_msg_get_header (draft);
3161 if (priv->msg_uid) {
3162 g_free (priv->msg_uid);
3163 priv->msg_uid = NULL;
3165 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3166 if (GTK_WIDGET_REALIZED (window))
3167 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3170 priv->draft_msg = draft;
3174 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3175 GtkTextIter *start, GtkTextIter *end,
3178 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3179 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3182 if (tag == NULL+13) return;
3183 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3184 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3185 replace_with_images (window, priv->images);
3190 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3193 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3195 g_return_if_fail (TNY_IS_MIME_PART (part));
3196 tny_list_prepend (priv->attachments, (GObject *) part);
3197 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3198 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3199 gtk_widget_show_all (priv->attachments_caption);
3200 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3204 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3206 ModestMsgEditWindowPrivate *priv;
3208 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3209 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3211 return priv->msg_uid;
3215 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3216 ModestMsgEditWindowWidgetType widget_type)
3218 ModestMsgEditWindowPrivate *priv;
3220 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3221 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3223 switch (widget_type) {
3224 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3225 return priv->msg_body;
3227 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3228 return priv->to_field;
3230 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3231 return priv->cc_field;
3233 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3234 return priv->bcc_field;
3236 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3237 return priv->subject_field;
3239 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3240 return priv->attachments_view;
3248 remove_tags (WPTextBuffer *buffer)
3250 GtkTextIter start, end;
3252 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3253 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3255 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3259 on_account_removed (TnyAccountStore *account_store,
3260 TnyAccount *account,
3263 /* Do nothing if it's a store account, because we use the
3264 transport to send the messages */
3265 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3266 const gchar *parent_acc = NULL;
3267 const gchar *our_acc = NULL;
3269 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3270 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3271 /* Close this window if I'm showing a message of the removed account */
3272 if (strcmp (parent_acc, our_acc) == 0)
3273 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3278 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3280 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3282 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3288 set_zoom_do_nothing (ModestWindow *window,
3294 get_zoom_do_nothing (ModestWindow *window)