1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include "modest-maemo-utils.h"
81 #define DEFAULT_FONT_SIZE 3
82 #define DEFAULT_FONT 2
83 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
84 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
85 #define DEFAULT_MAIN_VBOX_SPACING 6
86 #define SUBJECT_MAX_LENGTH 1000
87 #define IMAGE_MAX_WIDTH 560
88 #define DEFAULT_FONT_SCALE 1.5
90 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
91 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
92 static void modest_msg_edit_window_finalize (GObject *obj);
94 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
95 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
96 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
98 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
99 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
100 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
101 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
102 GtkTextIter *start, GtkTextIter *end,
104 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
105 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
106 static void subject_field_insert_text (GtkEditable *editable,
108 gint new_text_length,
110 ModestMsgEditWindow *window);
111 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
113 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
115 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
117 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
118 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
119 GdkEventWindowState *event,
121 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
122 ModestRecptEditor *editor);
123 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
124 ModestMsgEditWindow *window);
126 /* ModestWindow methods implementation */
127 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
128 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
129 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
130 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
131 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
132 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
133 gboolean show_toolbar);
134 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
136 ModestMsgEditWindow *window);
137 static void subject_field_move_cursor (GtkEntry *entry,
138 GtkMovementStep step,
142 static void update_window_title (ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
148 ModestMsgEditWindow *window);
149 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
151 GtkTextIter *match_start,
152 GtkTextIter *match_end);
154 static void remove_tags (WPTextBuffer *buffer);
156 static void on_account_removed (TnyAccountStore *account_store,
160 static void init_window (ModestMsgEditWindow *obj);
162 static void DEBUG_BUFFER (WPTextBuffer *buffer)
167 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
168 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
169 while (!gtk_text_iter_is_end (&iter)) {
170 GString *output = g_string_new ("");
171 GSList *toggled_tags;
174 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
175 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
176 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
177 GtkTextTag *tag = (GtkTextTag *) node->data;
179 g_object_get (G_OBJECT (tag), "name", &name, NULL);
180 output = g_string_append (output, name);
181 g_string_append (output, " ");
183 output = g_string_append (output, "] OPENED [ ");
184 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
185 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
186 GtkTextTag *tag = (GtkTextTag *) node->data;
188 g_object_get (G_OBJECT (tag), "name", &name, NULL);
189 output = g_string_append (output, name);
190 g_string_append (output, " ");
192 output = g_string_append (output, "]\n");
193 g_message ("%s", output->str);
194 g_string_free (output, TRUE);
195 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
197 g_message ("END BUFFER");
202 /* static gboolean */
203 /* on_key_pressed (GtkWidget *self, */
204 /* GdkEventKey *event, */
205 /* gpointer user_data); */
207 /* list my signals */
214 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
215 struct _ModestMsgEditWindowPrivate {
217 GtkWidget *header_box;
219 ModestPairList *from_field_protos;
220 GtkWidget *from_field;
224 GtkWidget *bcc_field;
225 GtkWidget *subject_field;
226 GtkWidget *attachments_view;
227 GtkWidget *priority_icon;
228 GtkWidget *add_attachment_button;
230 GtkWidget *cc_caption;
231 GtkWidget *bcc_caption;
232 gboolean update_caption_visibility;
233 GtkWidget *attachments_caption;
235 GtkTextBuffer *text_buffer;
237 GtkWidget *font_size_toolitem;
238 GtkWidget *font_face_toolitem;
239 GtkWidget *font_color_button;
240 GSList *font_items_group;
241 GtkWidget *font_tool_button_label;
242 GSList *size_items_group;
243 GtkWidget *size_tool_button_label;
245 GtkWidget *find_toolbar;
249 GtkWidget *scroll_area;
250 gint last_vadj_upper;
256 TnyHeaderFlags priority_flags;
260 gboolean can_undo, can_redo;
261 gulong clipboard_change_handler_id;
262 gulong default_clipboard_change_handler_id;
263 gulong account_removed_handler_id;
264 gchar *clipboard_text;
273 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
274 MODEST_TYPE_MSG_EDIT_WINDOW, \
275 ModestMsgEditWindowPrivate))
277 static GtkWindowClass *parent_class = NULL;
279 /* uncomment the following if you have defined any signals */
280 /* static guint signals[LAST_SIGNAL] = {0}; */
283 modest_msg_edit_window_get_type (void)
285 static GType my_type = 0;
287 static const GTypeInfo my_info = {
288 sizeof(ModestMsgEditWindowClass),
289 NULL, /* base init */
290 NULL, /* base finalize */
291 (GClassInitFunc) modest_msg_edit_window_class_init,
292 NULL, /* class finalize */
293 NULL, /* class data */
294 sizeof(ModestMsgEditWindow),
296 (GInstanceInitFunc) modest_msg_edit_window_init,
299 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
300 "ModestMsgEditWindow",
303 wp_text_buffer_library_init ();
309 save_state (ModestWindow *self)
311 modest_widget_memory_save (modest_runtime_get_conf(),
312 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
317 restore_settings (ModestMsgEditWindow *self)
319 ModestConf *conf = NULL;
321 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
323 conf = modest_runtime_get_conf ();
324 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
325 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
326 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
327 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
328 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
329 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
330 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
331 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
333 /* set initial state of cc and bcc */
334 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
335 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
336 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
337 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
338 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
339 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
341 /* Dim at start clipboard actions */
342 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
343 gtk_action_set_sensitive (action, FALSE);
344 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
345 gtk_action_set_sensitive (action, FALSE);
346 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
347 gtk_action_set_sensitive (action, FALSE);
349 modest_widget_memory_restore (conf,
350 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
355 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
357 GObjectClass *gobject_class;
358 ModestWindowClass *modest_window_class;
359 gobject_class = (GObjectClass*) klass;
360 modest_window_class = (ModestWindowClass*) klass;
362 parent_class = g_type_class_peek_parent (klass);
363 gobject_class->finalize = modest_msg_edit_window_finalize;
365 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
366 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
367 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
368 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
369 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
370 modest_window_class->save_state_func = save_state;
371 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
373 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
377 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
379 ModestMsgEditWindowPrivate *priv;
380 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
382 priv->msg_body = NULL;
383 priv->from_field = NULL;
384 priv->to_field = NULL;
385 priv->cc_field = NULL;
386 priv->bcc_field = NULL;
387 priv->subject_field = NULL;
388 priv->attachments = NULL;
391 priv->zoom_level = 1.0;
393 priv->cc_caption = NULL;
394 priv->bcc_caption = NULL;
395 priv->update_caption_visibility = FALSE;
397 priv->priority_flags = 0;
399 priv->find_toolbar = NULL;
400 priv->last_search = NULL;
402 priv->draft_msg = NULL;
403 priv->outbox_msg = NULL;
404 priv->msg_uid = NULL;
406 priv->can_undo = FALSE;
407 priv->can_redo = FALSE;
408 priv->clipboard_change_handler_id = 0;
409 priv->default_clipboard_change_handler_id = 0;
410 priv->account_removed_handler_id = 0;
411 priv->clipboard_text = NULL;
414 priv->last_vadj_upper = 0;
416 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
417 GTK_WINDOW(obj),"applications_email_editor");
422 /* FIXME: this is a dup from the one in gtk/ */
425 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
427 static ModestPairList*
428 get_transports (void)
430 GSList *transports = NULL;
432 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
433 GSList *accounts = modest_account_mgr_account_names (account_mgr,
434 TRUE /* only enabled accounts. */);
436 GSList *cursor = accounts;
438 gchar *account_name = cursor->data;
439 gchar *from_string = NULL;
441 from_string = modest_account_mgr_get_from_string (account_mgr,
445 if (from_string && account_name) {
446 gchar *name = account_name;
447 ModestPair *pair = modest_pair_new ((gpointer) name,
448 (gpointer) from_string , TRUE);
449 transports = g_slist_prepend (transports, pair);
452 cursor = cursor->next;
454 g_slist_free (accounts); /* only free the accounts, not the elements,
455 * because they are used in the pairlist */
459 void vadj_changed (GtkAdjustment *adj,
460 ModestMsgEditWindow *window)
462 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
464 GdkRectangle rectangle, cursor_rectangle;
465 GtkTextIter position;
469 /* We detect if cursor is visible using the full height, not only the center. This
471 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
472 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
474 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
475 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
477 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
478 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
480 if (gtk_widget_is_focus (priv->msg_body) &&
482 if (priv->last_vadj_upper != adj->upper) {
485 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
486 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
487 insert, 0.1, FALSE, 0.0, 0.0);
490 priv->last_vadj_upper = adj->upper;
495 connect_signals (ModestMsgEditWindow *obj)
497 ModestMsgEditWindowPrivate *priv;
499 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
501 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
502 G_CALLBACK (text_buffer_refresh_attributes), obj);
503 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
504 G_CALLBACK (text_buffer_can_undo), obj);
505 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
506 G_CALLBACK (text_buffer_can_redo), obj);
507 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
508 G_CALLBACK (body_changed), obj);
509 g_signal_connect (G_OBJECT (obj), "window-state-event",
510 G_CALLBACK (modest_msg_edit_window_window_state_event),
512 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
513 G_CALLBACK (text_buffer_apply_tag), obj);
514 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
515 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
516 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
517 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
518 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
519 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
521 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
522 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
524 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
525 G_CALLBACK (msg_body_focus), obj);
526 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
527 G_CALLBACK (msg_body_focus), obj);
528 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
529 "changed", G_CALLBACK (recpt_field_changed), obj);
530 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
531 "changed", G_CALLBACK (recpt_field_changed), obj);
532 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
533 "changed", G_CALLBACK (recpt_field_changed), obj);
534 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
535 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
536 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
538 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
539 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
541 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
543 G_CALLBACK (vadj_changed),
546 priv->clipboard_change_handler_id =
547 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
548 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
549 priv->default_clipboard_change_handler_id =
550 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
551 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
556 menubar_to_menu (GtkUIManager *ui_manager)
558 GtkWidget *main_menu;
560 /* Get the menubar from the UI manager */
561 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
567 init_window (ModestMsgEditWindow *obj)
569 GtkWidget *from_caption, *to_caption, *subject_caption;
570 GtkWidget *main_vbox;
571 ModestMsgEditWindowPrivate *priv;
572 GtkActionGroup *action_group;
573 ModestWindowPrivate *parent_priv;
574 GdkPixbuf *window_icon = NULL;
575 GError *error = NULL;
577 GtkSizeGroup *size_group;
579 GtkWidget *subject_box;
580 GtkWidget *attachment_icon;
581 GtkWidget *window_box;
582 #if (GTK_MINOR_VERSION >= 10)
583 GdkAtom deserialize_type;
585 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
586 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
588 parent_priv->ui_manager = gtk_ui_manager_new();
589 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
590 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
592 /* Add common actions */
593 gtk_action_group_add_actions (action_group,
594 modest_msg_edit_action_entries,
595 G_N_ELEMENTS (modest_msg_edit_action_entries),
597 gtk_action_group_add_toggle_actions (action_group,
598 modest_msg_edit_toggle_action_entries,
599 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
601 gtk_action_group_add_radio_actions (action_group,
602 modest_msg_edit_alignment_radio_action_entries,
603 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
605 G_CALLBACK (modest_ui_actions_on_change_justify),
607 gtk_action_group_add_radio_actions (action_group,
608 modest_msg_edit_zoom_action_entries,
609 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
611 G_CALLBACK (modest_ui_actions_on_change_zoom),
613 gtk_action_group_add_radio_actions (action_group,
614 modest_msg_edit_priority_action_entries,
615 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
617 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
619 gtk_action_group_add_radio_actions (action_group,
620 modest_msg_edit_file_format_action_entries,
621 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
622 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
623 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
625 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
626 g_object_unref (action_group);
628 /* Load the UI definition */
629 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
632 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
633 g_clear_error (&error);
636 /* Add accelerators */
637 gtk_window_add_accel_group (GTK_WINDOW (obj),
638 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
640 /* Menubar. Update the state of some toggles */
641 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
642 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
644 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
646 /* Note: This ModestPairList* must exist for as long as the combo
647 * that uses it, because the ModestComboBox uses the ID opaquely,
648 * so it can't know how to manage its memory. */
649 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
651 priv->to_field = modest_recpt_editor_new ();
652 priv->cc_field = modest_recpt_editor_new ();
653 priv->bcc_field = modest_recpt_editor_new ();
654 subject_box = gtk_hbox_new (FALSE, 0);
655 priv->priority_icon = gtk_image_new ();
656 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
657 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
658 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
659 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
660 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
661 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
662 priv->add_attachment_button = gtk_button_new ();
663 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
664 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
665 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
666 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
667 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
668 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
669 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
670 priv->attachments_view = modest_attachments_view_new (NULL);
672 priv->header_box = gtk_vbox_new (FALSE, 0);
674 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
675 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
676 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
677 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
678 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
679 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
680 g_object_unref (size_group);
682 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
683 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
684 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
685 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
686 gtk_size_group_add_widget (size_group, priv->subject_field);
687 gtk_size_group_add_widget (size_group, priv->attachments_view);
688 g_object_unref (size_group);
690 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
691 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
692 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
694 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
695 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
696 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
699 priv->msg_body = wp_text_view_new ();
700 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
701 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
702 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
703 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
704 #if (GTK_MINOR_VERSION >= 10)
705 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
706 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
708 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
709 deserialize_type, TRUE);
711 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
713 priv->find_toolbar = hildon_find_toolbar_new (NULL);
714 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
716 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
718 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
719 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
720 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
721 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
723 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
725 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
726 frame = gtk_frame_new (NULL);
727 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
729 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
730 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
731 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
733 G_CALLBACK (vadj_changed),
735 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
737 window_box = gtk_vbox_new (FALSE, 0);
738 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
739 gtk_container_add (GTK_CONTAINER(obj), window_box);
740 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
741 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
743 /* Set window icon */
744 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
746 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
747 g_object_unref (window_icon);
753 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
755 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
757 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
758 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
759 priv->clipboard_change_handler_id))
760 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
761 priv->clipboard_change_handler_id);
762 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
763 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
764 priv->default_clipboard_change_handler_id))
765 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
766 priv->default_clipboard_change_handler_id);
768 if (priv->account_removed_handler_id &&
769 g_signal_handler_is_connected (modest_runtime_get_account_store (),
770 priv->account_removed_handler_id))
771 g_signal_handler_disconnect(modest_runtime_get_account_store (),
772 priv->account_removed_handler_id);
776 modest_msg_edit_window_finalize (GObject *obj)
778 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
780 /* Sanity check: shouldn't be needed, the window mgr should
781 call this function before */
782 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
784 if (priv->clipboard_text != NULL) {
785 g_free (priv->clipboard_text);
786 priv->clipboard_text = NULL;
789 if (priv->draft_msg != NULL) {
790 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
791 if (TNY_IS_HEADER (header)) {
792 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
793 modest_window_mgr_unregister_header (mgr, header);
795 g_object_unref (priv->draft_msg);
796 priv->draft_msg = NULL;
798 if (priv->outbox_msg != NULL) {
799 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
800 if (TNY_IS_HEADER (header)) {
801 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
802 modest_window_mgr_unregister_header (mgr, header);
804 g_object_unref (priv->outbox_msg);
805 priv->outbox_msg = NULL;
807 if (priv->msg_uid != NULL) {
808 g_free (priv->msg_uid);
809 priv->msg_uid = NULL;
812 /* This had to stay alive for as long as the combobox that used it: */
813 modest_pair_list_free (priv->from_field_protos);
815 G_OBJECT_CLASS(parent_class)->finalize (obj);
819 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
821 GdkPixbufLoader *loader;
824 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
829 tny_stream_reset (TNY_STREAM (stream));
830 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
831 unsigned char read_buffer[128];
833 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
834 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
838 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
839 g_object_ref (pixbuf);
840 gdk_pixbuf_loader_close (loader, NULL);
841 g_object_unref (loader);
843 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
844 GdkPixbuf *new_pixbuf;
846 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
847 gdk_pixbuf_get_width (pixbuf);
848 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
849 g_object_unref (pixbuf);
857 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
859 ModestMsgEditWindowPrivate *priv;
862 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
864 for (node = attachments; node != NULL; node = g_list_next (node)) {
865 TnyMimePart *part = (TnyMimePart *) node->data;
866 const gchar *cid = tny_mime_part_get_content_id (part);
867 const gchar *mime_type = tny_mime_part_get_content_type (part);
868 if ((cid != NULL)&&(mime_type != NULL)) {
869 TnyStream *stream = tny_mime_part_get_stream (part);
870 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
871 g_object_unref (stream);
873 if (pixbuf != NULL) {
874 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
875 g_object_unref (pixbuf);
882 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
884 TnyMimePart *parent = NULL;
885 const gchar *content_type = NULL;
886 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
888 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
890 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
891 parent = g_object_ref (msg);
892 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
893 TnyList *parts = TNY_LIST (tny_simple_list_new ());
896 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
897 iter = tny_list_create_iterator (parts);
898 while (!tny_iterator_is_done (iter)) {
900 part = TNY_MIME_PART (tny_iterator_get_current (iter));
901 content_type = tny_mime_part_get_content_type (part);
902 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
906 g_object_unref (part);
908 tny_iterator_next (iter);
910 g_object_unref (iter);
911 g_object_unref (parts);
914 if (parent != NULL) {
915 TnyList *parts = TNY_LIST (tny_simple_list_new ());
918 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
919 iter = tny_list_create_iterator (parts);
920 while (!tny_iterator_is_done (iter)) {
922 part = TNY_MIME_PART (tny_iterator_get_current (iter));
923 content_type = tny_mime_part_get_content_type (part);
924 if (content_type && g_str_has_prefix (content_type, "image/")) {
925 priv->images = g_list_prepend (priv->images, part);
927 g_object_unref (part);
929 tny_iterator_next (iter);
931 g_object_unref (iter);
932 g_object_unref (parts);
933 g_object_unref (parent);
938 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
941 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
943 for (node = attachments; node != NULL; node = g_list_next (node)) {
944 TnyMimePart *part = (TnyMimePart *) node->data;
945 const gchar *cid = tny_mime_part_get_content_id (part);
947 char *invalid = NULL;
948 gint int_cid = strtol (cid, &invalid, 10);
949 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
950 priv->last_cid = int_cid;
958 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
961 const gchar *to, *cc, *bcc, *subject;
963 ModestMsgEditWindowPrivate *priv;
965 TnyHeaderFlags priority_flags;
966 TnyFolder *msg_folder;
967 gboolean is_html = FALSE;
969 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
970 g_return_if_fail (TNY_IS_MSG (msg));
972 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
974 header = tny_msg_get_header (msg);
975 to = tny_header_get_to (header);
976 cc = tny_header_get_cc (header);
977 bcc = tny_header_get_bcc (header);
978 subject = tny_header_get_subject (header);
979 priority_flags = tny_header_get_priority (header);
982 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
984 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
985 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
986 gtk_widget_show (priv->cc_caption);
987 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
988 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
989 gtk_widget_hide (priv->cc_caption);
992 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
993 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
994 gtk_widget_show (priv->bcc_caption);
995 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
996 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
997 gtk_widget_hide (priv->bcc_caption);
1000 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1001 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1004 update_window_title (self);
1006 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1007 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1009 if ((body == NULL)||(body[0] == '\0')) {
1011 body = modest_text_utils_convert_to_html ("");
1014 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1015 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1018 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1021 /* Add attachments to the view */
1022 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1023 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1024 if (priv->attachments == NULL) {
1025 gtk_widget_hide (priv->attachments_caption);
1027 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1028 gtk_widget_show_all (priv->attachments_caption);
1030 get_related_images (self, msg);
1031 update_last_cid (self, priv->attachments);
1032 update_last_cid (self, priv->images);
1033 replace_with_images (self, priv->images);
1035 if (preserve_is_rich && !is_html) {
1036 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1037 /* Get the default format required from configuration */
1038 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1039 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1042 /* Set the default focus depending on having already a To: field or not */
1043 if ((!to)||(*to == '\0')) {
1044 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1046 gtk_widget_grab_focus (priv->msg_body);
1049 /* TODO: lower priority, select in the From: combo to the
1050 value that comes from msg <- not sure, should it be
1053 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1055 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1056 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1058 modest_msg_edit_window_reset_modified (self);
1060 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1061 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1062 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1064 if (priv->msg_uid) {
1065 g_free (priv->msg_uid);
1066 priv->msg_uid = NULL;
1069 /* we should set a reference to the incoming message if it is a draft */
1070 msg_folder = tny_msg_get_folder (msg);
1072 if (modest_tny_folder_is_local_folder (msg_folder)) {
1073 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1074 if (type == TNY_FOLDER_TYPE_INVALID)
1075 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1077 if (type == TNY_FOLDER_TYPE_DRAFTS)
1078 priv->draft_msg = g_object_ref(msg);
1079 if (type == TNY_FOLDER_TYPE_OUTBOX)
1080 priv->outbox_msg = g_object_ref(msg);
1081 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1083 g_object_unref (msg_folder);
1088 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1091 GList *item_children, *node;
1092 GtkWidget *bin_child;
1094 bin_child = gtk_bin_get_child (GTK_BIN(item));
1096 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1098 for (node = item_children; node != NULL; node = g_list_next (node)) {
1099 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1100 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1103 g_list_free (item_children);
1107 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1110 GList *item_children, *node;
1112 box = gtk_bin_get_child (GTK_BIN (item));
1113 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1114 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1116 for (node = item_children; node != NULL; node = g_list_next (node)) {
1117 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1118 if (GTK_IS_TOGGLE_BUTTON (node->data))
1119 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1120 else if (GTK_IS_BUTTON (node->data))
1121 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1123 g_list_free (item_children);
1128 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1130 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1131 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1132 GtkWidget *placeholder;
1133 GtkWidget *tool_item;
1138 GtkWidget *sizes_menu;
1139 GtkWidget *fonts_menu;
1140 GSList *radio_group = NULL;
1141 GSList *node = NULL;
1145 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1146 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1148 /* Font color placeholder */
1149 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1150 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1153 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1154 priv->font_color_button = hildon_color_button_new ();
1155 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1156 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1157 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1158 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1159 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1160 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1161 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1163 G_CALLBACK (modest_msg_edit_window_color_button_change),
1166 /* Font size and face placeholder */
1167 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1168 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1170 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1171 priv->size_tool_button_label = gtk_label_new (NULL);
1172 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1173 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1174 size_text,"</span>", NULL);
1175 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1177 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1178 sizes_menu = gtk_menu_new ();
1179 priv->size_items_group = NULL;
1181 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1182 GtkWidget *size_menu_item;
1184 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1185 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1186 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1187 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1188 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1189 gtk_widget_show (size_menu_item);
1191 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1195 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1196 GtkWidget *item = (GtkWidget *) node->data;
1197 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1201 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1202 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1203 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1204 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1205 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1206 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1207 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1208 priv->font_size_toolitem = tool_item;
1211 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1212 priv->font_tool_button_label = gtk_label_new (NULL);
1213 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1214 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1216 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1217 fonts_menu = gtk_menu_new ();
1218 priv->font_items_group = NULL;
1220 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1221 GtkWidget *font_menu_item;
1222 GtkWidget *child_label;
1224 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1225 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1226 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1227 wp_get_font_name (font_index), "</span>", NULL);
1228 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1231 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1232 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1233 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1234 gtk_widget_show (font_menu_item);
1236 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1239 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1240 GtkWidget *item = (GtkWidget *) node->data;
1241 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1244 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1245 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1246 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1247 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1248 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1249 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1250 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1251 priv->font_face_toolitem = tool_item;
1253 /* Set expand and homogeneous for remaining items */
1254 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
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/ActionsBold");
1258 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1259 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1260 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1261 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1262 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1264 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1265 will not show the tool items added to the placeholders) */
1266 gtk_widget_show_all (parent_priv->toolbar);
1268 /* Set the no show all *after* showing all items. We do not
1269 want the toolbar to be shown with a show all because it
1270 could go agains the gconf setting regarding showing or not
1271 the toolbar of the editor window */
1272 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1278 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1281 ModestWindowPrivate *parent_priv;
1282 ModestMsgEditWindowPrivate *priv;
1283 ModestPair *account_pair = NULL;
1284 ModestDimmingRulesGroup *menu_rules_group = NULL;
1285 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1286 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1287 ModestWindowMgr *mgr = NULL;
1289 g_return_val_if_fail (msg, NULL);
1290 g_return_val_if_fail (account_name, NULL);
1292 mgr = modest_runtime_get_window_mgr ();
1294 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1296 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1297 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
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, (gpointer) (buffer_format->bold&0x1));
1626 if (buffer_format->cs.italic) {
1627 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1629 if (buffer_format->cs.color) {
1630 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1632 if (buffer_format->cs.font_size) {
1633 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1635 if (buffer_format->cs.justification) {
1636 switch (buffer_format->justification) {
1637 case GTK_JUSTIFY_LEFT:
1638 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1640 case GTK_JUSTIFY_CENTER:
1641 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1643 case GTK_JUSTIFY_RIGHT:
1644 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1651 if (buffer_format->cs.font) {
1652 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1654 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1655 if (buffer_format->cs.bullet) {
1656 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1658 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1660 g_free (current_format);
1665 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1667 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1669 ModestWindowPrivate *parent_priv;
1670 ModestMsgEditWindowPrivate *priv;
1671 GtkWidget *new_size_menuitem;
1672 GtkWidget *new_font_menuitem;
1674 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1675 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1677 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1678 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1679 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1680 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1682 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1683 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1684 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1687 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1689 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1690 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1692 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1693 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1695 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1696 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1698 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1699 G_CALLBACK (modest_msg_edit_window_color_button_change),
1701 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1702 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1703 G_CALLBACK (modest_msg_edit_window_color_button_change),
1706 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1707 buffer_format->font_size))->data);
1708 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1712 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1713 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1714 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1716 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1717 G_CALLBACK (modest_msg_edit_window_size_change),
1719 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1720 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1721 G_CALLBACK (modest_msg_edit_window_size_change),
1725 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1726 buffer_format->font))->data);
1727 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1731 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1732 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1733 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1735 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1736 G_CALLBACK (modest_msg_edit_window_font_change),
1738 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1739 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1740 G_CALLBACK (modest_msg_edit_window_font_change),
1744 g_free (buffer_format);
1748 #ifdef MODEST_HILDON_VERSION_0
1750 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1753 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1754 ModestMsgEditWindowPrivate *priv;
1755 GtkWidget *dialog = NULL;
1757 GdkColor *new_color = NULL;
1759 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1760 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1762 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1763 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1764 g_free (buffer_format);
1766 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1767 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1768 if (new_color != NULL) {
1769 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1770 (gpointer) new_color);
1773 gtk_widget_destroy (dialog);
1778 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1781 ModestMsgEditWindowPrivate *priv;
1782 GtkWidget *dialog = NULL;
1784 GdkColor *old_color = NULL;
1785 const GdkColor *new_color = NULL;
1787 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1788 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1790 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1791 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1793 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1794 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1795 if (new_color != NULL)
1796 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1798 gtk_widget_destroy (dialog);
1804 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1807 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1808 ModestMsgEditWindowPrivate *priv;
1809 GtkWidget *dialog = NULL;
1811 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1812 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1814 dialog = hildon_color_chooser_new ();
1815 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1816 g_free (buffer_format);
1818 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1820 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1821 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1824 gtk_widget_destroy (dialog);
1829 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1832 ModestMsgEditWindowPrivate *priv;
1833 GtkWidget *dialog = NULL;
1834 GdkColor *old_color = NULL;
1836 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1837 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1839 dialog = hildon_color_chooser_new ();
1840 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1842 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1844 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1845 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1847 gtk_widget_destroy (dialog);
1850 #endif /*!MODEST_HILDON_VERSION_0*/
1854 static TnyStream* create_stream_for_uri (const gchar* uri)
1859 TnyStream *result = NULL;
1861 GnomeVFSHandle *handle = NULL;
1862 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1863 if (test == GNOME_VFS_OK) {
1864 /* Create the tinymail stream: */
1865 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1866 result = TNY_STREAM (tny_vfs_stream_new (handle));
1873 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1876 ModestMsgEditWindowPrivate *priv;
1877 GtkWidget *dialog = NULL;
1879 GSList *uris = NULL;
1880 GSList *uri_node = NULL;
1882 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1884 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1885 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1886 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1888 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1890 response = gtk_dialog_run (GTK_DIALOG (dialog));
1892 case GTK_RESPONSE_OK:
1893 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1898 gtk_widget_destroy (dialog);
1900 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1902 GnomeVFSHandle *handle = NULL;
1903 GnomeVFSResult result;
1904 GtkTextIter position;
1905 GtkTextMark *insert_mark;
1907 uri = (const gchar *) uri_node->data;
1908 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1909 if (result == GNOME_VFS_OK) {
1911 GnomeVFSFileInfo info;
1912 gchar *filename, *basename, *escaped_filename;
1913 TnyMimePart *mime_part;
1915 const gchar *mime_type = NULL;
1916 GnomeVFSURI *vfs_uri;
1918 vfs_uri = gnome_vfs_uri_new (uri);
1920 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1921 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1922 g_free (escaped_filename);
1923 gnome_vfs_uri_unref (vfs_uri);
1925 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1926 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1928 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1930 mime_part = tny_platform_factory_new_mime_part
1931 (modest_runtime_get_platform_factory ());
1933 TnyStream *stream = create_stream_for_uri (uri);
1934 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1936 content_id = g_strdup_printf ("%d", priv->last_cid);
1937 tny_mime_part_set_content_id (mime_part, content_id);
1938 g_free (content_id);
1941 basename = g_path_get_basename (filename);
1942 tny_mime_part_set_filename (mime_part, basename);
1945 pixbuf = pixbuf_from_stream (stream, mime_type);
1947 if (pixbuf != NULL) {
1948 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1949 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1950 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1953 priv->images = g_list_prepend (priv->images, mime_part);
1954 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1964 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1966 GtkWidget *dialog = NULL;
1968 GSList *uris = NULL;
1971 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1972 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1973 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1975 response = gtk_dialog_run (GTK_DIALOG (dialog));
1977 case GTK_RESPONSE_OK:
1978 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1983 gtk_widget_destroy (dialog);
1985 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1986 const gchar *uri = (const gchar *) uri_node->data;
1987 modest_msg_edit_window_attach_file_one (window, uri);
1989 g_slist_foreach (uris, (GFunc) g_free, NULL);
1990 g_slist_free (uris);
1994 modest_msg_edit_window_attach_file_one (
1995 ModestMsgEditWindow *window,
1998 g_return_if_fail (window);
1999 g_return_if_fail (uri);
2001 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2004 GnomeVFSHandle *handle = NULL;
2005 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2006 if (result == GNOME_VFS_OK) {
2007 TnyMimePart *mime_part;
2009 const gchar *mime_type = NULL;
2011 gchar *escaped_filename;
2014 GnomeVFSFileInfo info;
2015 GnomeVFSURI *vfs_uri;
2017 vfs_uri = gnome_vfs_uri_new (uri);
2020 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2021 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2022 g_free (escaped_filename);
2023 gnome_vfs_uri_unref (vfs_uri);
2025 if (gnome_vfs_get_file_info (uri,
2027 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2028 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2030 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2031 mime_part = tny_platform_factory_new_mime_part
2032 (modest_runtime_get_platform_factory ());
2033 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2035 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2037 content_id = g_strdup_printf ("%d", priv->last_cid);
2038 tny_mime_part_set_content_id (mime_part, content_id);
2039 g_free (content_id);
2042 basename = g_path_get_basename (filename);
2043 tny_mime_part_set_filename (mime_part, basename);
2046 priv->attachments = g_list_prepend (priv->attachments, mime_part);
2047 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2049 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2050 gtk_widget_show_all (priv->attachments_caption);
2051 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2057 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2060 ModestMsgEditWindowPrivate *priv;
2061 gboolean clean_list = FALSE;
2063 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2064 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2066 if (att_list == NULL) {
2067 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2071 if (att_list == NULL) {
2072 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2074 GtkWidget *confirmation_dialog = NULL;
2075 gboolean dialog_response;
2077 gchar *message = NULL;
2078 gchar *filename = NULL;
2080 if (att_list->next == NULL) {
2081 if (TNY_IS_MSG (att_list->data)) {
2082 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2084 filename = g_strdup (tny_header_get_subject (header));
2085 g_object_unref (header);
2087 if (filename == NULL) {
2088 filename = g_strdup (_("mail_va_no_subject"));
2091 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2094 filename = g_strdup ("");
2096 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2097 att_list->next == NULL), filename);
2099 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2101 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2102 gtk_widget_destroy (confirmation_dialog);
2103 if (!dialog_response) {
2105 g_list_free (att_list);
2108 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2110 for (node = att_list; node != NULL; node = g_list_next (node)) {
2111 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2112 const gchar *att_id;
2113 priv->attachments = g_list_remove (priv->attachments, mime_part);
2115 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2117 if (priv->attachments == NULL)
2118 gtk_widget_hide (priv->attachments_caption);
2119 att_id = tny_mime_part_get_content_id (mime_part);
2121 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2123 g_object_unref (mime_part);
2124 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2129 g_list_free (att_list);
2133 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2136 ModestMsgEditWindowPrivate *priv;
2137 GdkColor *new_color;
2138 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2140 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2141 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2144 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2146 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2148 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2150 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2155 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2158 ModestMsgEditWindowPrivate *priv;
2159 gint new_size_index;
2160 ModestMsgEditWindow *window;
2163 window = MODEST_MSG_EDIT_WINDOW (userdata);
2164 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2165 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2167 if (gtk_check_menu_item_get_active (menu_item)) {
2169 WPTextBufferFormat format;
2171 memset (&format, 0, sizeof (format));
2172 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2174 label = gtk_bin_get_child (GTK_BIN (menu_item));
2176 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2177 format.cs.font_size = TRUE;
2178 format.cs.text_position = TRUE;
2179 format.cs.font = TRUE;
2180 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2181 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2183 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2184 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2185 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2187 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2188 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2189 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2195 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2198 ModestMsgEditWindowPrivate *priv;
2199 gint new_font_index;
2200 ModestMsgEditWindow *window;
2203 window = MODEST_MSG_EDIT_WINDOW (userdata);
2204 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2205 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2207 if (gtk_check_menu_item_get_active (menu_item)) {
2210 label = gtk_bin_get_child (GTK_BIN (menu_item));
2212 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2214 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2215 (gpointer) new_font_index))
2216 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2218 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2219 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2220 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2226 modest_msg_edit_window_set_zoom (ModestWindow *window,
2229 ModestMsgEditWindowPrivate *priv;
2230 ModestWindowPrivate *parent_priv;
2231 GtkRadioAction *zoom_radio_action;
2233 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2235 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2236 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2237 priv->zoom_level = zoom;
2238 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2240 /* Zoom level menu options should be updated with the current zoom level */
2241 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2242 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2243 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2244 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2245 /* FIXME: Not availible before Gtk 2.10 */
2247 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2252 modest_msg_edit_window_get_zoom (ModestWindow *window)
2254 ModestMsgEditWindowPrivate *priv;
2256 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2258 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2259 return priv->zoom_level;
2263 zoom_allowed (ModestMsgEditWindow *window)
2267 focus = gtk_window_get_focus (GTK_WINDOW (window));
2268 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2272 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2274 ModestWindowPrivate *parent_priv;
2275 GtkRadioAction *zoom_radio_action;
2276 GSList *group, *node;
2278 /* First we check if the text view is focused. If not, zooming is not allowed */
2279 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2280 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2284 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2285 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2286 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2288 group = gtk_radio_action_get_group (zoom_radio_action);
2290 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2291 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2295 for (node = group; node != NULL; node = g_slist_next (node)) {
2296 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2297 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2305 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2307 ModestWindowPrivate *parent_priv;
2308 GtkRadioAction *zoom_radio_action;
2309 GSList *group, *node;
2311 /* First we check if the text view is focused. If not, zooming is not allowed */
2312 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2313 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2317 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2318 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2319 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2321 group = gtk_radio_action_get_group (zoom_radio_action);
2323 for (node = group; node != NULL; node = g_slist_next (node)) {
2324 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2325 if (node->next != NULL) {
2326 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2329 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2337 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2339 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2340 ModestWindowPrivate *parent_priv;
2341 ModestWindowMgr *mgr;
2342 gboolean is_fullscreen;
2343 GtkAction *fs_toggle_action;
2346 mgr = modest_runtime_get_window_mgr ();
2347 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2349 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2351 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2352 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2353 if (is_fullscreen != active)
2354 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2362 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2365 ModestMsgEditWindowPrivate *priv = NULL;
2366 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2368 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2369 if (!priv->update_caption_visibility)
2372 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2374 gtk_widget_show (priv->cc_caption);
2376 gtk_widget_hide (priv->cc_caption);
2378 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2382 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2385 ModestMsgEditWindowPrivate *priv = NULL;
2386 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2388 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2389 if (!priv->update_caption_visibility)
2392 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2394 gtk_widget_show (priv->bcc_caption);
2396 gtk_widget_hide (priv->bcc_caption);
2398 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2402 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2403 ModestRecptEditor *editor)
2405 ModestMsgEditWindowPrivate *priv;
2407 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2408 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2409 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2411 if (editor == NULL) {
2412 GtkWidget *view_focus;
2413 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2415 /* This code should be kept in sync with ModestRecptEditor. The
2416 textview inside the recpt editor is the one that really gets the
2417 focus. As it's inside a scrolled window, and this one inside the
2418 hbox recpt editor inherits from, we'll need to go up in the
2419 hierarchy to know if the text view is part of the recpt editor
2420 or if it's a different text entry */
2422 if (gtk_widget_get_parent (view_focus)) {
2423 GtkWidget *first_parent;
2425 first_parent = gtk_widget_get_parent (view_focus);
2426 if (gtk_widget_get_parent (first_parent) &&
2427 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2428 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2433 editor = MODEST_RECPT_EDITOR (priv->to_field);
2437 modest_address_book_select_addresses (editor);
2442 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2444 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2446 modest_msg_edit_window_open_addressbook (window, NULL);
2450 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2451 gboolean show_toolbar)
2453 ModestWindowPrivate *parent_priv;
2454 const gchar *action_name;
2457 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2458 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2460 /* We can not just use the code of
2461 modest_msg_edit_window_setup_toolbar because it has a
2462 mixture of both initialization and creation code. */
2464 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2466 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2468 /* Update also the actions (to update the toggles in the
2469 menus), we have to do it manually because some other window
2470 of the same time could have changed it (remember that the
2471 toolbar fullscreen mode is shared by all the windows of the
2473 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2474 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2476 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2478 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2479 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2485 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2486 TnyHeaderFlags priority_flags)
2488 ModestMsgEditWindowPrivate *priv;
2489 ModestWindowPrivate *parent_priv;
2491 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2493 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2494 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2496 if (priv->priority_flags != priority_flags) {
2497 GtkAction *priority_action = NULL;
2499 priv->priority_flags = priority_flags;
2501 switch (priority_flags) {
2502 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2503 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2504 gtk_widget_show (priv->priority_icon);
2505 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2506 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2508 case TNY_HEADER_FLAG_LOW_PRIORITY:
2509 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2510 gtk_widget_show (priv->priority_icon);
2511 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2512 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2515 gtk_widget_hide (priv->priority_icon);
2516 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2517 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2520 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2521 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2526 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2529 ModestMsgEditWindowPrivate *priv;
2530 ModestWindowPrivate *parent_priv;
2531 gint current_format;
2533 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2535 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2536 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2538 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2539 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2541 if (current_format != file_format) {
2542 switch (file_format) {
2543 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2544 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2545 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2547 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2551 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2552 response = gtk_dialog_run (GTK_DIALOG (dialog));
2553 gtk_widget_destroy (dialog);
2554 if (response == GTK_RESPONSE_OK) {
2555 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2557 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2558 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2563 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2568 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2571 ModestMsgEditWindowPrivate *priv;
2572 WPTextBufferFormat oldfmt, fmt;
2573 gint old_position = 0;
2577 GdkColor *color = NULL;
2578 gboolean bold, bold_set, italic, italic_set;
2579 gboolean underline, underline_set;
2580 gboolean strikethrough, strikethrough_set;
2581 gboolean position_set;
2582 gboolean font_size_set, font_set, color_set;
2585 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2586 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2588 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2590 /* First we get the currently selected font information */
2591 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2592 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2594 switch (oldfmt.text_position) {
2595 case TEXT_POSITION_NORMAL:
2598 case TEXT_POSITION_SUPERSCRIPT:
2606 g_object_set (G_OBJECT (dialog),
2607 "bold", oldfmt.bold != FALSE,
2608 "bold-set", !oldfmt.cs.bold,
2609 "underline", oldfmt.underline != FALSE,
2610 "underline-set", !oldfmt.cs.underline,
2611 "italic", oldfmt.italic != FALSE,
2612 "italic-set", !oldfmt.cs.italic,
2613 "strikethrough", oldfmt.strikethrough != FALSE,
2614 "strikethrough-set", !oldfmt.cs.strikethrough,
2615 "color", &oldfmt.color,
2616 "color-set", !oldfmt.cs.color,
2617 "size", wp_font_size[oldfmt.font_size],
2618 "size-set", !oldfmt.cs.font_size,
2619 "position", old_position,
2620 "position-set", !oldfmt.cs.text_position,
2621 "family", wp_get_font_name (oldfmt.font),
2622 "family-set", !oldfmt.cs.font,
2625 gtk_widget_show_all (dialog);
2626 response = gtk_dialog_run (GTK_DIALOG (dialog));
2627 if (response == GTK_RESPONSE_OK) {
2629 g_object_get( dialog,
2631 "bold-set", &bold_set,
2632 "underline", &underline,
2633 "underline-set", &underline_set,
2635 "italic-set", &italic_set,
2636 "strikethrough", &strikethrough,
2637 "strikethrough-set", &strikethrough_set,
2639 "color-set", &color_set,
2641 "size-set", &font_size_set,
2642 "family", &font_name,
2643 "family-set", &font_set,
2644 "position", &position,
2645 "position-set", &position_set,
2650 if (response == GTK_RESPONSE_OK) {
2651 memset(&fmt, 0, sizeof(fmt));
2657 fmt.italic = italic;
2658 fmt.cs.italic = TRUE;
2660 if (underline_set) {
2661 fmt.underline = underline;
2662 fmt.cs.underline = TRUE;
2664 if (strikethrough_set) {
2665 fmt.strikethrough = strikethrough;
2666 fmt.cs.strikethrough = TRUE;
2671 ? TEXT_POSITION_NORMAL
2672 : ( ( position == 1 )
2673 ? TEXT_POSITION_SUPERSCRIPT
2674 : TEXT_POSITION_SUBSCRIPT );
2675 fmt.cs.text_position = TRUE;
2679 fmt.cs.color = TRUE;
2682 fmt.font = wp_get_font_index(font_name,
2687 if (font_size_set) {
2688 fmt.font_size = wp_get_font_size_index(
2689 font_size, DEFAULT_FONT_SIZE);
2690 fmt.cs.font_size = TRUE;
2692 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2693 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2695 gtk_widget_destroy (dialog);
2697 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2701 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2703 ModestMsgEditWindowPrivate *priv;
2705 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2706 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2708 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2710 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2715 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2717 ModestMsgEditWindowPrivate *priv;
2719 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2720 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2722 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2724 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2729 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2731 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2733 priv->can_undo = can_undo;
2737 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2739 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2741 priv->can_redo = can_redo;
2745 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2747 ModestMsgEditWindowPrivate *priv;
2748 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2749 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2751 return priv->can_undo;
2755 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2757 ModestMsgEditWindowPrivate *priv;
2758 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2759 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2761 return priv->can_redo;
2766 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2769 GtkTextIter match_start, match_end;
2771 if (image_id == NULL)
2774 gtk_text_buffer_get_start_iter (buffer, &iter);
2776 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2777 GSList *tags = gtk_text_iter_get_tags (&match_start);
2779 for (node = tags; node != NULL; node = g_slist_next (node)) {
2780 GtkTextTag *tag = (GtkTextTag *) node->data;
2781 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2782 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2783 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2785 offset = gtk_text_iter_get_offset (&match_start);
2786 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2787 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2791 gtk_text_iter_forward_char (&iter);
2796 message_is_empty (ModestMsgEditWindow *window)
2798 ModestMsgEditWindowPrivate *priv = NULL;
2800 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2801 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2803 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2804 * so we can ignore markup.
2806 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2809 count = gtk_text_buffer_get_char_count (buf);
2815 msg_body_focus (GtkWidget *focus,
2816 GdkEventFocus *event,
2820 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2825 recpt_field_changed (GtkTextBuffer *buffer,
2826 ModestMsgEditWindow *editor)
2828 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2832 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2834 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2838 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2840 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2841 GtkTextBuffer *buffer;
2843 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2844 gtk_text_buffer_set_modified (buffer, FALSE);
2845 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2846 gtk_text_buffer_set_modified (buffer, FALSE);
2847 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2848 gtk_text_buffer_set_modified (buffer, FALSE);
2849 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2853 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2855 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2856 GtkTextBuffer *buffer;
2858 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2859 if (gtk_text_buffer_get_modified (buffer))
2861 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2862 if (gtk_text_buffer_get_modified (buffer))
2864 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2865 if (gtk_text_buffer_get_modified (buffer))
2867 if (gtk_text_buffer_get_modified (priv->text_buffer))
2877 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2879 ModestMsgEditWindowPrivate *priv = NULL;
2881 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2882 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2884 /* check if there's no recipient added */
2885 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2886 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2887 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2888 /* no recipient contents, then select contacts */
2889 modest_msg_edit_window_open_addressbook (window, NULL);
2893 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2894 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2897 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2898 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2901 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2902 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2906 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2907 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2908 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2915 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2916 ModestMsgEditWindow *window)
2918 modest_msg_edit_window_offer_attach_file (window);
2922 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2924 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2926 return priv->clipboard_text;
2930 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2932 ModestMsgEditWindow *window)
2934 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2935 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2937 if (!GTK_WIDGET_VISIBLE (window))
2940 text = gtk_clipboard_wait_for_text (selection_clipboard);
2942 if (priv->clipboard_text != NULL) {
2943 g_free (priv->clipboard_text);
2945 priv->clipboard_text = text;
2947 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2950 subject_field_move_cursor (GtkEntry *entry,
2951 GtkMovementStep step,
2956 if (!GTK_WIDGET_VISIBLE (window))
2959 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2963 update_window_title (ModestMsgEditWindow *window)
2965 ModestMsgEditWindowPrivate *priv = NULL;
2966 const gchar *subject;
2968 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2969 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2970 if (subject == NULL || subject[0] == '\0')
2971 subject = _("mail_va_new_email");
2973 gtk_window_set_title (GTK_WINDOW (window), subject);
2978 subject_field_changed (GtkEditable *editable,
2979 ModestMsgEditWindow *window)
2981 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2982 update_window_title (window);
2983 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2984 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2988 subject_field_insert_text (GtkEditable *editable,
2990 gint new_text_length,
2992 ModestMsgEditWindow *window)
2994 GString *result = g_string_new ("");
2996 gint result_len = 0;
2997 const gchar *entry_text = NULL;
3000 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3001 old_length = g_utf8_strlen (entry_text, -1);
3003 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3004 gunichar c = g_utf8_get_char_validated (current, 8);
3005 /* Invalid unichar, stop */
3011 result = g_string_append_unichar (result, c);
3015 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3016 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3019 /* Prevent endless recursion */
3020 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3021 g_signal_emit_by_name (editable, "insert-text",
3022 (gpointer) result->str, (gpointer) result->len,
3023 (gpointer) position, (gpointer) window);
3024 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3028 if (result_len + old_length > 1000) {
3029 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3030 dgettext("hildon-common-strings",
3031 "ckdg_ib_maximum_characters_reached"));
3034 g_string_free (result, TRUE);
3038 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3041 ModestMsgEditWindowPrivate *priv = NULL;
3043 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3044 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3046 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3049 gtk_widget_show_all (priv->find_toolbar);
3050 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3052 gtk_widget_hide_all (priv->find_toolbar);
3053 gtk_widget_grab_focus (priv->msg_body);
3059 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3061 GtkTextIter *match_start,
3062 GtkTextIter *match_end)
3064 GtkTextIter end_iter;
3065 gchar *str_casefold;
3068 gchar *range_casefold;
3071 gboolean result = FALSE;
3078 gtk_text_iter_forward_to_end (&end_iter);
3080 str_casefold = g_utf8_casefold (str, -1);
3081 str_chars_n = strlen (str);
3083 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3084 range_casefold = g_utf8_casefold (range_text, -1);
3085 range_chars_n = strlen (range_casefold);
3087 if (range_chars_n < str_chars_n) {
3088 g_free (str_casefold);
3089 g_free (range_text);
3090 g_free (range_casefold);
3094 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3095 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3096 if (!g_utf8_collate (range_subtext, str_casefold)) {
3097 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3099 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3100 match_start, match_end, NULL);
3101 g_free (found_text);
3103 g_free (range_subtext);
3107 g_free (str_casefold);
3108 g_free (range_text);
3109 g_free (range_casefold);
3116 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3117 ModestMsgEditWindow *window)
3119 gchar *current_search = NULL;
3120 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3122 GtkTextIter selection_start, selection_end;
3123 GtkTextIter match_start, match_end;
3124 gboolean continue_search = FALSE;
3126 if (message_is_empty (window)) {
3127 g_free (priv->last_search);
3128 priv->last_search = NULL;
3129 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3133 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3134 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3135 g_free (current_search);
3136 g_free (priv->last_search);
3137 priv->last_search = NULL;
3138 /* Information banner about empty search */
3139 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3143 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3144 continue_search = TRUE;
3146 g_free (priv->last_search);
3147 priv->last_search = g_strdup (current_search);
3150 if (continue_search) {
3151 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3152 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3153 &match_start, &match_end);
3155 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3157 GtkTextIter buffer_start;
3158 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3159 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3160 &match_start, &match_end);
3162 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3165 /* Mark as selected the string found in search */
3167 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3168 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3170 g_free (priv->last_search);
3171 priv->last_search = NULL;
3173 g_free (current_search);
3177 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3178 ModestMsgEditWindow *window)
3180 GtkToggleAction *toggle;
3181 ModestWindowPrivate *parent_priv;
3182 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3184 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3185 gtk_toggle_action_set_active (toggle, FALSE);
3189 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3191 ModestMsgEditWindowPrivate *priv;
3193 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3198 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3201 ModestMsgEditWindowPrivate *priv;
3203 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3209 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3212 ModestMsgEditWindowPrivate *priv;
3213 TnyHeader *header = NULL;
3215 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3216 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3218 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3219 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3221 if (priv->draft_msg != NULL) {
3222 g_object_unref (priv->draft_msg);
3225 if (draft != NULL) {
3226 g_object_ref (draft);
3227 header = tny_msg_get_header (draft);
3228 if (priv->msg_uid) {
3229 g_free (priv->msg_uid);
3230 priv->msg_uid = NULL;
3232 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3233 if (GTK_WIDGET_REALIZED (window))
3234 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3237 priv->draft_msg = draft;
3241 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3242 GtkTextIter *start, GtkTextIter *end,
3245 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3246 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3249 if (tag == NULL+13) return;
3250 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3251 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3252 replace_with_images (window, priv->images);
3257 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3260 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3262 g_return_if_fail (TNY_IS_MIME_PART (part));
3263 priv->attachments = g_list_prepend (priv->attachments, part);
3264 g_object_ref (part);
3265 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3266 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3267 gtk_widget_show_all (priv->attachments_caption);
3268 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3272 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3274 ModestMsgEditWindowPrivate *priv;
3276 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3277 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3279 return priv->msg_uid;
3283 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3284 ModestMsgEditWindowWidgetType widget_type)
3286 ModestMsgEditWindowPrivate *priv;
3288 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3289 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3291 switch (widget_type) {
3292 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3293 return priv->msg_body;
3295 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3296 return priv->to_field;
3298 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3299 return priv->cc_field;
3301 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3302 return priv->bcc_field;
3304 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3305 return priv->subject_field;
3307 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3308 return priv->attachments_view;
3316 remove_tags (WPTextBuffer *buffer)
3318 GtkTextIter start, end;
3320 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3321 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3323 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3327 on_account_removed (TnyAccountStore *account_store,
3328 TnyAccount *account,
3331 /* Do nothing if it's a store account, because we use the
3332 transport to send the messages */
3333 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3334 const gchar *parent_acc = NULL;
3335 const gchar *our_acc = NULL;
3337 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3338 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3339 /* Close this window if I'm showing a message of the removed account */
3340 if (strcmp (parent_acc, our_acc) == 0)
3341 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));