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 init_window (ModestMsgEditWindow *obj);
163 static void DEBUG_BUFFER (WPTextBuffer *buffer)
168 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
169 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
170 while (!gtk_text_iter_is_end (&iter)) {
171 GString *output = g_string_new ("");
172 GSList *toggled_tags;
175 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
176 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
177 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
178 GtkTextTag *tag = (GtkTextTag *) node->data;
180 g_object_get (G_OBJECT (tag), "name", &name, NULL);
181 output = g_string_append (output, name);
182 g_string_append (output, " ");
184 output = g_string_append (output, "] OPENED [ ");
185 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
186 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
187 GtkTextTag *tag = (GtkTextTag *) node->data;
189 g_object_get (G_OBJECT (tag), "name", &name, NULL);
190 output = g_string_append (output, name);
191 g_string_append (output, " ");
193 output = g_string_append (output, "]\n");
194 g_message ("%s", output->str);
195 g_string_free (output, TRUE);
196 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
198 g_message ("END BUFFER");
203 /* static gboolean */
204 /* on_key_pressed (GtkWidget *self, */
205 /* GdkEventKey *event, */
206 /* gpointer user_data); */
208 /* list my signals */
215 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
216 struct _ModestMsgEditWindowPrivate {
218 GtkWidget *header_box;
220 ModestPairList *from_field_protos;
221 GtkWidget *from_field;
225 GtkWidget *bcc_field;
226 GtkWidget *subject_field;
227 GtkWidget *attachments_view;
228 GtkWidget *priority_icon;
229 GtkWidget *add_attachment_button;
231 GtkWidget *cc_caption;
232 GtkWidget *bcc_caption;
233 gboolean update_caption_visibility;
234 GtkWidget *attachments_caption;
236 GtkTextBuffer *text_buffer;
238 GtkWidget *font_size_toolitem;
239 GtkWidget *font_face_toolitem;
240 GtkWidget *font_color_button;
241 GSList *font_items_group;
242 GtkWidget *font_tool_button_label;
243 GSList *size_items_group;
244 GtkWidget *size_tool_button_label;
246 GtkWidget *find_toolbar;
250 GtkWidget *scroll_area;
251 gint last_vadj_upper;
257 TnyHeaderFlags priority_flags;
259 gboolean can_undo, can_redo;
260 gulong clipboard_change_handler_id;
261 gulong default_clipboard_change_handler_id;
262 gulong account_removed_handler_id;
263 gchar *clipboard_text;
272 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
273 MODEST_TYPE_MSG_EDIT_WINDOW, \
274 ModestMsgEditWindowPrivate))
276 static GtkWindowClass *parent_class = NULL;
278 /* uncomment the following if you have defined any signals */
279 /* static guint signals[LAST_SIGNAL] = {0}; */
282 modest_msg_edit_window_get_type (void)
284 static GType my_type = 0;
286 static const GTypeInfo my_info = {
287 sizeof(ModestMsgEditWindowClass),
288 NULL, /* base init */
289 NULL, /* base finalize */
290 (GClassInitFunc) modest_msg_edit_window_class_init,
291 NULL, /* class finalize */
292 NULL, /* class data */
293 sizeof(ModestMsgEditWindow),
295 (GInstanceInitFunc) modest_msg_edit_window_init,
298 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
299 "ModestMsgEditWindow",
307 save_state (ModestWindow *self)
309 modest_widget_memory_save (modest_runtime_get_conf(),
310 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
315 restore_settings (ModestMsgEditWindow *self)
317 ModestConf *conf = NULL;
319 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
321 conf = modest_runtime_get_conf ();
322 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
323 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
324 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
325 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
326 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
327 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
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_FULLSCREEN, NULL));
331 /* set initial state of cc and bcc */
332 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
333 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
334 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
335 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
336 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
337 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
339 /* Dim at start clipboard actions */
340 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
341 gtk_action_set_sensitive (action, FALSE);
342 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
343 gtk_action_set_sensitive (action, FALSE);
344 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
345 gtk_action_set_sensitive (action, FALSE);
347 modest_widget_memory_restore (conf,
348 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
353 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
355 GObjectClass *gobject_class;
356 ModestWindowClass *modest_window_class;
357 gobject_class = (GObjectClass*) klass;
358 modest_window_class = (ModestWindowClass*) klass;
360 parent_class = g_type_class_peek_parent (klass);
361 gobject_class->finalize = modest_msg_edit_window_finalize;
363 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
364 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
365 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
366 modest_window_class->save_state_func = save_state;
367 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
369 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
373 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
375 ModestMsgEditWindowPrivate *priv;
376 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
378 priv->msg_body = NULL;
379 priv->from_field = NULL;
380 priv->to_field = NULL;
381 priv->cc_field = NULL;
382 priv->bcc_field = NULL;
383 priv->subject_field = NULL;
384 priv->attachments = NULL;
388 priv->cc_caption = NULL;
389 priv->bcc_caption = NULL;
390 priv->update_caption_visibility = FALSE;
392 priv->priority_flags = 0;
394 priv->find_toolbar = NULL;
395 priv->last_search = NULL;
397 priv->draft_msg = NULL;
398 priv->outbox_msg = NULL;
399 priv->msg_uid = NULL;
401 priv->can_undo = FALSE;
402 priv->can_redo = FALSE;
403 priv->clipboard_change_handler_id = 0;
404 priv->default_clipboard_change_handler_id = 0;
405 priv->account_removed_handler_id = 0;
406 priv->clipboard_text = NULL;
409 priv->last_vadj_upper = 0;
411 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
412 GTK_WINDOW(obj),"applications_email_editor");
414 if (!is_wp_text_buffer_started) {
415 is_wp_text_buffer_started = TRUE;
416 wp_text_buffer_library_init ();
423 /* FIXME: this is a dup from the one in gtk/ */
426 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
428 static ModestPairList*
429 get_transports (void)
431 GSList *transports = NULL;
433 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
434 GSList *accounts = modest_account_mgr_account_names (account_mgr,
435 TRUE /* only enabled accounts. */);
437 GSList *cursor = accounts;
439 gchar *account_name = cursor->data;
440 gchar *from_string = NULL;
442 from_string = modest_account_mgr_get_from_string (account_mgr,
446 if (from_string && account_name) {
447 gchar *name = account_name;
448 ModestPair *pair = modest_pair_new ((gpointer) name,
449 (gpointer) from_string , TRUE);
450 transports = g_slist_prepend (transports, pair);
453 cursor = cursor->next;
455 g_slist_free (accounts); /* only free the accounts, not the elements,
456 * because they are used in the pairlist */
460 void vadj_changed (GtkAdjustment *adj,
461 ModestMsgEditWindow *window)
463 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
465 GdkRectangle rectangle, cursor_rectangle;
466 GtkTextIter position;
470 /* We detect if cursor is visible using the full height, not only the center. This
472 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
473 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
475 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
476 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
478 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
479 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
481 if (gtk_widget_is_focus (priv->msg_body) &&
483 if (priv->last_vadj_upper != adj->upper) {
486 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
487 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
488 insert, 0.1, FALSE, 0.0, 0.0);
491 priv->last_vadj_upper = adj->upper;
496 connect_signals (ModestMsgEditWindow *obj)
498 ModestMsgEditWindowPrivate *priv;
500 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
502 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
503 G_CALLBACK (text_buffer_refresh_attributes), obj);
504 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
505 G_CALLBACK (text_buffer_can_undo), obj);
506 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
507 G_CALLBACK (text_buffer_can_redo), obj);
508 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
509 G_CALLBACK (body_changed), obj);
510 g_signal_connect (G_OBJECT (obj), "window-state-event",
511 G_CALLBACK (modest_msg_edit_window_window_state_event),
513 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
514 G_CALLBACK (text_buffer_apply_tag), obj);
515 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
516 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
517 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
518 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
519 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
520 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
522 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
523 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
525 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
526 G_CALLBACK (msg_body_focus), obj);
527 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
528 G_CALLBACK (msg_body_focus), obj);
529 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
530 "changed", G_CALLBACK (recpt_field_changed), obj);
531 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
532 "changed", G_CALLBACK (recpt_field_changed), obj);
533 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
534 "changed", G_CALLBACK (recpt_field_changed), obj);
535 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
536 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
537 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
539 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
540 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
542 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
544 G_CALLBACK (vadj_changed),
547 priv->clipboard_change_handler_id =
548 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
549 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
550 priv->default_clipboard_change_handler_id =
551 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
552 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
557 menubar_to_menu (GtkUIManager *ui_manager)
559 GtkWidget *main_menu;
561 /* Get the menubar from the UI manager */
562 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
568 init_window (ModestMsgEditWindow *obj)
570 GtkWidget *from_caption, *to_caption, *subject_caption;
571 GtkWidget *main_vbox;
572 ModestMsgEditWindowPrivate *priv;
573 GtkActionGroup *action_group;
574 ModestWindowPrivate *parent_priv;
575 GdkPixbuf *window_icon = NULL;
576 GError *error = NULL;
578 GtkSizeGroup *size_group;
580 GtkWidget *subject_box;
581 GtkWidget *attachment_icon;
582 GtkWidget *window_box;
583 #if (GTK_MINOR_VERSION >= 10)
584 GdkAtom deserialize_type;
586 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
587 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
589 parent_priv->ui_manager = gtk_ui_manager_new();
590 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
591 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
593 /* Add common actions */
594 gtk_action_group_add_actions (action_group,
595 modest_msg_edit_action_entries,
596 G_N_ELEMENTS (modest_msg_edit_action_entries),
598 gtk_action_group_add_toggle_actions (action_group,
599 modest_msg_edit_toggle_action_entries,
600 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
602 gtk_action_group_add_radio_actions (action_group,
603 modest_msg_edit_alignment_radio_action_entries,
604 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
606 G_CALLBACK (modest_ui_actions_on_change_justify),
608 gtk_action_group_add_radio_actions (action_group,
609 modest_msg_edit_priority_action_entries,
610 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
612 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
614 gtk_action_group_add_radio_actions (action_group,
615 modest_msg_edit_file_format_action_entries,
616 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
617 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
618 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
620 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
621 g_object_unref (action_group);
623 /* Load the UI definition */
624 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
627 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
628 g_clear_error (&error);
631 /* Add accelerators */
632 gtk_window_add_accel_group (GTK_WINDOW (obj),
633 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
635 parent_priv->menubar = NULL;
637 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
639 /* Note: This ModestPairList* must exist for as long as the combo
640 * that uses it, because the ModestComboBox uses the ID opaquely,
641 * so it can't know how to manage its memory. */
642 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
644 priv->to_field = modest_recpt_editor_new ();
645 priv->cc_field = modest_recpt_editor_new ();
646 priv->bcc_field = modest_recpt_editor_new ();
647 subject_box = gtk_hbox_new (FALSE, 0);
648 priv->priority_icon = gtk_image_new ();
649 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
650 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
651 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
652 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
653 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
654 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
655 priv->add_attachment_button = gtk_button_new ();
656 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
657 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
658 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
659 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
660 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
661 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
662 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
663 priv->attachments_view = modest_attachments_view_new (NULL);
665 priv->header_box = gtk_vbox_new (FALSE, 0);
667 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
668 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
669 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
670 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
671 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
672 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
673 g_object_unref (size_group);
675 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
676 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
677 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
678 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
679 gtk_size_group_add_widget (size_group, priv->subject_field);
680 gtk_size_group_add_widget (size_group, priv->attachments_view);
681 g_object_unref (size_group);
683 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
684 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
685 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
686 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
687 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
688 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
689 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
692 priv->msg_body = wp_text_view_new ();
693 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
694 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
695 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
696 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
697 #if (GTK_MINOR_VERSION >= 10)
698 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
699 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
701 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
702 deserialize_type, TRUE);
704 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
706 priv->find_toolbar = hildon_find_toolbar_new (NULL);
707 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
709 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
711 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
712 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
713 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
714 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
716 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
718 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
719 frame = gtk_frame_new (NULL);
720 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
722 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
723 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
724 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
726 G_CALLBACK (vadj_changed),
728 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
730 window_box = gtk_vbox_new (FALSE, 0);
731 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
732 gtk_container_add (GTK_CONTAINER(obj), window_box);
733 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
734 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
736 /* Set window icon */
737 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
739 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
740 g_object_unref (window_icon);
746 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
748 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
750 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
751 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
752 priv->clipboard_change_handler_id))
753 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
754 priv->clipboard_change_handler_id);
755 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
756 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
757 priv->default_clipboard_change_handler_id))
758 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
759 priv->default_clipboard_change_handler_id);
761 if (priv->account_removed_handler_id &&
762 g_signal_handler_is_connected (modest_runtime_get_account_store (),
763 priv->account_removed_handler_id))
764 g_signal_handler_disconnect(modest_runtime_get_account_store (),
765 priv->account_removed_handler_id);
769 modest_msg_edit_window_finalize (GObject *obj)
771 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
773 /* Sanity check: shouldn't be needed, the window mgr should
774 call this function before */
775 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
777 if (priv->clipboard_text != NULL) {
778 g_free (priv->clipboard_text);
779 priv->clipboard_text = NULL;
782 if (priv->draft_msg != NULL) {
783 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
784 if (TNY_IS_HEADER (header)) {
785 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
786 modest_window_mgr_unregister_header (mgr, header);
788 g_object_unref (priv->draft_msg);
789 priv->draft_msg = NULL;
791 if (priv->outbox_msg != NULL) {
792 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
793 if (TNY_IS_HEADER (header)) {
794 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
795 modest_window_mgr_unregister_header (mgr, header);
797 g_object_unref (priv->outbox_msg);
798 priv->outbox_msg = NULL;
800 g_free (priv->msg_uid);
801 g_free (priv->last_search);
802 g_slist_free (priv->font_items_group);
803 g_slist_free (priv->size_items_group);
804 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
805 g_list_free (priv->attachments);
806 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
807 g_list_free (priv->images);
809 /* This had to stay alive for as long as the combobox that used it: */
810 modest_pair_list_free (priv->from_field_protos);
812 G_OBJECT_CLASS(parent_class)->finalize (obj);
816 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
818 GdkPixbufLoader *loader;
821 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
826 tny_stream_reset (TNY_STREAM (stream));
827 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
828 unsigned char read_buffer[128];
830 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
831 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
835 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
836 g_object_ref (pixbuf);
837 gdk_pixbuf_loader_close (loader, NULL);
838 g_object_unref (loader);
840 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
841 GdkPixbuf *new_pixbuf;
843 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
844 gdk_pixbuf_get_width (pixbuf);
845 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
846 g_object_unref (pixbuf);
854 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
856 ModestMsgEditWindowPrivate *priv;
859 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
861 for (node = attachments; node != NULL; node = g_list_next (node)) {
862 TnyMimePart *part = (TnyMimePart *) node->data;
863 const gchar *cid = tny_mime_part_get_content_id (part);
864 const gchar *mime_type = tny_mime_part_get_content_type (part);
865 if ((cid != NULL)&&(mime_type != NULL)) {
866 TnyStream *stream = tny_mime_part_get_stream (part);
867 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
868 g_object_unref (stream);
870 if (pixbuf != NULL) {
871 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
872 g_object_unref (pixbuf);
879 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
881 TnyMimePart *parent = NULL;
882 const gchar *content_type = NULL;
883 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
885 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
887 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
888 parent = g_object_ref (msg);
889 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
890 TnyList *parts = TNY_LIST (tny_simple_list_new ());
893 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
894 iter = tny_list_create_iterator (parts);
895 while (!tny_iterator_is_done (iter)) {
897 part = TNY_MIME_PART (tny_iterator_get_current (iter));
898 content_type = tny_mime_part_get_content_type (part);
899 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
903 g_object_unref (part);
905 tny_iterator_next (iter);
907 g_object_unref (iter);
908 g_object_unref (parts);
911 if (parent != NULL) {
912 TnyList *parts = TNY_LIST (tny_simple_list_new ());
915 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
916 iter = tny_list_create_iterator (parts);
917 while (!tny_iterator_is_done (iter)) {
919 part = TNY_MIME_PART (tny_iterator_get_current (iter));
920 content_type = tny_mime_part_get_content_type (part);
921 if (content_type && g_str_has_prefix (content_type, "image/")) {
922 priv->images = g_list_prepend (priv->images, part);
924 g_object_unref (part);
926 tny_iterator_next (iter);
928 g_object_unref (iter);
929 g_object_unref (parts);
930 g_object_unref (parent);
935 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
938 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
940 for (node = attachments; node != NULL; node = g_list_next (node)) {
941 TnyMimePart *part = (TnyMimePart *) node->data;
942 const gchar *cid = tny_mime_part_get_content_id (part);
944 char *invalid = NULL;
945 gint int_cid = strtol (cid, &invalid, 10);
946 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
947 priv->last_cid = int_cid;
955 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
958 const gchar *to, *cc, *bcc, *subject;
960 ModestMsgEditWindowPrivate *priv;
962 TnyHeaderFlags priority_flags;
963 TnyFolder *msg_folder;
964 gboolean is_html = FALSE;
966 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
967 g_return_if_fail (TNY_IS_MSG (msg));
969 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
971 header = tny_msg_get_header (msg);
972 to = tny_header_get_to (header);
973 cc = tny_header_get_cc (header);
974 bcc = tny_header_get_bcc (header);
975 subject = tny_header_get_subject (header);
976 priority_flags = tny_header_get_priority (header);
979 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
981 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
982 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
983 gtk_widget_show (priv->cc_caption);
984 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
985 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
986 gtk_widget_hide (priv->cc_caption);
989 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
990 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
991 gtk_widget_show (priv->bcc_caption);
992 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
993 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
994 gtk_widget_hide (priv->bcc_caption);
997 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
998 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1001 update_window_title (self);
1003 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1004 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1006 if ((body == NULL)||(body[0] == '\0')) {
1008 body = modest_text_utils_convert_to_html ("");
1011 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1012 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1015 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1018 /* Add attachments to the view */
1019 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1020 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1021 if (priv->attachments == NULL) {
1022 gtk_widget_hide (priv->attachments_caption);
1024 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1025 gtk_widget_show_all (priv->attachments_caption);
1027 get_related_images (self, msg);
1028 update_last_cid (self, priv->attachments);
1029 update_last_cid (self, priv->images);
1030 replace_with_images (self, priv->images);
1032 if (preserve_is_rich && !is_html) {
1033 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1034 /* Get the default format required from configuration */
1035 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1036 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1039 /* Set the default focus depending on having already a To: field or not */
1040 if ((!to)||(*to == '\0')) {
1041 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1043 gtk_widget_grab_focus (priv->msg_body);
1046 /* TODO: lower priority, select in the From: combo to the
1047 value that comes from msg <- not sure, should it be
1050 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1052 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1053 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1055 modest_msg_edit_window_reset_modified (self);
1057 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1058 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1059 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1061 if (priv->msg_uid) {
1062 g_free (priv->msg_uid);
1063 priv->msg_uid = NULL;
1066 /* we should set a reference to the incoming message if it is a draft */
1067 msg_folder = tny_msg_get_folder (msg);
1069 if (modest_tny_folder_is_local_folder (msg_folder)) {
1070 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1071 if (type == TNY_FOLDER_TYPE_INVALID)
1072 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1074 if (type == TNY_FOLDER_TYPE_DRAFTS)
1075 priv->draft_msg = g_object_ref(msg);
1076 if (type == TNY_FOLDER_TYPE_OUTBOX)
1077 priv->outbox_msg = g_object_ref(msg);
1078 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1080 g_object_unref (msg_folder);
1085 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1088 GList *item_children, *node;
1089 GtkWidget *bin_child;
1091 bin_child = gtk_bin_get_child (GTK_BIN(item));
1093 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1095 for (node = item_children; node != NULL; node = g_list_next (node)) {
1096 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1097 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1100 g_list_free (item_children);
1104 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1107 GList *item_children, *node;
1109 box = gtk_bin_get_child (GTK_BIN (item));
1110 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1111 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1113 for (node = item_children; node != NULL; node = g_list_next (node)) {
1114 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1115 if (GTK_IS_TOGGLE_BUTTON (node->data))
1116 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1117 else if (GTK_IS_BUTTON (node->data))
1118 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1120 g_list_free (item_children);
1125 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1127 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1128 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1129 GtkWidget *placeholder;
1130 GtkWidget *tool_item;
1135 GtkWidget *sizes_menu;
1136 GtkWidget *fonts_menu;
1137 GSList *radio_group = NULL;
1138 GSList *node = NULL;
1142 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1143 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1145 /* Font color placeholder */
1146 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1147 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1150 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1151 priv->font_color_button = hildon_color_button_new ();
1152 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1153 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1154 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1155 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1156 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1157 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1158 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1160 G_CALLBACK (modest_msg_edit_window_color_button_change),
1163 /* Font size and face placeholder */
1164 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1165 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1167 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1168 priv->size_tool_button_label = gtk_label_new (NULL);
1169 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1170 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1171 size_text,"</span>", NULL);
1172 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1174 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1175 sizes_menu = gtk_menu_new ();
1176 priv->size_items_group = NULL;
1178 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1179 GtkWidget *size_menu_item;
1181 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1182 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1183 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1184 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1185 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1186 gtk_widget_show (size_menu_item);
1188 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1192 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1193 GtkWidget *item = (GtkWidget *) node->data;
1194 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1198 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1199 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1200 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1201 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1202 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1203 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1204 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1205 priv->font_size_toolitem = tool_item;
1208 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1209 priv->font_tool_button_label = gtk_label_new (NULL);
1210 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1211 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1213 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1214 fonts_menu = gtk_menu_new ();
1215 priv->font_items_group = NULL;
1217 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1218 GtkWidget *font_menu_item;
1219 GtkWidget *child_label;
1221 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1222 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1223 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1224 wp_get_font_name (font_index), "</span>", NULL);
1225 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1228 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1229 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1230 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1231 gtk_widget_show (font_menu_item);
1233 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1236 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1237 GtkWidget *item = (GtkWidget *) node->data;
1238 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1241 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1242 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1243 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1244 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1245 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1246 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1247 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1248 priv->font_face_toolitem = tool_item;
1250 /* Set expand and homogeneous for remaining items */
1251 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1252 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1253 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1254 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1255 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1256 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1257 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1258 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1259 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1261 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1262 will not show the tool items added to the placeholders) */
1263 gtk_widget_show_all (parent_priv->toolbar);
1265 /* Set the no show all *after* showing all items. We do not
1266 want the toolbar to be shown with a show all because it
1267 could go agains the gconf setting regarding showing or not
1268 the toolbar of the editor window */
1269 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1275 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1278 ModestWindowPrivate *parent_priv;
1279 ModestMsgEditWindowPrivate *priv;
1280 ModestPair *account_pair = NULL;
1281 ModestDimmingRulesGroup *menu_rules_group = NULL;
1282 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1283 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1284 ModestWindowMgr *mgr = NULL;
1286 g_return_val_if_fail (msg, NULL);
1287 g_return_val_if_fail (account_name, NULL);
1289 mgr = modest_runtime_get_window_mgr ();
1291 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1293 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1294 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1296 /* Menubar. Update the state of some toggles */
1297 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1298 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1299 priv->from_field_protos = get_transports ();
1300 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1301 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1302 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1305 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1307 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1309 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1311 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1312 if (account_pair != NULL)
1313 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1315 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1316 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1317 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1318 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1319 /* Add common dimming rules */
1320 modest_dimming_rules_group_add_rules (menu_rules_group,
1321 modest_msg_edit_window_menu_dimming_entries,
1322 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1323 MODEST_WINDOW (obj));
1324 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1325 modest_msg_edit_window_toolbar_dimming_entries,
1326 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1327 MODEST_WINDOW (obj));
1328 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1329 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1330 MODEST_WINDOW (obj));
1331 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1332 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1333 MODEST_WINDOW (obj));
1334 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1335 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1336 MODEST_WINDOW (obj));
1337 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1338 modest_msg_edit_window_clipboard_dimming_entries,
1339 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1340 MODEST_WINDOW (obj));
1341 /* Insert dimming rules group for this window */
1342 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1343 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1344 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1345 /* Checks the dimming rules */
1346 g_object_unref (menu_rules_group);
1347 g_object_unref (toolbar_rules_group);
1348 g_object_unref (clipboard_rules_group);
1350 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1352 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1354 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1355 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1356 priv->update_caption_visibility = TRUE;
1358 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1360 /* Track account-removed signal, this window should be closed
1361 in the case we're creating a mail associated to the account
1363 priv->account_removed_handler_id =
1364 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1366 G_CALLBACK(on_account_removed),
1369 return (ModestWindow*) obj;
1373 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1375 GString **string_buffer = (GString **) user_data;
1377 *string_buffer = g_string_append (*string_buffer, buffer);
1383 * @result: A new string which should be freed with g_free().
1386 get_formatted_data (ModestMsgEditWindow *edit_window)
1388 ModestMsgEditWindowPrivate *priv;
1389 GString *string_buffer = g_string_new ("");
1391 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1393 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1395 return g_string_free (string_buffer, FALSE);
1400 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1403 const gchar *account_name;
1404 ModestMsgEditWindowPrivate *priv;
1406 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1408 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1410 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1411 g_return_val_if_fail (account_name, NULL);
1414 /* don't free these (except from) */
1415 data = g_slice_new0 (MsgData);
1416 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1418 data->account_name = g_strdup (account_name);
1419 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1420 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1421 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1422 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1423 if (priv->draft_msg) {
1424 data->draft_msg = g_object_ref (priv->draft_msg);
1425 } else if (priv->outbox_msg) {
1426 data->draft_msg = g_object_ref (priv->outbox_msg);
1428 data->draft_msg = NULL;
1431 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1433 gtk_text_buffer_get_bounds (buf, &b, &e);
1434 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1436 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1437 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1439 data->html_body = NULL;
1441 /* deep-copy the data */
1442 GList *cursor = priv->attachments;
1443 data->attachments = NULL;
1445 if (!(TNY_IS_MIME_PART(cursor->data))) {
1446 g_warning ("strange data in attachment list");
1447 cursor = g_list_next (cursor);
1450 data->attachments = g_list_append (data->attachments,
1451 g_object_ref (cursor->data));
1452 cursor = g_list_next (cursor);
1455 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1456 cursor = priv->images;
1457 data->images = NULL;
1460 if (!(TNY_IS_MIME_PART(cursor->data))) {
1461 g_warning ("strange data in attachment list");
1462 cursor = g_list_next (cursor);
1465 cid = tny_mime_part_get_content_id (cursor->data);
1467 gchar *image_tag_id;
1468 GtkTextTag *image_tag;
1470 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1471 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1472 g_free (image_tag_id);
1474 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1476 ((gtk_text_iter_has_tag (&iter, image_tag))||
1477 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1478 data->images = g_list_append (data->images,
1479 g_object_ref (cursor->data));
1481 cursor = g_list_next (cursor);
1484 data->priority_flags = priv->priority_flags;
1491 unref_gobject (GObject *obj, gpointer data)
1493 if (!G_IS_OBJECT(obj))
1495 g_object_unref (obj);
1499 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1502 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1510 g_free (data->from);
1511 g_free (data->subject);
1512 g_free (data->plain_body);
1513 g_free (data->html_body);
1514 g_free (data->account_name);
1516 if (data->draft_msg != NULL) {
1517 g_object_unref (data->draft_msg);
1518 data->draft_msg = NULL;
1521 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1522 g_list_free (data->attachments);
1523 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1524 g_list_free (data->images);
1526 g_slice_free (MsgData, data);
1530 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1533 ModestMsgEditWindowPrivate *priv = NULL;
1534 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1536 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1538 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1540 return MODEST_MSG_EDIT_FORMAT_HTML;
1542 return MODEST_MSG_EDIT_FORMAT_TEXT;
1546 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1547 ModestMsgEditFormat format)
1549 ModestMsgEditWindowPrivate *priv;
1551 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1552 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1555 case MODEST_MSG_EDIT_FORMAT_HTML:
1556 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1558 case MODEST_MSG_EDIT_FORMAT_TEXT:
1559 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1562 g_return_if_reached ();
1566 ModestMsgEditFormatState *
1567 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1569 ModestMsgEditFormatState *format_state = NULL;
1570 ModestMsgEditWindowPrivate *priv;
1571 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1573 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1574 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1576 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1578 format_state = g_new0 (ModestMsgEditFormatState, 1);
1579 format_state->bold = buffer_format->bold&0x1;
1580 format_state->italics = buffer_format->italic&0x1;
1581 format_state->bullet = buffer_format->bullet&0x1;
1582 format_state->color = buffer_format->color;
1583 format_state->font_size = buffer_format->font_size;
1584 format_state->font_family = wp_get_font_name (buffer_format->font);
1585 format_state->justification = buffer_format->justification;
1586 g_free (buffer_format);
1588 return format_state;
1593 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1594 const ModestMsgEditFormatState *format_state)
1596 ModestMsgEditWindowPrivate *priv;
1597 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1598 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1599 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1600 g_return_if_fail (format_state != NULL);
1602 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1603 gtk_widget_grab_focus (priv->msg_body);
1604 buffer_format->bold = (format_state->bold != FALSE);
1605 buffer_format->italic = (format_state->italics != FALSE);
1606 buffer_format->color = format_state->color;
1607 buffer_format->font_size = format_state->font_size;
1608 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1609 buffer_format->justification = format_state->justification;
1610 buffer_format->bullet = format_state->bullet;
1612 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1614 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1615 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1616 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1617 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1618 buffer_format->cs.font = (buffer_format->font != current_format->font);
1619 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1620 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1622 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1623 if (buffer_format->cs.bold) {
1624 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1625 GINT_TO_POINTER (buffer_format->bold&0x1));
1627 if (buffer_format->cs.italic) {
1628 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1629 GINT_TO_POINTER (buffer_format->italic&0x1));
1631 if (buffer_format->cs.color) {
1632 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1633 GINT_TO_POINTER (&(buffer_format->color)));
1635 if (buffer_format->cs.font_size) {
1636 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1637 GINT_TO_POINTER (buffer_format->font_size));
1639 if (buffer_format->cs.justification) {
1640 switch (buffer_format->justification) {
1641 case GTK_JUSTIFY_LEFT:
1642 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1643 GINT_TO_POINTER(TRUE));
1645 case GTK_JUSTIFY_CENTER:
1646 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1647 GINT_TO_POINTER(TRUE));
1649 case GTK_JUSTIFY_RIGHT:
1650 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1651 GINT_TO_POINTER(TRUE));
1658 if (buffer_format->cs.font) {
1659 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1660 GINT_TO_POINTER (buffer_format->font));
1662 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1663 if (buffer_format->cs.bullet) {
1664 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1665 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1667 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1669 g_free (current_format);
1674 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1676 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1678 ModestWindowPrivate *parent_priv;
1679 ModestMsgEditWindowPrivate *priv;
1680 GtkWidget *new_size_menuitem;
1681 GtkWidget *new_font_menuitem;
1683 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1684 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1686 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1687 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1688 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1689 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1691 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1692 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1693 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1696 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1698 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1699 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1701 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1702 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1704 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1705 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1707 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1708 G_CALLBACK (modest_msg_edit_window_color_button_change),
1710 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1711 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1712 G_CALLBACK (modest_msg_edit_window_color_button_change),
1715 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1716 buffer_format->font_size))->data);
1717 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1721 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1722 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1723 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1725 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1726 G_CALLBACK (modest_msg_edit_window_size_change),
1728 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1729 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1730 G_CALLBACK (modest_msg_edit_window_size_change),
1734 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1735 buffer_format->font))->data);
1736 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1740 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1741 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1742 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1744 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1745 G_CALLBACK (modest_msg_edit_window_font_change),
1747 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1748 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1749 G_CALLBACK (modest_msg_edit_window_font_change),
1753 g_free (buffer_format);
1757 #ifdef MODEST_HILDON_VERSION_0
1759 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1762 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1763 ModestMsgEditWindowPrivate *priv;
1764 GtkWidget *dialog = NULL;
1766 GdkColor *new_color = NULL;
1768 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1769 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1771 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1772 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1773 g_free (buffer_format);
1775 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1776 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1777 if (new_color != NULL) {
1778 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1779 (gpointer) new_color);
1782 gtk_widget_destroy (dialog);
1787 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1790 ModestMsgEditWindowPrivate *priv;
1791 GtkWidget *dialog = NULL;
1793 GdkColor *old_color = NULL;
1794 const GdkColor *new_color = NULL;
1796 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1797 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1799 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1800 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1802 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1803 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1804 if (new_color != NULL)
1805 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1807 gtk_widget_destroy (dialog);
1813 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1816 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1817 ModestMsgEditWindowPrivate *priv;
1818 GtkWidget *dialog = NULL;
1820 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1821 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1823 dialog = hildon_color_chooser_new ();
1824 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1825 g_free (buffer_format);
1827 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1829 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1830 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1833 gtk_widget_destroy (dialog);
1838 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1841 ModestMsgEditWindowPrivate *priv;
1842 GtkWidget *dialog = NULL;
1843 GdkColor *old_color = NULL;
1845 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1846 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1848 dialog = hildon_color_chooser_new ();
1849 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1851 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1853 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1854 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1856 gtk_widget_destroy (dialog);
1859 #endif /*!MODEST_HILDON_VERSION_0*/
1863 static TnyStream* create_stream_for_uri (const gchar* uri)
1868 TnyStream *result = NULL;
1870 GnomeVFSHandle *handle = NULL;
1871 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1872 if (test == GNOME_VFS_OK) {
1873 /* Create the tinymail stream: */
1874 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1875 result = TNY_STREAM (tny_vfs_stream_new (handle));
1882 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1885 ModestMsgEditWindowPrivate *priv;
1886 GtkWidget *dialog = NULL;
1888 GSList *uris = NULL;
1889 GSList *uri_node = NULL;
1891 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1893 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1894 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1895 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1897 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1899 response = gtk_dialog_run (GTK_DIALOG (dialog));
1901 case GTK_RESPONSE_OK:
1902 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1907 gtk_widget_destroy (dialog);
1909 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1911 GnomeVFSHandle *handle = NULL;
1912 GnomeVFSResult result;
1913 GtkTextIter position;
1914 GtkTextMark *insert_mark;
1916 uri = (const gchar *) uri_node->data;
1917 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1918 if (result == GNOME_VFS_OK) {
1920 GnomeVFSFileInfo info;
1921 gchar *filename, *basename, *escaped_filename;
1922 TnyMimePart *mime_part;
1924 const gchar *mime_type = NULL;
1925 GnomeVFSURI *vfs_uri;
1927 vfs_uri = gnome_vfs_uri_new (uri);
1929 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1930 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1931 g_free (escaped_filename);
1932 gnome_vfs_uri_unref (vfs_uri);
1934 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1935 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1937 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1939 mime_part = tny_platform_factory_new_mime_part
1940 (modest_runtime_get_platform_factory ());
1942 TnyStream *stream = create_stream_for_uri (uri);
1943 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1945 content_id = g_strdup_printf ("%d", priv->last_cid);
1946 tny_mime_part_set_content_id (mime_part, content_id);
1947 g_free (content_id);
1950 basename = g_path_get_basename (filename);
1951 tny_mime_part_set_filename (mime_part, basename);
1954 pixbuf = pixbuf_from_stream (stream, mime_type);
1956 if (pixbuf != NULL) {
1957 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1958 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1959 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1962 priv->images = g_list_prepend (priv->images, mime_part);
1963 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1973 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1975 GtkWidget *dialog = NULL;
1977 GSList *uris = NULL;
1980 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1981 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1982 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1984 response = gtk_dialog_run (GTK_DIALOG (dialog));
1986 case GTK_RESPONSE_OK:
1987 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1992 gtk_widget_destroy (dialog);
1994 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1995 const gchar *uri = (const gchar *) uri_node->data;
1996 modest_msg_edit_window_attach_file_one (window, uri);
1998 g_slist_foreach (uris, (GFunc) g_free, NULL);
1999 g_slist_free (uris);
2003 modest_msg_edit_window_attach_file_one (
2004 ModestMsgEditWindow *window,
2007 g_return_if_fail (window);
2008 g_return_if_fail (uri);
2010 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2013 GnomeVFSHandle *handle = NULL;
2014 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2015 if (result == GNOME_VFS_OK) {
2016 TnyMimePart *mime_part;
2018 const gchar *mime_type = NULL;
2020 gchar *escaped_filename;
2023 GnomeVFSFileInfo info;
2024 GnomeVFSURI *vfs_uri;
2026 vfs_uri = gnome_vfs_uri_new (uri);
2029 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2030 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2031 g_free (escaped_filename);
2032 gnome_vfs_uri_unref (vfs_uri);
2034 if (gnome_vfs_get_file_info (uri,
2036 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2037 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2039 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2040 mime_part = tny_platform_factory_new_mime_part
2041 (modest_runtime_get_platform_factory ());
2042 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2044 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2046 content_id = g_strdup_printf ("%d", priv->last_cid);
2047 tny_mime_part_set_content_id (mime_part, content_id);
2048 g_free (content_id);
2051 basename = g_path_get_basename (filename);
2052 tny_mime_part_set_filename (mime_part, basename);
2055 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2056 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2058 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2059 gtk_widget_show_all (priv->attachments_caption);
2060 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2066 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2069 ModestMsgEditWindowPrivate *priv;
2070 gboolean clean_list = FALSE;
2072 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2073 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2075 if (att_list == NULL) {
2076 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2080 if (att_list == NULL) {
2081 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2083 GtkWidget *confirmation_dialog = NULL;
2084 gboolean dialog_response;
2086 gchar *message = NULL;
2087 gchar *filename = NULL;
2089 if (att_list->next == NULL) {
2090 if (TNY_IS_MSG (att_list->data)) {
2091 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2093 filename = g_strdup (tny_header_get_subject (header));
2094 g_object_unref (header);
2096 if (filename == NULL) {
2097 filename = g_strdup (_("mail_va_no_subject"));
2100 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2103 filename = g_strdup ("");
2105 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2106 att_list->next == NULL), filename);
2108 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2110 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2111 gtk_widget_destroy (confirmation_dialog);
2112 if (!dialog_response) {
2114 g_list_free (att_list);
2117 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2119 for (node = att_list; node != NULL; node = g_list_next (node)) {
2120 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2121 const gchar *att_id;
2122 priv->attachments = g_list_remove (priv->attachments, mime_part);
2124 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2126 if (priv->attachments == NULL)
2127 gtk_widget_hide (priv->attachments_caption);
2128 att_id = tny_mime_part_get_content_id (mime_part);
2130 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2132 g_object_unref (mime_part);
2133 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2138 g_list_free (att_list);
2142 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2145 ModestMsgEditWindowPrivate *priv;
2146 GdkColor *new_color;
2147 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2149 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2150 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2153 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2155 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2157 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2159 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2164 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2167 ModestMsgEditWindowPrivate *priv;
2168 gint new_size_index;
2169 ModestMsgEditWindow *window;
2172 window = MODEST_MSG_EDIT_WINDOW (userdata);
2173 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2174 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2176 if (gtk_check_menu_item_get_active (menu_item)) {
2178 WPTextBufferFormat format;
2180 memset (&format, 0, sizeof (format));
2181 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2183 label = gtk_bin_get_child (GTK_BIN (menu_item));
2185 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2186 format.cs.font_size = TRUE;
2187 format.cs.text_position = TRUE;
2188 format.cs.font = TRUE;
2189 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2190 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2192 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2193 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2194 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2196 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2197 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2198 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2204 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2207 ModestMsgEditWindowPrivate *priv;
2208 gint new_font_index;
2209 ModestMsgEditWindow *window;
2212 window = MODEST_MSG_EDIT_WINDOW (userdata);
2213 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2214 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2216 if (gtk_check_menu_item_get_active (menu_item)) {
2219 label = gtk_bin_get_child (GTK_BIN (menu_item));
2221 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2223 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2224 GINT_TO_POINTER(new_font_index)))
2225 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2227 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2228 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2229 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2235 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2237 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2238 ModestWindowPrivate *parent_priv;
2239 ModestWindowMgr *mgr;
2240 gboolean is_fullscreen;
2241 GtkAction *fs_toggle_action;
2244 mgr = modest_runtime_get_window_mgr ();
2245 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2247 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2249 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2250 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2251 if (is_fullscreen != active)
2252 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2260 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2263 ModestMsgEditWindowPrivate *priv = NULL;
2264 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2266 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2267 if (!priv->update_caption_visibility)
2270 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2272 gtk_widget_show (priv->cc_caption);
2274 gtk_widget_hide (priv->cc_caption);
2276 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2280 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2283 ModestMsgEditWindowPrivate *priv = NULL;
2284 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2286 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2287 if (!priv->update_caption_visibility)
2290 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2292 gtk_widget_show (priv->bcc_caption);
2294 gtk_widget_hide (priv->bcc_caption);
2296 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2300 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2301 ModestRecptEditor *editor)
2303 ModestMsgEditWindowPrivate *priv;
2305 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2306 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2307 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2309 if (editor == NULL) {
2310 GtkWidget *view_focus;
2311 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2313 /* This code should be kept in sync with ModestRecptEditor. The
2314 textview inside the recpt editor is the one that really gets the
2315 focus. As it's inside a scrolled window, and this one inside the
2316 hbox recpt editor inherits from, we'll need to go up in the
2317 hierarchy to know if the text view is part of the recpt editor
2318 or if it's a different text entry */
2320 if (gtk_widget_get_parent (view_focus)) {
2321 GtkWidget *first_parent;
2323 first_parent = gtk_widget_get_parent (view_focus);
2324 if (gtk_widget_get_parent (first_parent) &&
2325 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2326 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2331 editor = MODEST_RECPT_EDITOR (priv->to_field);
2335 modest_address_book_select_addresses (editor);
2340 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2342 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2344 modest_msg_edit_window_open_addressbook (window, NULL);
2348 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2349 gboolean show_toolbar)
2351 ModestWindowPrivate *parent_priv;
2352 const gchar *action_name;
2355 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2356 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2358 /* We can not just use the code of
2359 modest_msg_edit_window_setup_toolbar because it has a
2360 mixture of both initialization and creation code. */
2362 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2364 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2366 /* Update also the actions (to update the toggles in the
2367 menus), we have to do it manually because some other window
2368 of the same time could have changed it (remember that the
2369 toolbar fullscreen mode is shared by all the windows of the
2371 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2372 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2374 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2376 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2377 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2383 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2384 TnyHeaderFlags priority_flags)
2386 ModestMsgEditWindowPrivate *priv;
2387 ModestWindowPrivate *parent_priv;
2389 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2391 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2392 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2394 if (priv->priority_flags != priority_flags) {
2395 GtkAction *priority_action = NULL;
2397 priv->priority_flags = priority_flags;
2399 switch (priority_flags) {
2400 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2401 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2402 gtk_widget_show (priv->priority_icon);
2403 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2404 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2406 case TNY_HEADER_FLAG_LOW_PRIORITY:
2407 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2408 gtk_widget_show (priv->priority_icon);
2409 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2410 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2413 gtk_widget_hide (priv->priority_icon);
2414 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2415 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2418 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2419 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2424 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2427 ModestMsgEditWindowPrivate *priv;
2428 ModestWindowPrivate *parent_priv;
2429 gint current_format;
2431 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2433 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2434 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2436 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2437 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2439 if (current_format != file_format) {
2440 switch (file_format) {
2441 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2442 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2443 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2445 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2449 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2450 response = gtk_dialog_run (GTK_DIALOG (dialog));
2451 gtk_widget_destroy (dialog);
2452 if (response == GTK_RESPONSE_OK) {
2453 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2455 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2456 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2461 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2466 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2469 ModestMsgEditWindowPrivate *priv;
2470 WPTextBufferFormat oldfmt, fmt;
2471 gint old_position = 0;
2475 GdkColor *color = NULL;
2476 gboolean bold, bold_set, italic, italic_set;
2477 gboolean underline, underline_set;
2478 gboolean strikethrough, strikethrough_set;
2479 gboolean position_set;
2480 gboolean font_size_set, font_set, color_set;
2483 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2484 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2486 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2488 /* First we get the currently selected font information */
2489 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2491 switch (oldfmt.text_position) {
2492 case TEXT_POSITION_NORMAL:
2495 case TEXT_POSITION_SUPERSCRIPT:
2503 g_object_set (G_OBJECT (dialog),
2504 "bold", oldfmt.bold != FALSE,
2505 "bold-set", !oldfmt.cs.bold,
2506 "underline", oldfmt.underline != FALSE,
2507 "underline-set", !oldfmt.cs.underline,
2508 "italic", oldfmt.italic != FALSE,
2509 "italic-set", !oldfmt.cs.italic,
2510 "strikethrough", oldfmt.strikethrough != FALSE,
2511 "strikethrough-set", !oldfmt.cs.strikethrough,
2512 "color", &oldfmt.color,
2513 "color-set", !oldfmt.cs.color,
2514 "size", wp_font_size[oldfmt.font_size],
2515 "size-set", !oldfmt.cs.font_size,
2516 "position", old_position,
2517 "position-set", !oldfmt.cs.text_position,
2518 "family", wp_get_font_name (oldfmt.font),
2519 "family-set", !oldfmt.cs.font,
2522 gtk_widget_show_all (dialog);
2523 response = gtk_dialog_run (GTK_DIALOG (dialog));
2524 if (response == GTK_RESPONSE_OK) {
2526 g_object_get( dialog,
2528 "bold-set", &bold_set,
2529 "underline", &underline,
2530 "underline-set", &underline_set,
2532 "italic-set", &italic_set,
2533 "strikethrough", &strikethrough,
2534 "strikethrough-set", &strikethrough_set,
2536 "color-set", &color_set,
2538 "size-set", &font_size_set,
2539 "family", &font_name,
2540 "family-set", &font_set,
2541 "position", &position,
2542 "position-set", &position_set,
2547 if (response == GTK_RESPONSE_OK) {
2548 memset(&fmt, 0, sizeof(fmt));
2554 fmt.italic = italic;
2555 fmt.cs.italic = TRUE;
2557 if (underline_set) {
2558 fmt.underline = underline;
2559 fmt.cs.underline = TRUE;
2561 if (strikethrough_set) {
2562 fmt.strikethrough = strikethrough;
2563 fmt.cs.strikethrough = TRUE;
2568 ? TEXT_POSITION_NORMAL
2569 : ( ( position == 1 )
2570 ? TEXT_POSITION_SUPERSCRIPT
2571 : TEXT_POSITION_SUBSCRIPT );
2572 fmt.cs.text_position = TRUE;
2576 fmt.cs.color = TRUE;
2579 fmt.font = wp_get_font_index(font_name,
2584 if (font_size_set) {
2585 fmt.font_size = wp_get_font_size_index(
2586 font_size, DEFAULT_FONT_SIZE);
2587 fmt.cs.font_size = TRUE;
2589 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2590 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2592 gtk_widget_destroy (dialog);
2594 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2598 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2600 ModestMsgEditWindowPrivate *priv;
2602 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2603 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2605 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2607 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2612 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2614 ModestMsgEditWindowPrivate *priv;
2616 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2617 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2619 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2621 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2626 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2628 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2630 priv->can_undo = can_undo;
2634 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2636 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2638 priv->can_redo = can_redo;
2642 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2644 ModestMsgEditWindowPrivate *priv;
2645 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2646 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2648 return priv->can_undo;
2652 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2654 ModestMsgEditWindowPrivate *priv;
2655 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2656 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2658 return priv->can_redo;
2663 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2666 GtkTextIter match_start, match_end;
2668 if (image_id == NULL)
2671 gtk_text_buffer_get_start_iter (buffer, &iter);
2673 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2674 GSList *tags = gtk_text_iter_get_tags (&match_start);
2676 for (node = tags; node != NULL; node = g_slist_next (node)) {
2677 GtkTextTag *tag = (GtkTextTag *) node->data;
2678 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2679 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2680 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2682 offset = gtk_text_iter_get_offset (&match_start);
2683 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2684 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2688 gtk_text_iter_forward_char (&iter);
2693 message_is_empty (ModestMsgEditWindow *window)
2695 ModestMsgEditWindowPrivate *priv = NULL;
2697 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2698 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2700 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2701 * so we can ignore markup.
2703 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2706 count = gtk_text_buffer_get_char_count (buf);
2712 msg_body_focus (GtkWidget *focus,
2713 GdkEventFocus *event,
2717 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2722 recpt_field_changed (GtkTextBuffer *buffer,
2723 ModestMsgEditWindow *editor)
2725 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2729 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2731 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2735 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2737 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2738 GtkTextBuffer *buffer;
2740 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2741 gtk_text_buffer_set_modified (buffer, FALSE);
2742 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2743 gtk_text_buffer_set_modified (buffer, FALSE);
2744 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2745 gtk_text_buffer_set_modified (buffer, FALSE);
2746 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2750 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2752 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2753 GtkTextBuffer *buffer;
2755 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2756 if (gtk_text_buffer_get_modified (buffer))
2758 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2759 if (gtk_text_buffer_get_modified (buffer))
2761 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2762 if (gtk_text_buffer_get_modified (buffer))
2764 if (gtk_text_buffer_get_modified (priv->text_buffer))
2774 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2776 ModestMsgEditWindowPrivate *priv = NULL;
2778 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2779 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2781 /* check if there's no recipient added */
2782 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2783 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2784 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2785 /* no recipient contents, then select contacts */
2786 modest_msg_edit_window_open_addressbook (window, NULL);
2790 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2791 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2794 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2795 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2798 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2799 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2803 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2804 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2805 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2812 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2813 ModestMsgEditWindow *window)
2815 modest_msg_edit_window_offer_attach_file (window);
2819 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2821 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2823 return priv->clipboard_text;
2827 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2829 ModestMsgEditWindow *window)
2831 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2832 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2834 if (!GTK_WIDGET_VISIBLE (window))
2837 text = gtk_clipboard_wait_for_text (selection_clipboard);
2839 if (priv->clipboard_text != NULL) {
2840 g_free (priv->clipboard_text);
2842 priv->clipboard_text = text;
2844 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2847 subject_field_move_cursor (GtkEntry *entry,
2848 GtkMovementStep step,
2853 if (!GTK_WIDGET_VISIBLE (window))
2856 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2860 update_window_title (ModestMsgEditWindow *window)
2862 ModestMsgEditWindowPrivate *priv = NULL;
2863 const gchar *subject;
2865 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2866 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2867 if (subject == NULL || subject[0] == '\0')
2868 subject = _("mail_va_new_email");
2870 gtk_window_set_title (GTK_WINDOW (window), subject);
2875 subject_field_changed (GtkEditable *editable,
2876 ModestMsgEditWindow *window)
2878 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2879 update_window_title (window);
2880 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2881 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2885 subject_field_insert_text (GtkEditable *editable,
2887 gint new_text_length,
2889 ModestMsgEditWindow *window)
2891 GString *result = g_string_new ("");
2893 gint result_len = 0;
2894 const gchar *entry_text = NULL;
2897 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2898 old_length = g_utf8_strlen (entry_text, -1);
2900 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2901 gunichar c = g_utf8_get_char_validated (current, 8);
2902 /* Invalid unichar, stop */
2908 result = g_string_append_unichar (result, c);
2912 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2913 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2916 /* Prevent endless recursion */
2917 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2918 g_signal_emit_by_name (editable, "insert-text",
2919 (gpointer) result->str, (gpointer) result->len,
2920 (gpointer) position, (gpointer) window);
2921 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2925 if (result_len + old_length > 1000) {
2926 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2927 dgettext("hildon-common-strings",
2928 "ckdg_ib_maximum_characters_reached"));
2931 g_string_free (result, TRUE);
2935 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2938 ModestMsgEditWindowPrivate *priv = NULL;
2940 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2941 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2943 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2946 gtk_widget_show_all (priv->find_toolbar);
2947 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2949 gtk_widget_hide_all (priv->find_toolbar);
2950 gtk_widget_grab_focus (priv->msg_body);
2956 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2958 GtkTextIter *match_start,
2959 GtkTextIter *match_end)
2961 GtkTextIter end_iter;
2962 gchar *str_casefold;
2965 gchar *range_casefold;
2968 gboolean result = FALSE;
2975 gtk_text_iter_forward_to_end (&end_iter);
2977 str_casefold = g_utf8_casefold (str, -1);
2978 str_chars_n = strlen (str);
2980 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2981 range_casefold = g_utf8_casefold (range_text, -1);
2982 range_chars_n = strlen (range_casefold);
2984 if (range_chars_n < str_chars_n) {
2985 g_free (str_casefold);
2986 g_free (range_text);
2987 g_free (range_casefold);
2991 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2992 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2993 if (!g_utf8_collate (range_subtext, str_casefold)) {
2994 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2996 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2997 match_start, match_end, NULL);
2998 g_free (found_text);
3000 g_free (range_subtext);
3004 g_free (str_casefold);
3005 g_free (range_text);
3006 g_free (range_casefold);
3013 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3014 ModestMsgEditWindow *window)
3016 gchar *current_search = NULL;
3017 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3019 GtkTextIter selection_start, selection_end;
3020 GtkTextIter match_start, match_end;
3021 gboolean continue_search = FALSE;
3023 if (message_is_empty (window)) {
3024 g_free (priv->last_search);
3025 priv->last_search = NULL;
3026 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3030 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3031 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3032 g_free (current_search);
3033 g_free (priv->last_search);
3034 priv->last_search = NULL;
3035 /* Information banner about empty search */
3036 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3040 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3041 continue_search = TRUE;
3043 g_free (priv->last_search);
3044 priv->last_search = g_strdup (current_search);
3047 if (continue_search) {
3048 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3049 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3050 &match_start, &match_end);
3052 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3054 GtkTextIter buffer_start;
3055 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3056 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3057 &match_start, &match_end);
3059 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3062 /* Mark as selected the string found in search */
3064 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3065 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3067 g_free (priv->last_search);
3068 priv->last_search = NULL;
3070 g_free (current_search);
3074 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3075 ModestMsgEditWindow *window)
3077 GtkToggleAction *toggle;
3078 ModestWindowPrivate *parent_priv;
3079 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3081 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3082 gtk_toggle_action_set_active (toggle, FALSE);
3086 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3088 ModestMsgEditWindowPrivate *priv;
3090 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3095 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3098 ModestMsgEditWindowPrivate *priv;
3100 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3106 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3109 ModestMsgEditWindowPrivate *priv;
3110 TnyHeader *header = NULL;
3112 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3113 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3115 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3116 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3118 if (priv->draft_msg != NULL) {
3119 g_object_unref (priv->draft_msg);
3122 if (draft != NULL) {
3123 g_object_ref (draft);
3124 header = tny_msg_get_header (draft);
3125 if (priv->msg_uid) {
3126 g_free (priv->msg_uid);
3127 priv->msg_uid = NULL;
3129 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3130 if (GTK_WIDGET_REALIZED (window))
3131 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3134 priv->draft_msg = draft;
3138 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3139 GtkTextIter *start, GtkTextIter *end,
3142 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3143 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3146 if (tag == NULL+13) return;
3147 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3148 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3149 replace_with_images (window, priv->images);
3154 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3157 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3159 g_return_if_fail (TNY_IS_MIME_PART (part));
3160 priv->attachments = g_list_prepend (priv->attachments, part);
3161 g_object_ref (part);
3162 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3163 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3164 gtk_widget_show_all (priv->attachments_caption);
3165 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3169 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3171 ModestMsgEditWindowPrivate *priv;
3173 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3174 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3176 return priv->msg_uid;
3180 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3181 ModestMsgEditWindowWidgetType widget_type)
3183 ModestMsgEditWindowPrivate *priv;
3185 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3186 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3188 switch (widget_type) {
3189 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3190 return priv->msg_body;
3192 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3193 return priv->to_field;
3195 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3196 return priv->cc_field;
3198 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3199 return priv->bcc_field;
3201 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3202 return priv->subject_field;
3204 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3205 return priv->attachments_view;
3213 remove_tags (WPTextBuffer *buffer)
3215 GtkTextIter start, end;
3217 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3218 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3220 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3224 on_account_removed (TnyAccountStore *account_store,
3225 TnyAccount *account,
3228 /* Do nothing if it's a store account, because we use the
3229 transport to send the messages */
3230 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3231 const gchar *parent_acc = NULL;
3232 const gchar *our_acc = NULL;
3234 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3235 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3236 /* Close this window if I'm showing a message of the removed account */
3237 if (strcmp (parent_acc, our_acc) == 0)
3238 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3243 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3245 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3247 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));