1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include <modest-utils.h>
79 #include "modest-maemo-utils.h"
82 #define DEFAULT_FONT_SIZE 3
83 #define DEFAULT_FONT 2
84 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
85 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
86 #define DEFAULT_MAIN_VBOX_SPACING 6
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #define DEFAULT_FONT_SCALE 1.5
91 static gboolean is_wp_text_buffer_started = FALSE;
93 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
94 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
95 static void modest_msg_edit_window_finalize (GObject *obj);
97 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
98 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
99 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
101 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
102 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
103 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
104 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
105 GtkTextIter *start, GtkTextIter *end,
107 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
108 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
109 static void subject_field_insert_text (GtkEditable *editable,
111 gint new_text_length,
113 ModestMsgEditWindow *window);
114 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
116 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
118 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
120 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
121 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
122 GdkEventWindowState *event,
124 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
125 ModestRecptEditor *editor);
126 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
127 ModestMsgEditWindow *window);
129 /* ModestWindow methods implementation */
130 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
131 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
132 gboolean show_toolbar);
133 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
135 ModestMsgEditWindow *window);
136 static void subject_field_move_cursor (GtkEntry *entry,
137 GtkMovementStep step,
141 static void update_window_title (ModestMsgEditWindow *window);
144 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
145 ModestMsgEditWindow *window);
146 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
147 ModestMsgEditWindow *window);
148 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
150 GtkTextIter *match_start,
151 GtkTextIter *match_end);
153 static void remove_tags (WPTextBuffer *buffer);
155 static void on_account_removed (TnyAccountStore *account_store,
159 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
161 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
163 static gdouble get_zoom_do_nothing (ModestWindow *window);
165 static void init_window (ModestMsgEditWindow *obj);
167 static void DEBUG_BUFFER (WPTextBuffer *buffer)
171 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
173 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
174 while (!gtk_text_iter_is_end (&iter)) {
175 GString *output = g_string_new ("");
176 GSList *toggled_tags;
179 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
180 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
181 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
182 GtkTextTag *tag = (GtkTextTag *) node->data;
184 g_object_get (G_OBJECT (tag), "name", &name, NULL);
185 output = g_string_append (output, name);
186 g_string_append (output, " ");
188 output = g_string_append (output, "] OPENED [ ");
189 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
190 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
191 GtkTextTag *tag = (GtkTextTag *) node->data;
193 g_object_get (G_OBJECT (tag), "name", &name, NULL);
194 output = g_string_append (output, name);
195 g_string_append (output, " ");
197 output = g_string_append (output, "]\n");
198 g_message ("%s", output->str);
199 g_string_free (output, TRUE);
200 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
202 g_message ("END BUFFER");
207 /* static gboolean */
208 /* on_key_pressed (GtkWidget *self, */
209 /* GdkEventKey *event, */
210 /* gpointer user_data); */
212 /* list my signals */
219 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
220 struct _ModestMsgEditWindowPrivate {
222 GtkWidget *header_box;
224 ModestPairList *from_field_protos;
225 GtkWidget *from_field;
229 GtkWidget *bcc_field;
230 GtkWidget *subject_field;
231 GtkWidget *attachments_view;
232 GtkWidget *priority_icon;
233 GtkWidget *add_attachment_button;
235 GtkWidget *cc_caption;
236 GtkWidget *bcc_caption;
237 gboolean update_caption_visibility;
238 GtkWidget *attachments_caption;
240 GtkTextBuffer *text_buffer;
242 GtkWidget *font_size_toolitem;
243 GtkWidget *font_face_toolitem;
244 GtkWidget *font_color_button;
245 GSList *font_items_group;
246 GtkWidget *font_tool_button_label;
247 GSList *size_items_group;
248 GtkWidget *size_tool_button_label;
250 GtkWidget *find_toolbar;
254 GtkWidget *scroll_area;
255 gint last_vadj_upper;
258 TnyList *attachments;
261 TnyHeaderFlags priority_flags;
263 gboolean can_undo, can_redo;
264 gulong clipboard_change_handler_id;
265 gulong default_clipboard_change_handler_id;
266 gulong account_removed_handler_id;
267 gchar *clipboard_text;
276 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
277 MODEST_TYPE_MSG_EDIT_WINDOW, \
278 ModestMsgEditWindowPrivate))
280 static GtkWindowClass *parent_class = NULL;
282 /* uncomment the following if you have defined any signals */
283 /* static guint signals[LAST_SIGNAL] = {0}; */
286 modest_msg_edit_window_get_type (void)
288 static GType my_type = 0;
290 static const GTypeInfo my_info = {
291 sizeof(ModestMsgEditWindowClass),
292 NULL, /* base init */
293 NULL, /* base finalize */
294 (GClassInitFunc) modest_msg_edit_window_class_init,
295 NULL, /* class finalize */
296 NULL, /* class data */
297 sizeof(ModestMsgEditWindow),
299 (GInstanceInitFunc) modest_msg_edit_window_init,
302 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
303 "ModestMsgEditWindow",
311 save_state (ModestWindow *self)
313 modest_widget_memory_save (modest_runtime_get_conf(),
314 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
319 restore_settings (ModestMsgEditWindow *self)
321 ModestConf *conf = NULL;
323 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
325 conf = modest_runtime_get_conf ();
326 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
327 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
328 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
329 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
330 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
331 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
332 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
333 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
335 /* set initial state of cc and bcc */
336 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
337 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
338 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
339 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
340 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
341 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
343 /* Dim at start clipboard actions */
344 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
345 gtk_action_set_sensitive (action, FALSE);
346 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
347 gtk_action_set_sensitive (action, FALSE);
348 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
349 gtk_action_set_sensitive (action, FALSE);
351 modest_widget_memory_restore (conf,
352 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
357 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
359 GObjectClass *gobject_class;
360 ModestWindowClass *modest_window_class;
361 gobject_class = (GObjectClass*) klass;
362 modest_window_class = (ModestWindowClass*) klass;
364 parent_class = g_type_class_peek_parent (klass);
365 gobject_class->finalize = modest_msg_edit_window_finalize;
367 modest_window_class->set_zoom_func = set_zoom_do_nothing;
368 modest_window_class->get_zoom_func = get_zoom_do_nothing;
369 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
370 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
371 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
372 modest_window_class->save_state_func = save_state;
373 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
375 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
379 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
381 ModestMsgEditWindowPrivate *priv;
382 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
384 priv->msg_body = NULL;
385 priv->from_field = NULL;
386 priv->to_field = NULL;
387 priv->cc_field = NULL;
388 priv->bcc_field = NULL;
389 priv->subject_field = NULL;
390 priv->attachments = TNY_LIST (tny_simple_list_new ());
391 priv->images = TNY_LIST (tny_simple_list_new ());
394 priv->cc_caption = NULL;
395 priv->bcc_caption = NULL;
396 priv->update_caption_visibility = FALSE;
398 priv->priority_flags = 0;
400 priv->find_toolbar = NULL;
401 priv->last_search = NULL;
403 priv->draft_msg = NULL;
404 priv->outbox_msg = NULL;
405 priv->msg_uid = NULL;
407 priv->can_undo = FALSE;
408 priv->can_redo = FALSE;
409 priv->clipboard_change_handler_id = 0;
410 priv->default_clipboard_change_handler_id = 0;
411 priv->account_removed_handler_id = 0;
412 priv->clipboard_text = NULL;
415 priv->last_vadj_upper = 0;
417 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
418 GTK_WINDOW(obj),"applications_email_editor");
420 if (!is_wp_text_buffer_started) {
421 is_wp_text_buffer_started = TRUE;
422 wp_text_buffer_library_init ();
427 hildon_program_add_window (hildon_program_get_instance(),
432 /* FIXME: this is a dup from the one in gtk/ */
435 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
437 static ModestPairList*
438 get_transports (void)
440 GSList *transports = NULL;
442 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
443 GSList *accounts = modest_account_mgr_account_names (account_mgr,
444 TRUE /* only enabled accounts. */);
446 GSList *cursor = accounts;
448 gchar *account_name = cursor->data;
449 gchar *from_string = NULL;
451 from_string = modest_account_mgr_get_from_string (account_mgr,
455 if (from_string && account_name) {
456 gchar *name = account_name;
457 ModestPair *pair = modest_pair_new ((gpointer) name,
458 (gpointer) from_string , TRUE);
459 transports = g_slist_prepend (transports, pair);
462 cursor = cursor->next;
464 g_slist_free (accounts); /* only free the accounts, not the elements,
465 * because they are used in the pairlist */
469 void vadj_changed (GtkAdjustment *adj,
470 ModestMsgEditWindow *window)
472 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
474 GdkRectangle rectangle, cursor_rectangle;
475 GtkTextIter position;
479 /* We detect if cursor is visible using the full height, not only the center. This
481 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
482 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
484 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
485 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
487 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
488 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
490 if (gtk_widget_is_focus (priv->msg_body) &&
492 if (priv->last_vadj_upper != adj->upper) {
495 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
496 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
497 insert, 0.1, FALSE, 0.0, 0.0);
500 priv->last_vadj_upper = adj->upper;
503 static void window_focus (GtkWindow *window,
507 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
512 connect_signals (ModestMsgEditWindow *obj)
514 ModestMsgEditWindowPrivate *priv;
516 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
518 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
519 G_CALLBACK (text_buffer_refresh_attributes), obj);
520 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
521 G_CALLBACK (text_buffer_can_undo), obj);
522 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
523 G_CALLBACK (text_buffer_can_redo), obj);
524 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
525 G_CALLBACK (body_changed), obj);
526 g_signal_connect (G_OBJECT (obj), "window-state-event",
527 G_CALLBACK (modest_msg_edit_window_window_state_event),
529 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
530 G_CALLBACK (text_buffer_apply_tag), obj);
531 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
532 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
533 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
534 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
535 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
536 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
538 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
539 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
541 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
542 G_CALLBACK (msg_body_focus), obj);
543 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
544 G_CALLBACK (msg_body_focus), obj);
545 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
546 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
547 "changed", G_CALLBACK (recpt_field_changed), obj);
548 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
549 "changed", G_CALLBACK (recpt_field_changed), obj);
550 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
551 "changed", G_CALLBACK (recpt_field_changed), obj);
552 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
553 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
554 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
556 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
557 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
559 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
561 G_CALLBACK (vadj_changed),
564 priv->clipboard_change_handler_id =
565 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
566 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
567 priv->default_clipboard_change_handler_id =
568 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
569 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
574 init_window (ModestMsgEditWindow *obj)
576 GtkWidget *from_caption, *to_caption, *subject_caption;
577 GtkWidget *main_vbox;
578 ModestMsgEditWindowPrivate *priv;
579 GtkActionGroup *action_group;
580 ModestWindowPrivate *parent_priv;
581 GdkPixbuf *window_icon = NULL;
582 GError *error = NULL;
584 GtkSizeGroup *size_group;
586 GtkWidget *subject_box;
587 GtkWidget *attachment_icon;
588 GtkWidget *window_box;
589 #if (GTK_MINOR_VERSION >= 10)
590 GdkAtom deserialize_type;
592 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
593 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
595 parent_priv->ui_manager = gtk_ui_manager_new();
596 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
597 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
599 /* Add common actions */
600 gtk_action_group_add_actions (action_group,
601 modest_msg_edit_action_entries,
602 G_N_ELEMENTS (modest_msg_edit_action_entries),
604 gtk_action_group_add_toggle_actions (action_group,
605 modest_msg_edit_toggle_action_entries,
606 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
608 gtk_action_group_add_radio_actions (action_group,
609 modest_msg_edit_alignment_radio_action_entries,
610 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
612 G_CALLBACK (modest_ui_actions_on_change_justify),
614 gtk_action_group_add_radio_actions (action_group,
615 modest_msg_edit_priority_action_entries,
616 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
618 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
620 gtk_action_group_add_radio_actions (action_group,
621 modest_msg_edit_file_format_action_entries,
622 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
623 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
624 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
626 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
627 g_object_unref (action_group);
629 /* Load the UI definition */
630 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
633 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
634 g_clear_error (&error);
637 /* Add accelerators */
638 gtk_window_add_accel_group (GTK_WINDOW (obj),
639 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
641 parent_priv->menubar = NULL;
643 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
645 /* Note: This ModestPairList* must exist for as long as the combo
646 * that uses it, because the ModestComboBox uses the ID opaquely,
647 * so it can't know how to manage its memory. */
648 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
650 priv->to_field = modest_recpt_editor_new ();
651 priv->cc_field = modest_recpt_editor_new ();
652 priv->bcc_field = modest_recpt_editor_new ();
653 subject_box = gtk_hbox_new (FALSE, 0);
654 priv->priority_icon = gtk_image_new ();
655 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
656 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
657 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
658 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
659 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
660 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
661 priv->add_attachment_button = gtk_button_new ();
662 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
663 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
664 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
665 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
666 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
667 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
668 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
669 priv->attachments_view = modest_attachments_view_new (NULL);
671 priv->header_box = gtk_vbox_new (FALSE, 0);
673 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
674 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
675 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
676 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
677 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
678 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
679 g_object_unref (size_group);
681 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
682 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
683 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
684 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
685 gtk_size_group_add_widget (size_group, priv->subject_field);
686 gtk_size_group_add_widget (size_group, priv->attachments_view);
687 g_object_unref (size_group);
689 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
690 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
691 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
692 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
694 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
695 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
698 priv->msg_body = wp_text_view_new ();
699 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
700 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
701 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
702 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
703 #if (GTK_MINOR_VERSION >= 10)
704 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
705 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
707 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
708 deserialize_type, TRUE);
710 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
712 priv->find_toolbar = hildon_find_toolbar_new (NULL);
713 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
715 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
717 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
718 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
719 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
720 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
722 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
724 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
725 frame = gtk_frame_new (NULL);
726 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
728 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
729 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
730 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
732 G_CALLBACK (vadj_changed),
734 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
736 window_box = gtk_vbox_new (FALSE, 0);
737 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
738 gtk_container_add (GTK_CONTAINER(obj), window_box);
739 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
740 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
742 /* Set window icon */
743 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
745 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
746 g_object_unref (window_icon);
751 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
753 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
755 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
756 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
757 priv->clipboard_change_handler_id))
758 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
759 priv->clipboard_change_handler_id);
760 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
761 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
762 priv->default_clipboard_change_handler_id))
763 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
764 priv->default_clipboard_change_handler_id);
766 if (priv->account_removed_handler_id &&
767 g_signal_handler_is_connected (modest_runtime_get_account_store (),
768 priv->account_removed_handler_id))
769 g_signal_handler_disconnect(modest_runtime_get_account_store (),
770 priv->account_removed_handler_id);
774 modest_msg_edit_window_finalize (GObject *obj)
776 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
778 /* Sanity check: shouldn't be needed, the window mgr should
779 call this function before */
780 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
782 if (priv->clipboard_text != NULL) {
783 g_free (priv->clipboard_text);
784 priv->clipboard_text = NULL;
787 if (priv->draft_msg != NULL) {
788 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
789 if (TNY_IS_HEADER (header)) {
790 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
791 modest_window_mgr_unregister_header (mgr, header);
793 g_object_unref (priv->draft_msg);
794 priv->draft_msg = NULL;
796 if (priv->outbox_msg != NULL) {
797 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
798 if (TNY_IS_HEADER (header)) {
799 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
800 modest_window_mgr_unregister_header (mgr, header);
802 g_object_unref (priv->outbox_msg);
803 priv->outbox_msg = NULL;
805 g_free (priv->msg_uid);
806 g_free (priv->last_search);
807 g_slist_free (priv->font_items_group);
808 g_slist_free (priv->size_items_group);
809 g_object_unref (priv->attachments);
810 g_object_unref (priv->images);
812 /* This had to stay alive for as long as the combobox that used it: */
813 modest_pair_list_free (priv->from_field_protos);
815 G_OBJECT_CLASS(parent_class)->finalize (obj);
819 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
821 GdkPixbufLoader *loader;
824 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
829 tny_stream_reset (TNY_STREAM (stream));
830 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
831 unsigned char read_buffer[128];
833 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
834 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
838 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
839 g_object_ref (pixbuf);
840 gdk_pixbuf_loader_close (loader, NULL);
841 g_object_unref (loader);
843 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
844 GdkPixbuf *new_pixbuf;
846 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
847 gdk_pixbuf_get_width (pixbuf);
848 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
849 g_object_unref (pixbuf);
857 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
859 ModestMsgEditWindowPrivate *priv;
862 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
864 for (iter = tny_list_create_iterator (attachments);
865 !tny_iterator_is_done (iter);
866 tny_iterator_next (iter)) {
867 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
868 const gchar *cid = tny_mime_part_get_content_id (part);
869 const gchar *mime_type = tny_mime_part_get_content_type (part);
870 if ((cid != NULL)&&(mime_type != NULL)) {
871 TnyStream *stream = tny_mime_part_get_stream (part);
872 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
873 g_object_unref (stream);
875 if (pixbuf != NULL) {
876 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
877 g_object_unref (pixbuf);
880 g_object_unref (part);
885 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
887 TnyMimePart *parent = NULL;
888 const gchar *content_type = NULL;
889 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
891 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
893 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
894 parent = g_object_ref (msg);
895 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
896 TnyList *parts = TNY_LIST (tny_simple_list_new ());
899 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
900 iter = tny_list_create_iterator (parts);
901 while (!tny_iterator_is_done (iter)) {
903 part = TNY_MIME_PART (tny_iterator_get_current (iter));
904 content_type = tny_mime_part_get_content_type (part);
905 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
909 g_object_unref (part);
911 tny_iterator_next (iter);
913 g_object_unref (iter);
914 g_object_unref (parts);
917 if (parent != NULL) {
918 TnyList *parts = TNY_LIST (tny_simple_list_new ());
921 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
922 iter = tny_list_create_iterator (parts);
923 while (!tny_iterator_is_done (iter)) {
925 part = TNY_MIME_PART (tny_iterator_get_current (iter));
926 content_type = tny_mime_part_get_content_type (part);
927 if (content_type && g_str_has_prefix (content_type, "image/")) {
928 tny_list_prepend (priv->images, (GObject *) part);
930 g_object_unref (part);
931 tny_iterator_next (iter);
933 g_object_unref (iter);
934 g_object_unref (parts);
935 g_object_unref (parent);
940 update_last_cid (ModestMsgEditWindow *self, TnyList *attachments)
943 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
945 for (iter = tny_list_create_iterator (attachments) ;
946 !tny_iterator_is_done (iter);
947 tny_iterator_next (iter)) {
948 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
949 const gchar *cid = tny_mime_part_get_content_id (part);
951 char *invalid = NULL;
952 gint int_cid = strtol (cid, &invalid, 10);
953 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
954 priv->last_cid = int_cid;
957 g_object_unref (part);
962 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
965 const gchar *to, *cc, *bcc, *subject;
967 ModestMsgEditWindowPrivate *priv;
969 TnyHeaderFlags priority_flags;
970 TnyFolder *msg_folder;
971 gboolean is_html = FALSE;
973 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
974 g_return_if_fail (TNY_IS_MSG (msg));
976 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
978 header = tny_msg_get_header (msg);
979 to = tny_header_get_to (header);
980 cc = tny_header_get_cc (header);
981 bcc = tny_header_get_bcc (header);
982 subject = tny_header_get_subject (header);
983 priority_flags = tny_header_get_priority (header);
986 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
988 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
989 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
990 gtk_widget_show (priv->cc_caption);
991 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
992 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
993 gtk_widget_hide (priv->cc_caption);
996 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
997 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
998 gtk_widget_show (priv->bcc_caption);
999 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1000 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1001 gtk_widget_hide (priv->bcc_caption);
1004 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1005 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1008 update_window_title (self);
1010 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1011 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1013 if ((body == NULL)||(body[0] == '\0')) {
1015 body = modest_text_utils_convert_to_html ("");
1018 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1019 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1022 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1025 /* Add attachments to the view */
1026 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1027 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1028 if (tny_list_get_length (priv->attachments) == 0) {
1029 gtk_widget_hide (priv->attachments_caption);
1031 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1032 gtk_widget_show_all (priv->attachments_caption);
1034 get_related_images (self, msg);
1035 update_last_cid (self, priv->attachments);
1036 update_last_cid (self, priv->images);
1037 replace_with_images (self, priv->images);
1039 if (preserve_is_rich && !is_html) {
1040 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1041 /* Get the default format required from configuration */
1042 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1043 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1046 /* Set the default focus depending on having already a To: field or not */
1047 if ((!to)||(*to == '\0')) {
1048 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1050 gtk_widget_grab_focus (priv->msg_body);
1053 /* TODO: lower priority, select in the From: combo to the
1054 value that comes from msg <- not sure, should it be
1057 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1059 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1060 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1062 modest_msg_edit_window_reset_modified (self);
1064 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1065 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1066 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1067 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1069 if (priv->msg_uid) {
1070 g_free (priv->msg_uid);
1071 priv->msg_uid = NULL;
1074 /* we should set a reference to the incoming message if it is a draft */
1075 msg_folder = tny_msg_get_folder (msg);
1077 if (modest_tny_folder_is_local_folder (msg_folder)) {
1078 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1079 if (type == TNY_FOLDER_TYPE_INVALID)
1080 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1082 if (type == TNY_FOLDER_TYPE_DRAFTS)
1083 priv->draft_msg = g_object_ref(msg);
1084 if (type == TNY_FOLDER_TYPE_OUTBOX)
1085 priv->outbox_msg = g_object_ref(msg);
1086 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1088 g_object_unref (msg_folder);
1093 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1096 GList *item_children, *node;
1097 GtkWidget *bin_child;
1099 bin_child = gtk_bin_get_child (GTK_BIN(item));
1101 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1103 for (node = item_children; node != NULL; node = g_list_next (node)) {
1104 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1105 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1108 g_list_free (item_children);
1112 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1115 GList *item_children, *node;
1117 box = gtk_bin_get_child (GTK_BIN (item));
1118 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1119 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1121 for (node = item_children; node != NULL; node = g_list_next (node)) {
1122 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1123 if (GTK_IS_TOGGLE_BUTTON (node->data))
1124 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1125 else if (GTK_IS_BUTTON (node->data))
1126 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1128 g_list_free (item_children);
1133 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1135 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1136 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1137 GtkWidget *placeholder;
1138 GtkWidget *tool_item;
1143 GtkWidget *sizes_menu;
1144 GtkWidget *fonts_menu;
1145 GSList *radio_group = NULL;
1146 GSList *node = NULL;
1150 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1151 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1153 /* Font color placeholder */
1154 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1155 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1158 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1159 priv->font_color_button = hildon_color_button_new ();
1160 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1161 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1162 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1163 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1164 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1165 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1166 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1168 G_CALLBACK (modest_msg_edit_window_color_button_change),
1171 /* Font size and face placeholder */
1172 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1173 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1175 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1176 priv->size_tool_button_label = gtk_label_new (NULL);
1177 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1178 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1179 size_text,"</span>", NULL);
1180 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1182 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1183 sizes_menu = gtk_menu_new ();
1184 priv->size_items_group = NULL;
1186 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1187 GtkWidget *size_menu_item;
1189 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1190 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1191 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1192 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1193 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1194 gtk_widget_show (size_menu_item);
1196 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1200 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1201 GtkWidget *item = (GtkWidget *) node->data;
1202 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1206 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1207 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1208 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1209 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1210 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1211 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1212 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1213 priv->font_size_toolitem = tool_item;
1216 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1217 priv->font_tool_button_label = gtk_label_new (NULL);
1218 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1219 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1221 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1222 fonts_menu = gtk_menu_new ();
1223 priv->font_items_group = NULL;
1225 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1226 GtkWidget *font_menu_item;
1227 GtkWidget *child_label;
1229 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1230 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1231 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1232 wp_get_font_name (font_index), "</span>", NULL);
1233 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1236 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1237 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1238 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1239 gtk_widget_show (font_menu_item);
1241 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1244 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1245 GtkWidget *item = (GtkWidget *) node->data;
1246 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1249 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1250 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1251 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1252 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1253 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1254 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1255 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1256 priv->font_face_toolitem = tool_item;
1258 /* Set expand and homogeneous for remaining items */
1259 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1260 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1261 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1262 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1263 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1264 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1265 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1266 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1267 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1269 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1270 will not show the tool items added to the placeholders) */
1271 gtk_widget_show_all (parent_priv->toolbar);
1273 /* Set the no show all *after* showing all items. We do not
1274 want the toolbar to be shown with a show all because it
1275 could go agains the gconf setting regarding showing or not
1276 the toolbar of the editor window */
1277 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1283 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1286 ModestWindowPrivate *parent_priv;
1287 ModestMsgEditWindowPrivate *priv;
1288 ModestPair *account_pair = NULL;
1289 ModestDimmingRulesGroup *menu_rules_group = NULL;
1290 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1291 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1292 ModestWindowMgr *mgr = NULL;
1294 g_return_val_if_fail (msg, NULL);
1295 g_return_val_if_fail (account_name, NULL);
1297 mgr = modest_runtime_get_window_mgr ();
1299 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1301 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1302 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1304 /* Menubar. Update the state of some toggles */
1305 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1306 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1307 priv->from_field_protos = get_transports ();
1308 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1309 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1310 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1313 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1315 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1317 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1319 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1320 if (account_pair != NULL)
1321 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1323 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1324 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1325 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1326 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1327 /* Add common dimming rules */
1328 modest_dimming_rules_group_add_rules (menu_rules_group,
1329 modest_msg_edit_window_menu_dimming_entries,
1330 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1331 MODEST_WINDOW (obj));
1332 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1333 modest_msg_edit_window_toolbar_dimming_entries,
1334 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1335 MODEST_WINDOW (obj));
1336 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1337 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1338 MODEST_WINDOW (obj));
1339 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1340 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1341 MODEST_WINDOW (obj));
1342 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1343 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1344 MODEST_WINDOW (obj));
1345 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1346 modest_msg_edit_window_clipboard_dimming_entries,
1347 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1348 MODEST_WINDOW (obj));
1349 /* Insert dimming rules group for this window */
1350 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1351 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1352 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1353 /* Checks the dimming rules */
1354 g_object_unref (menu_rules_group);
1355 g_object_unref (toolbar_rules_group);
1356 g_object_unref (clipboard_rules_group);
1357 gtk_widget_show_all (GTK_WIDGET (obj));
1359 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1361 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1363 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1364 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1365 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1366 priv->update_caption_visibility = TRUE;
1368 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1370 /* Track account-removed signal, this window should be closed
1371 in the case we're creating a mail associated to the account
1373 priv->account_removed_handler_id =
1374 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1376 G_CALLBACK(on_account_removed),
1379 return (ModestWindow*) obj;
1383 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1385 GString **string_buffer = (GString **) user_data;
1387 *string_buffer = g_string_append (*string_buffer, buffer);
1393 * @result: A new string which should be freed with g_free().
1396 get_formatted_data (ModestMsgEditWindow *edit_window)
1398 ModestMsgEditWindowPrivate *priv;
1399 GString *string_buffer = g_string_new ("");
1401 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1403 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1405 return g_string_free (string_buffer, FALSE);
1410 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1413 const gchar *account_name;
1414 ModestMsgEditWindowPrivate *priv;
1415 TnyIterator *att_iter;
1417 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1419 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1421 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1422 g_return_val_if_fail (account_name, NULL);
1425 /* don't free these (except from) */
1426 data = g_slice_new0 (MsgData);
1427 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1429 data->account_name = g_strdup (account_name);
1430 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1431 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1432 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1433 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1434 if (priv->draft_msg) {
1435 data->draft_msg = g_object_ref (priv->draft_msg);
1436 } else if (priv->outbox_msg) {
1437 data->draft_msg = g_object_ref (priv->outbox_msg);
1439 data->draft_msg = NULL;
1442 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1444 gtk_text_buffer_get_bounds (buf, &b, &e);
1445 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1447 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1448 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1450 data->html_body = NULL;
1452 /* deep-copy the data */
1453 att_iter = tny_list_create_iterator (priv->attachments);
1454 data->attachments = NULL;
1455 while (!tny_iterator_is_done (att_iter)) {
1456 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1457 if (!(TNY_IS_MIME_PART(part))) {
1458 g_warning ("strange data in attachment list");
1459 g_object_unref (part);
1460 tny_iterator_next (att_iter);
1463 data->attachments = g_list_append (data->attachments,
1465 tny_iterator_next (att_iter);
1467 g_object_unref (att_iter);
1469 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1470 att_iter = tny_list_create_iterator (priv->images);
1471 data->images = NULL;
1472 while (!tny_iterator_is_done (att_iter)) {
1473 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1475 if (!(TNY_IS_MIME_PART(part))) {
1476 g_warning ("strange data in attachment list");
1477 g_object_unref (part);
1478 tny_iterator_next (att_iter);
1481 cid = tny_mime_part_get_content_id (part);
1483 gchar *image_tag_id;
1484 GtkTextTag *image_tag;
1486 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1487 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1488 g_free (image_tag_id);
1490 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1492 ((gtk_text_iter_has_tag (&iter, image_tag))||
1493 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1494 data->images = g_list_append (data->images,
1495 g_object_ref (part));
1497 g_object_unref (part);
1498 tny_iterator_next (att_iter);
1501 data->priority_flags = priv->priority_flags;
1508 unref_gobject (GObject *obj, gpointer data)
1510 if (!G_IS_OBJECT(obj))
1512 g_object_unref (obj);
1516 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1519 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1527 g_free (data->from);
1528 g_free (data->subject);
1529 g_free (data->plain_body);
1530 g_free (data->html_body);
1531 g_free (data->account_name);
1533 if (data->draft_msg != NULL) {
1534 g_object_unref (data->draft_msg);
1535 data->draft_msg = NULL;
1538 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1539 g_list_free (data->attachments);
1540 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1541 g_list_free (data->images);
1543 g_slice_free (MsgData, data);
1547 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1550 ModestMsgEditWindowPrivate *priv = NULL;
1551 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1553 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1555 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1557 return MODEST_MSG_EDIT_FORMAT_HTML;
1559 return MODEST_MSG_EDIT_FORMAT_TEXT;
1563 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1564 ModestMsgEditFormat format)
1566 ModestMsgEditWindowPrivate *priv;
1568 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1569 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1572 case MODEST_MSG_EDIT_FORMAT_HTML:
1573 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1575 case MODEST_MSG_EDIT_FORMAT_TEXT:
1576 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1579 g_return_if_reached ();
1583 ModestMsgEditFormatState *
1584 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1586 ModestMsgEditFormatState *format_state = NULL;
1587 ModestMsgEditWindowPrivate *priv;
1588 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1590 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1591 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1593 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1595 format_state = g_new0 (ModestMsgEditFormatState, 1);
1596 format_state->bold = buffer_format->bold&0x1;
1597 format_state->italics = buffer_format->italic&0x1;
1598 format_state->bullet = buffer_format->bullet&0x1;
1599 format_state->color = buffer_format->color;
1600 format_state->font_size = buffer_format->font_size;
1601 format_state->font_family = wp_get_font_name (buffer_format->font);
1602 format_state->justification = buffer_format->justification;
1603 g_free (buffer_format);
1605 return format_state;
1610 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1611 const ModestMsgEditFormatState *format_state)
1613 ModestMsgEditWindowPrivate *priv;
1614 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1615 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1616 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1617 g_return_if_fail (format_state != NULL);
1619 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1620 gtk_widget_grab_focus (priv->msg_body);
1621 buffer_format->bold = (format_state->bold != FALSE);
1622 buffer_format->italic = (format_state->italics != FALSE);
1623 buffer_format->color = format_state->color;
1624 buffer_format->font_size = format_state->font_size;
1625 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1626 buffer_format->justification = format_state->justification;
1627 buffer_format->bullet = format_state->bullet;
1629 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1631 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1632 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1633 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1634 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1635 buffer_format->cs.font = (buffer_format->font != current_format->font);
1636 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1637 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1639 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1640 if (buffer_format->cs.bold) {
1641 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1642 GINT_TO_POINTER (buffer_format->bold&0x1));
1644 if (buffer_format->cs.italic) {
1645 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1646 GINT_TO_POINTER (buffer_format->italic&0x1));
1648 if (buffer_format->cs.color) {
1649 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1650 GINT_TO_POINTER (&(buffer_format->color)));
1652 if (buffer_format->cs.font_size) {
1653 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1654 GINT_TO_POINTER (buffer_format->font_size));
1656 if (buffer_format->cs.justification) {
1657 switch (buffer_format->justification) {
1658 case GTK_JUSTIFY_LEFT:
1659 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1660 GINT_TO_POINTER(TRUE));
1662 case GTK_JUSTIFY_CENTER:
1663 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1664 GINT_TO_POINTER(TRUE));
1666 case GTK_JUSTIFY_RIGHT:
1667 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1668 GINT_TO_POINTER(TRUE));
1675 if (buffer_format->cs.font) {
1676 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1677 GINT_TO_POINTER (buffer_format->font));
1679 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1680 if (buffer_format->cs.bullet) {
1681 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1682 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1684 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1686 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1688 g_free (current_format);
1693 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1695 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1697 ModestWindowPrivate *parent_priv;
1698 ModestMsgEditWindowPrivate *priv;
1699 GtkWidget *new_size_menuitem;
1700 GtkWidget *new_font_menuitem;
1702 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1703 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1705 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1706 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1707 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1708 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1710 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1711 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1712 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1715 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1717 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1718 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1720 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1721 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1723 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1724 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1727 switch (buffer_format->justification)
1729 case GTK_JUSTIFY_LEFT:
1730 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentLeftMenu");
1732 case GTK_JUSTIFY_CENTER:
1733 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentCenterMenu");
1735 case GTK_JUSTIFY_RIGHT:
1736 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentRightMenu");
1743 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1745 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1746 G_CALLBACK (modest_msg_edit_window_color_button_change),
1748 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1749 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1750 G_CALLBACK (modest_msg_edit_window_color_button_change),
1753 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1754 buffer_format->font_size))->data);
1755 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1759 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1760 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1761 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1763 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1764 G_CALLBACK (modest_msg_edit_window_size_change),
1766 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1767 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1768 G_CALLBACK (modest_msg_edit_window_size_change),
1772 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1773 buffer_format->font))->data);
1774 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1778 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1779 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1780 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1782 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1783 G_CALLBACK (modest_msg_edit_window_font_change),
1785 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1786 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1787 G_CALLBACK (modest_msg_edit_window_font_change),
1791 g_free (buffer_format);
1795 #ifdef MODEST_HILDON_VERSION_0
1797 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1800 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1801 ModestMsgEditWindowPrivate *priv;
1802 GtkWidget *dialog = NULL;
1804 GdkColor *new_color = NULL;
1806 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1807 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1809 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1810 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1811 g_free (buffer_format);
1813 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1814 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1815 if (new_color != NULL) {
1816 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1817 (gpointer) new_color);
1820 gtk_widget_destroy (dialog);
1825 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1828 ModestMsgEditWindowPrivate *priv;
1829 GtkWidget *dialog = NULL;
1831 GdkColor *old_color = NULL;
1832 const GdkColor *new_color = NULL;
1834 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1835 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1837 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1838 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1840 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1841 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1842 if (new_color != NULL)
1843 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1845 gtk_widget_destroy (dialog);
1851 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1854 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1855 ModestMsgEditWindowPrivate *priv;
1856 GtkWidget *dialog = NULL;
1858 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1859 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1861 dialog = hildon_color_chooser_new ();
1862 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1863 g_free (buffer_format);
1865 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1867 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1868 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1871 gtk_widget_destroy (dialog);
1876 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1879 ModestMsgEditWindowPrivate *priv;
1880 GtkWidget *dialog = NULL;
1881 GdkColor *old_color = NULL;
1883 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1884 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1886 dialog = hildon_color_chooser_new ();
1887 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1889 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1891 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1892 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1894 gtk_widget_destroy (dialog);
1897 #endif /*!MODEST_HILDON_VERSION_0*/
1901 static TnyStream* create_stream_for_uri (const gchar* uri)
1906 TnyStream *result = NULL;
1908 GnomeVFSHandle *handle = NULL;
1909 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1910 if (test == GNOME_VFS_OK) {
1911 /* Create the tinymail stream: */
1912 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1913 result = TNY_STREAM (tny_vfs_stream_new (handle));
1920 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1923 ModestMsgEditWindowPrivate *priv;
1924 GtkWidget *dialog = NULL;
1926 GSList *uris = NULL;
1927 GSList *uri_node = NULL;
1929 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1931 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1932 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1933 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1935 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1937 response = gtk_dialog_run (GTK_DIALOG (dialog));
1939 case GTK_RESPONSE_OK:
1940 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1945 gtk_widget_destroy (dialog);
1947 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1949 GnomeVFSHandle *handle = NULL;
1950 GnomeVFSResult result;
1951 GtkTextIter position;
1952 GtkTextMark *insert_mark;
1954 uri = (const gchar *) uri_node->data;
1955 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1956 if (result == GNOME_VFS_OK) {
1958 GnomeVFSFileInfo info;
1959 gchar *filename, *basename, *escaped_filename;
1960 TnyMimePart *mime_part;
1962 const gchar *mime_type = NULL;
1963 GnomeVFSURI *vfs_uri;
1965 vfs_uri = gnome_vfs_uri_new (uri);
1967 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1968 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1969 g_free (escaped_filename);
1970 gnome_vfs_uri_unref (vfs_uri);
1972 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1973 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1975 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1977 mime_part = tny_platform_factory_new_mime_part
1978 (modest_runtime_get_platform_factory ());
1980 TnyStream *stream = create_stream_for_uri (uri);
1981 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
1983 content_id = g_strdup_printf ("%d", priv->last_cid);
1984 tny_mime_part_set_content_id (mime_part, content_id);
1985 g_free (content_id);
1988 basename = g_path_get_basename (filename);
1989 tny_mime_part_set_filename (mime_part, basename);
1992 pixbuf = pixbuf_from_stream (stream, mime_type);
1994 if (pixbuf != NULL) {
1995 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1996 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1997 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2000 tny_list_prepend (priv->images, (GObject *) mime_part);
2001 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2003 g_object_unref (mime_part);
2012 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2014 GtkWidget *dialog = NULL;
2016 GSList *uris = NULL;
2019 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2020 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2021 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2023 response = gtk_dialog_run (GTK_DIALOG (dialog));
2025 case GTK_RESPONSE_OK:
2026 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2031 gtk_widget_destroy (dialog);
2033 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2034 const gchar *uri = (const gchar *) uri_node->data;
2035 modest_msg_edit_window_attach_file_one (window, uri);
2037 g_slist_foreach (uris, (GFunc) g_free, NULL);
2038 g_slist_free (uris);
2042 modest_msg_edit_window_attach_file_one (
2043 ModestMsgEditWindow *window,
2046 g_return_if_fail (window);
2047 g_return_if_fail (uri);
2049 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2052 GnomeVFSHandle *handle = NULL;
2053 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2054 if (result == GNOME_VFS_OK) {
2055 TnyMimePart *mime_part;
2057 const gchar *mime_type = NULL;
2059 gchar *escaped_filename;
2062 GnomeVFSFileInfo info;
2063 GnomeVFSURI *vfs_uri;
2065 vfs_uri = gnome_vfs_uri_new (uri);
2068 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2069 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2070 g_free (escaped_filename);
2071 gnome_vfs_uri_unref (vfs_uri);
2073 if (gnome_vfs_get_file_info (uri,
2075 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2077 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2078 mime_part = tny_platform_factory_new_mime_part
2079 (modest_runtime_get_platform_factory ());
2080 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2082 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2084 g_object_unref (stream);
2086 content_id = g_strdup_printf ("%d", priv->last_cid);
2087 tny_mime_part_set_content_id (mime_part, content_id);
2088 g_free (content_id);
2091 basename = g_path_get_basename (filename);
2092 tny_mime_part_set_filename (mime_part, basename);
2095 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2096 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2098 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2099 gtk_widget_show_all (priv->attachments_caption);
2100 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2102 g_object_unref (mime_part);
2107 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2110 ModestMsgEditWindowPrivate *priv;
2113 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2114 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2116 if (att_list == NULL) {
2117 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2119 g_object_ref (att_list);
2122 if (tny_list_get_length (att_list) == 0) {
2123 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2125 GtkWidget *confirmation_dialog = NULL;
2126 gboolean dialog_response;
2127 gchar *message = NULL;
2128 gchar *filename = NULL;
2130 if (tny_list_get_length (att_list) == 1) {
2132 iter = tny_list_create_iterator (att_list);
2133 part = (TnyMimePart *) tny_iterator_get_current (iter);
2134 g_object_unref (iter);
2135 if (TNY_IS_MSG (part)) {
2136 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2138 filename = g_strdup (tny_header_get_subject (header));
2139 g_object_unref (header);
2141 if (filename == NULL) {
2142 filename = g_strdup (_("mail_va_no_subject"));
2145 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2147 g_object_unref (part);
2149 filename = g_strdup ("");
2151 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2152 (tny_list_get_length (att_list) == 1)), filename);
2154 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2156 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2157 gtk_widget_destroy (confirmation_dialog);
2158 if (!dialog_response) {
2159 g_object_unref (att_list);
2162 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2164 for (iter = tny_list_create_iterator (att_list);
2165 !tny_iterator_is_done (iter);
2166 tny_iterator_next (iter)) {
2167 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2168 const gchar *att_id;
2169 tny_list_remove (priv->attachments, (GObject *) mime_part);
2171 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2173 if (tny_list_get_length (priv->attachments) == 0)
2174 gtk_widget_hide (priv->attachments_caption);
2175 att_id = tny_mime_part_get_content_id (mime_part);
2177 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2179 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2180 g_object_unref (mime_part);
2184 g_object_unref (att_list);
2186 /* if the last attachment has been removed, focus the Subject: field */
2187 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2188 gtk_widget_grab_focus (priv->subject_field);
2192 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2195 ModestMsgEditWindowPrivate *priv;
2196 GdkColor *new_color;
2197 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2199 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2200 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2203 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2205 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2207 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2209 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2214 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2217 ModestMsgEditWindowPrivate *priv;
2218 gint new_size_index;
2219 ModestMsgEditWindow *window;
2222 window = MODEST_MSG_EDIT_WINDOW (userdata);
2223 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2224 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2226 if (gtk_check_menu_item_get_active (menu_item)) {
2228 WPTextBufferFormat format;
2230 memset (&format, 0, sizeof (format));
2231 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2233 label = gtk_bin_get_child (GTK_BIN (menu_item));
2235 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2236 format.cs.font_size = TRUE;
2237 format.cs.text_position = TRUE;
2238 format.cs.font = TRUE;
2239 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2240 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2242 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2243 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2244 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2246 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2247 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2248 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2254 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2257 ModestMsgEditWindowPrivate *priv;
2258 gint new_font_index;
2259 ModestMsgEditWindow *window;
2262 window = MODEST_MSG_EDIT_WINDOW (userdata);
2263 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2264 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2266 if (gtk_check_menu_item_get_active (menu_item)) {
2269 label = gtk_bin_get_child (GTK_BIN (menu_item));
2271 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2273 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2274 GINT_TO_POINTER(new_font_index)))
2275 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2277 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2278 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2279 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2285 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2287 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2288 ModestWindowPrivate *parent_priv;
2289 ModestWindowMgr *mgr;
2290 gboolean is_fullscreen;
2291 GtkAction *fs_toggle_action;
2294 mgr = modest_runtime_get_window_mgr ();
2295 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2297 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2299 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2300 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2301 if (is_fullscreen != active)
2302 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2310 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2313 ModestMsgEditWindowPrivate *priv = NULL;
2314 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2316 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2317 if (!priv->update_caption_visibility)
2320 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2322 gtk_widget_show (priv->cc_caption);
2324 gtk_widget_hide (priv->cc_caption);
2326 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2330 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2333 ModestMsgEditWindowPrivate *priv = NULL;
2334 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2336 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2337 if (!priv->update_caption_visibility)
2340 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2342 gtk_widget_show (priv->bcc_caption);
2344 gtk_widget_hide (priv->bcc_caption);
2346 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2350 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2351 ModestRecptEditor *editor)
2353 ModestMsgEditWindowPrivate *priv;
2355 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2356 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2357 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2359 if (editor == NULL) {
2360 GtkWidget *view_focus;
2361 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2363 /* This code should be kept in sync with ModestRecptEditor. The
2364 textview inside the recpt editor is the one that really gets the
2365 focus. As it's inside a scrolled window, and this one inside the
2366 hbox recpt editor inherits from, we'll need to go up in the
2367 hierarchy to know if the text view is part of the recpt editor
2368 or if it's a different text entry */
2370 if (gtk_widget_get_parent (view_focus)) {
2371 GtkWidget *first_parent;
2373 first_parent = gtk_widget_get_parent (view_focus);
2374 if (gtk_widget_get_parent (first_parent) &&
2375 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2376 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2381 editor = MODEST_RECPT_EDITOR (priv->to_field);
2385 modest_address_book_select_addresses (editor);
2390 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2392 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2394 modest_msg_edit_window_open_addressbook (window, NULL);
2398 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2399 gboolean show_toolbar)
2401 ModestWindowPrivate *parent_priv;
2402 const gchar *action_name;
2405 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2406 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2408 /* We can not just use the code of
2409 modest_msg_edit_window_setup_toolbar because it has a
2410 mixture of both initialization and creation code. */
2412 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2414 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2416 /* Update also the actions (to update the toggles in the
2417 menus), we have to do it manually because some other window
2418 of the same time could have changed it (remember that the
2419 toolbar fullscreen mode is shared by all the windows of the
2421 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2422 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2424 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2426 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2427 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2433 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2434 TnyHeaderFlags priority_flags)
2436 ModestMsgEditWindowPrivate *priv;
2437 ModestWindowPrivate *parent_priv;
2439 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2441 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2442 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2444 if (priv->priority_flags != priority_flags) {
2445 GtkAction *priority_action = NULL;
2447 priv->priority_flags = priority_flags;
2449 switch (priority_flags) {
2450 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2451 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2452 gtk_widget_show (priv->priority_icon);
2453 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2454 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2456 case TNY_HEADER_FLAG_LOW_PRIORITY:
2457 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2458 gtk_widget_show (priv->priority_icon);
2459 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2460 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2463 gtk_widget_hide (priv->priority_icon);
2464 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2465 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2468 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2469 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2474 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2477 ModestMsgEditWindowPrivate *priv;
2478 ModestWindowPrivate *parent_priv;
2479 gint current_format;
2481 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2483 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2484 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2486 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2487 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2489 if (current_format != file_format) {
2490 switch (file_format) {
2491 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2492 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2493 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2495 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2499 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2500 response = gtk_dialog_run (GTK_DIALOG (dialog));
2501 gtk_widget_destroy (dialog);
2502 if (response == GTK_RESPONSE_OK) {
2503 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2505 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2506 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2511 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2516 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2519 ModestMsgEditWindowPrivate *priv;
2520 WPTextBufferFormat oldfmt, fmt;
2521 gint old_position = 0;
2525 GdkColor *color = NULL;
2526 gboolean bold, bold_set, italic, italic_set;
2527 gboolean underline, underline_set;
2528 gboolean strikethrough, strikethrough_set;
2529 gboolean position_set;
2530 gboolean font_size_set, font_set, color_set;
2533 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2534 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2536 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2538 /* First we get the currently selected font information */
2539 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2541 switch (oldfmt.text_position) {
2542 case TEXT_POSITION_NORMAL:
2545 case TEXT_POSITION_SUPERSCRIPT:
2553 g_object_set (G_OBJECT (dialog),
2554 "bold", oldfmt.bold != FALSE,
2555 "bold-set", !oldfmt.cs.bold,
2556 "underline", oldfmt.underline != FALSE,
2557 "underline-set", !oldfmt.cs.underline,
2558 "italic", oldfmt.italic != FALSE,
2559 "italic-set", !oldfmt.cs.italic,
2560 "strikethrough", oldfmt.strikethrough != FALSE,
2561 "strikethrough-set", !oldfmt.cs.strikethrough,
2562 "color", &oldfmt.color,
2563 "color-set", !oldfmt.cs.color,
2564 "size", wp_font_size[oldfmt.font_size],
2565 "size-set", !oldfmt.cs.font_size,
2566 "position", old_position,
2567 "position-set", !oldfmt.cs.text_position,
2568 "family", wp_get_font_name (oldfmt.font),
2569 "family-set", !oldfmt.cs.font,
2572 gtk_widget_show_all (dialog);
2573 response = gtk_dialog_run (GTK_DIALOG (dialog));
2574 if (response == GTK_RESPONSE_OK) {
2576 g_object_get( dialog,
2578 "bold-set", &bold_set,
2579 "underline", &underline,
2580 "underline-set", &underline_set,
2582 "italic-set", &italic_set,
2583 "strikethrough", &strikethrough,
2584 "strikethrough-set", &strikethrough_set,
2586 "color-set", &color_set,
2588 "size-set", &font_size_set,
2589 "family", &font_name,
2590 "family-set", &font_set,
2591 "position", &position,
2592 "position-set", &position_set,
2597 if (response == GTK_RESPONSE_OK) {
2598 memset(&fmt, 0, sizeof(fmt));
2604 fmt.italic = italic;
2605 fmt.cs.italic = TRUE;
2607 if (underline_set) {
2608 fmt.underline = underline;
2609 fmt.cs.underline = TRUE;
2611 if (strikethrough_set) {
2612 fmt.strikethrough = strikethrough;
2613 fmt.cs.strikethrough = TRUE;
2618 ? TEXT_POSITION_NORMAL
2619 : ( ( position == 1 )
2620 ? TEXT_POSITION_SUPERSCRIPT
2621 : TEXT_POSITION_SUBSCRIPT );
2622 fmt.cs.text_position = TRUE;
2623 fmt.font_size = oldfmt.font_size;
2627 fmt.cs.color = TRUE;
2630 fmt.font = wp_get_font_index(font_name,
2635 if (font_size_set) {
2636 fmt.cs.font_size = TRUE;
2637 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2639 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2640 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2642 gtk_widget_destroy (dialog);
2644 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2648 modest_msg_edit_window_undo (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_undo (WP_TEXT_BUFFER (priv->text_buffer));
2657 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2658 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2663 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2665 ModestMsgEditWindowPrivate *priv;
2667 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2668 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2670 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2672 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2673 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2678 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2680 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2682 priv->can_undo = can_undo;
2686 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2688 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2690 priv->can_redo = can_redo;
2694 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2696 ModestMsgEditWindowPrivate *priv;
2697 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2698 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2700 return priv->can_undo;
2704 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2706 ModestMsgEditWindowPrivate *priv;
2707 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2708 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2710 return priv->can_redo;
2715 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2718 GtkTextIter match_start, match_end;
2720 if (image_id == NULL)
2723 gtk_text_buffer_get_start_iter (buffer, &iter);
2725 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2726 GSList *tags = gtk_text_iter_get_tags (&match_start);
2728 for (node = tags; node != NULL; node = g_slist_next (node)) {
2729 GtkTextTag *tag = (GtkTextTag *) node->data;
2730 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2731 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2732 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2734 offset = gtk_text_iter_get_offset (&match_start);
2735 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2736 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2740 gtk_text_iter_forward_char (&iter);
2745 message_is_empty (ModestMsgEditWindow *window)
2747 ModestMsgEditWindowPrivate *priv = NULL;
2749 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2750 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2752 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2753 * so we can ignore markup.
2755 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2758 count = gtk_text_buffer_get_char_count (buf);
2764 msg_body_focus (GtkWidget *focus,
2765 GdkEventFocus *event,
2769 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2770 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
2771 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
2776 recpt_field_changed (GtkTextBuffer *buffer,
2777 ModestMsgEditWindow *editor)
2779 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2780 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
2784 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2786 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2787 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
2791 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2793 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2794 GtkTextBuffer *buffer;
2796 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2797 gtk_text_buffer_set_modified (buffer, FALSE);
2798 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2799 gtk_text_buffer_set_modified (buffer, FALSE);
2800 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2801 gtk_text_buffer_set_modified (buffer, FALSE);
2802 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2806 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2808 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2809 GtkTextBuffer *buffer;
2811 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2812 if (gtk_text_buffer_get_modified (buffer))
2814 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2815 if (gtk_text_buffer_get_modified (buffer))
2817 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2818 if (gtk_text_buffer_get_modified (buffer))
2820 if (gtk_text_buffer_get_modified (priv->text_buffer))
2830 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2832 ModestMsgEditWindowPrivate *priv = NULL;
2834 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2835 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2837 /* check if there's no recipient added */
2838 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2839 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2840 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2841 /* no recipient contents, then select contacts */
2842 modest_msg_edit_window_open_addressbook (window, NULL);
2846 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2847 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2850 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2851 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2854 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2855 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2859 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2860 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2861 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2868 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2869 ModestMsgEditWindow *window)
2871 modest_msg_edit_window_offer_attach_file (window);
2875 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2877 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2879 return priv->clipboard_text;
2883 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2885 ModestMsgEditWindow *window)
2887 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2888 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2890 if (!GTK_WIDGET_VISIBLE (window))
2893 text = gtk_clipboard_wait_for_text (selection_clipboard);
2895 if (priv->clipboard_text != NULL) {
2896 g_free (priv->clipboard_text);
2898 priv->clipboard_text = text;
2900 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2903 subject_field_move_cursor (GtkEntry *entry,
2904 GtkMovementStep step,
2909 if (!GTK_WIDGET_VISIBLE (window))
2912 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2916 update_window_title (ModestMsgEditWindow *window)
2918 ModestMsgEditWindowPrivate *priv = NULL;
2919 const gchar *subject;
2921 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2922 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2923 if (subject == NULL || subject[0] == '\0')
2924 subject = _("mail_va_new_email");
2926 gtk_window_set_title (GTK_WINDOW (window), subject);
2931 subject_field_changed (GtkEditable *editable,
2932 ModestMsgEditWindow *window)
2934 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2935 update_window_title (window);
2936 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2937 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2938 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2942 subject_field_insert_text (GtkEditable *editable,
2944 gint new_text_length,
2946 ModestMsgEditWindow *window)
2948 GString *result = g_string_new ("");
2950 gint result_len = 0;
2951 const gchar *entry_text = NULL;
2954 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2955 old_length = g_utf8_strlen (entry_text, -1);
2957 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2958 gunichar c = g_utf8_get_char_validated (current, 8);
2959 /* Invalid unichar, stop */
2965 result = g_string_append_unichar (result, c);
2969 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2970 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2973 /* Prevent endless recursion */
2974 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2975 g_signal_emit_by_name (editable, "insert-text",
2976 (gpointer) result->str, (gpointer) result->len,
2977 (gpointer) position, (gpointer) window);
2978 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2982 if (result_len + old_length > 1000) {
2983 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2984 dgettext("hildon-common-strings",
2985 "ckdg_ib_maximum_characters_reached"));
2988 g_string_free (result, TRUE);
2992 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2995 ModestMsgEditWindowPrivate *priv = NULL;
2997 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2998 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3000 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3003 gtk_widget_show_all (priv->find_toolbar);
3004 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3006 gtk_widget_hide_all (priv->find_toolbar);
3007 gtk_widget_grab_focus (priv->msg_body);
3013 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3015 GtkTextIter *match_start,
3016 GtkTextIter *match_end)
3018 GtkTextIter end_iter;
3019 gchar *str_casefold;
3022 gchar *range_casefold;
3025 gboolean result = FALSE;
3032 gtk_text_iter_forward_to_end (&end_iter);
3034 str_casefold = g_utf8_casefold (str, -1);
3035 str_chars_n = strlen (str);
3037 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3038 range_casefold = g_utf8_casefold (range_text, -1);
3039 range_chars_n = strlen (range_casefold);
3041 if (range_chars_n < str_chars_n) {
3042 g_free (str_casefold);
3043 g_free (range_text);
3044 g_free (range_casefold);
3048 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3049 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3050 if (!g_utf8_collate (range_subtext, str_casefold)) {
3051 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3053 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3054 match_start, match_end, NULL);
3055 g_free (found_text);
3057 g_free (range_subtext);
3061 g_free (str_casefold);
3062 g_free (range_text);
3063 g_free (range_casefold);
3070 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3071 ModestMsgEditWindow *window)
3073 gchar *current_search = NULL;
3074 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3076 GtkTextIter selection_start, selection_end;
3077 GtkTextIter match_start, match_end;
3078 gboolean continue_search = FALSE;
3080 if (message_is_empty (window)) {
3081 g_free (priv->last_search);
3082 priv->last_search = NULL;
3083 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3087 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3088 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3089 g_free (current_search);
3090 g_free (priv->last_search);
3091 priv->last_search = NULL;
3092 /* Information banner about empty search */
3093 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3097 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3098 continue_search = TRUE;
3100 g_free (priv->last_search);
3101 priv->last_search = g_strdup (current_search);
3104 if (continue_search) {
3105 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3106 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3107 &match_start, &match_end);
3109 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3111 GtkTextIter buffer_start;
3112 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3113 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3114 &match_start, &match_end);
3116 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3119 /* Mark as selected the string found in search */
3121 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3122 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3124 g_free (priv->last_search);
3125 priv->last_search = NULL;
3127 g_free (current_search);
3131 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3132 ModestMsgEditWindow *window)
3134 GtkToggleAction *toggle;
3135 ModestWindowPrivate *parent_priv;
3136 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3138 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3139 gtk_toggle_action_set_active (toggle, FALSE);
3143 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3145 ModestMsgEditWindowPrivate *priv;
3147 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3152 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3155 ModestMsgEditWindowPrivate *priv;
3157 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3163 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3166 ModestMsgEditWindowPrivate *priv;
3167 TnyHeader *header = NULL;
3169 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3170 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3172 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3173 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3175 if (priv->draft_msg != NULL) {
3176 g_object_unref (priv->draft_msg);
3179 if (draft != NULL) {
3180 g_object_ref (draft);
3181 header = tny_msg_get_header (draft);
3182 if (priv->msg_uid) {
3183 g_free (priv->msg_uid);
3184 priv->msg_uid = NULL;
3186 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3187 if (GTK_WIDGET_REALIZED (window))
3188 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3191 priv->draft_msg = draft;
3195 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3196 GtkTextIter *start, GtkTextIter *end,
3199 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3200 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3203 if (tag == NULL+13) return;
3204 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3205 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3206 replace_with_images (window, priv->images);
3211 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3214 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3216 g_return_if_fail (TNY_IS_MIME_PART (part));
3217 tny_list_prepend (priv->attachments, (GObject *) part);
3218 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3219 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3220 gtk_widget_show_all (priv->attachments_caption);
3221 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3225 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3227 ModestMsgEditWindowPrivate *priv;
3229 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3232 return priv->msg_uid;
3236 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3237 ModestMsgEditWindowWidgetType widget_type)
3239 ModestMsgEditWindowPrivate *priv;
3241 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3242 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3244 switch (widget_type) {
3245 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3246 return priv->msg_body;
3248 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3249 return priv->to_field;
3251 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3252 return priv->cc_field;
3254 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3255 return priv->bcc_field;
3257 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3258 return priv->subject_field;
3260 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3261 return priv->attachments_view;
3269 remove_tags (WPTextBuffer *buffer)
3271 GtkTextIter start, end;
3273 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3274 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3276 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3280 on_account_removed (TnyAccountStore *account_store,
3281 TnyAccount *account,
3284 /* Do nothing if it's a store account, because we use the
3285 transport to send the messages */
3286 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3287 const gchar *parent_acc = NULL;
3288 const gchar *our_acc = NULL;
3290 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3291 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3292 /* Close this window if I'm showing a message of the removed account */
3293 if (strcmp (parent_acc, our_acc) == 0)
3294 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3299 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3301 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3303 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3309 set_zoom_do_nothing (ModestWindow *window,
3315 get_zoom_do_nothing (ModestWindow *window)