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 g_free (priv->msg_uid);
808 g_free (priv->last_search);
809 g_slist_free (priv->font_items_group);
810 g_slist_free (priv->size_items_group);
811 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
812 g_list_free (priv->attachments);
813 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
814 g_list_free (priv->images);
816 /* This had to stay alive for as long as the combobox that used it: */
817 modest_pair_list_free (priv->from_field_protos);
819 G_OBJECT_CLASS(parent_class)->finalize (obj);
823 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
825 GdkPixbufLoader *loader;
828 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
833 tny_stream_reset (TNY_STREAM (stream));
834 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
835 unsigned char read_buffer[128];
837 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
838 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
842 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
843 g_object_ref (pixbuf);
844 gdk_pixbuf_loader_close (loader, NULL);
845 g_object_unref (loader);
847 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
848 GdkPixbuf *new_pixbuf;
850 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
851 gdk_pixbuf_get_width (pixbuf);
852 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
853 g_object_unref (pixbuf);
861 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
863 ModestMsgEditWindowPrivate *priv;
866 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
868 for (node = attachments; node != NULL; node = g_list_next (node)) {
869 TnyMimePart *part = (TnyMimePart *) node->data;
870 const gchar *cid = tny_mime_part_get_content_id (part);
871 const gchar *mime_type = tny_mime_part_get_content_type (part);
872 if ((cid != NULL)&&(mime_type != NULL)) {
873 TnyStream *stream = tny_mime_part_get_stream (part);
874 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
875 g_object_unref (stream);
877 if (pixbuf != NULL) {
878 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
879 g_object_unref (pixbuf);
886 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
888 TnyMimePart *parent = NULL;
889 const gchar *content_type = NULL;
890 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
892 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
894 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
895 parent = g_object_ref (msg);
896 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
897 TnyList *parts = TNY_LIST (tny_simple_list_new ());
900 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
901 iter = tny_list_create_iterator (parts);
902 while (!tny_iterator_is_done (iter)) {
904 part = TNY_MIME_PART (tny_iterator_get_current (iter));
905 content_type = tny_mime_part_get_content_type (part);
906 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
910 g_object_unref (part);
912 tny_iterator_next (iter);
914 g_object_unref (iter);
915 g_object_unref (parts);
918 if (parent != NULL) {
919 TnyList *parts = TNY_LIST (tny_simple_list_new ());
922 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
923 iter = tny_list_create_iterator (parts);
924 while (!tny_iterator_is_done (iter)) {
926 part = TNY_MIME_PART (tny_iterator_get_current (iter));
927 content_type = tny_mime_part_get_content_type (part);
928 if (content_type && g_str_has_prefix (content_type, "image/")) {
929 priv->images = g_list_prepend (priv->images, part);
931 g_object_unref (part);
933 tny_iterator_next (iter);
935 g_object_unref (iter);
936 g_object_unref (parts);
937 g_object_unref (parent);
942 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
945 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
947 for (node = attachments; node != NULL; node = g_list_next (node)) {
948 TnyMimePart *part = (TnyMimePart *) node->data;
949 const gchar *cid = tny_mime_part_get_content_id (part);
951 char *invalid = NULL;
952 gint int_cid = strtol (cid, &invalid, 10);
953 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
954 priv->last_cid = int_cid;
962 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
965 const gchar *to, *cc, *bcc, *subject;
967 ModestMsgEditWindowPrivate *priv;
969 TnyHeaderFlags priority_flags;
970 TnyFolder *msg_folder;
971 gboolean is_html = FALSE;
973 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
974 g_return_if_fail (TNY_IS_MSG (msg));
976 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
978 header = tny_msg_get_header (msg);
979 to = tny_header_get_to (header);
980 cc = tny_header_get_cc (header);
981 bcc = tny_header_get_bcc (header);
982 subject = tny_header_get_subject (header);
983 priority_flags = tny_header_get_priority (header);
986 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
988 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
989 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
990 gtk_widget_show (priv->cc_caption);
991 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
992 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
993 gtk_widget_hide (priv->cc_caption);
996 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
997 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
998 gtk_widget_show (priv->bcc_caption);
999 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1000 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1001 gtk_widget_hide (priv->bcc_caption);
1004 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1005 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1008 update_window_title (self);
1010 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1011 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1013 if ((body == NULL)||(body[0] == '\0')) {
1015 body = modest_text_utils_convert_to_html ("");
1018 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1019 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1022 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1025 /* Add attachments to the view */
1026 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1027 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1028 if (priv->attachments == NULL) {
1029 gtk_widget_hide (priv->attachments_caption);
1031 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1032 gtk_widget_show_all (priv->attachments_caption);
1034 get_related_images (self, msg);
1035 update_last_cid (self, priv->attachments);
1036 update_last_cid (self, priv->images);
1037 replace_with_images (self, priv->images);
1039 if (preserve_is_rich && !is_html) {
1040 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1041 /* Get the default format required from configuration */
1042 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1043 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1046 /* Set the default focus depending on having already a To: field or not */
1047 if ((!to)||(*to == '\0')) {
1048 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1050 gtk_widget_grab_focus (priv->msg_body);
1053 /* TODO: lower priority, select in the From: combo to the
1054 value that comes from msg <- not sure, should it be
1057 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1059 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1060 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1062 modest_msg_edit_window_reset_modified (self);
1064 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1065 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1066 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1068 if (priv->msg_uid) {
1069 g_free (priv->msg_uid);
1070 priv->msg_uid = NULL;
1073 /* we should set a reference to the incoming message if it is a draft */
1074 msg_folder = tny_msg_get_folder (msg);
1076 if (modest_tny_folder_is_local_folder (msg_folder)) {
1077 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1078 if (type == TNY_FOLDER_TYPE_INVALID)
1079 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1081 if (type == TNY_FOLDER_TYPE_DRAFTS)
1082 priv->draft_msg = g_object_ref(msg);
1083 if (type == TNY_FOLDER_TYPE_OUTBOX)
1084 priv->outbox_msg = g_object_ref(msg);
1085 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1087 g_object_unref (msg_folder);
1092 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1095 GList *item_children, *node;
1096 GtkWidget *bin_child;
1098 bin_child = gtk_bin_get_child (GTK_BIN(item));
1100 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1102 for (node = item_children; node != NULL; node = g_list_next (node)) {
1103 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1104 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1107 g_list_free (item_children);
1111 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1114 GList *item_children, *node;
1116 box = gtk_bin_get_child (GTK_BIN (item));
1117 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1118 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1120 for (node = item_children; node != NULL; node = g_list_next (node)) {
1121 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1122 if (GTK_IS_TOGGLE_BUTTON (node->data))
1123 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1124 else if (GTK_IS_BUTTON (node->data))
1125 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1127 g_list_free (item_children);
1132 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1134 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1135 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1136 GtkWidget *placeholder;
1137 GtkWidget *tool_item;
1142 GtkWidget *sizes_menu;
1143 GtkWidget *fonts_menu;
1144 GSList *radio_group = NULL;
1145 GSList *node = NULL;
1149 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1150 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1152 /* Font color placeholder */
1153 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1154 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1157 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1158 priv->font_color_button = hildon_color_button_new ();
1159 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1160 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1161 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1162 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1163 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1164 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1165 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1167 G_CALLBACK (modest_msg_edit_window_color_button_change),
1170 /* Font size and face placeholder */
1171 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1172 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1174 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1175 priv->size_tool_button_label = gtk_label_new (NULL);
1176 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1177 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1178 size_text,"</span>", NULL);
1179 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1181 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1182 sizes_menu = gtk_menu_new ();
1183 priv->size_items_group = NULL;
1185 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1186 GtkWidget *size_menu_item;
1188 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1189 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1190 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1191 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1192 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1193 gtk_widget_show (size_menu_item);
1195 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1199 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1200 GtkWidget *item = (GtkWidget *) node->data;
1201 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1205 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1206 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1207 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1208 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1209 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1210 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1211 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1212 priv->font_size_toolitem = tool_item;
1215 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1216 priv->font_tool_button_label = gtk_label_new (NULL);
1217 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1218 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1220 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1221 fonts_menu = gtk_menu_new ();
1222 priv->font_items_group = NULL;
1224 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1225 GtkWidget *font_menu_item;
1226 GtkWidget *child_label;
1228 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1229 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1230 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1231 wp_get_font_name (font_index), "</span>", NULL);
1232 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1235 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1236 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1237 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1238 gtk_widget_show (font_menu_item);
1240 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1243 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1244 GtkWidget *item = (GtkWidget *) node->data;
1245 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1248 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1249 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1250 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1251 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1252 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1253 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1254 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1255 priv->font_face_toolitem = tool_item;
1257 /* Set expand and homogeneous for remaining items */
1258 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1259 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1260 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1261 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1262 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1263 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1264 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1265 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1266 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1268 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1269 will not show the tool items added to the placeholders) */
1270 gtk_widget_show_all (parent_priv->toolbar);
1272 /* Set the no show all *after* showing all items. We do not
1273 want the toolbar to be shown with a show all because it
1274 could go agains the gconf setting regarding showing or not
1275 the toolbar of the editor window */
1276 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1282 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1285 ModestWindowPrivate *parent_priv;
1286 ModestMsgEditWindowPrivate *priv;
1287 ModestPair *account_pair = NULL;
1288 ModestDimmingRulesGroup *menu_rules_group = NULL;
1289 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1290 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1291 ModestWindowMgr *mgr = NULL;
1293 g_return_val_if_fail (msg, NULL);
1294 g_return_val_if_fail (account_name, NULL);
1296 mgr = modest_runtime_get_window_mgr ();
1298 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1300 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1301 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1303 priv->from_field_protos = get_transports ();
1304 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1305 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1306 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1309 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1311 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1313 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1315 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1316 if (account_pair != NULL)
1317 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1319 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1320 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1321 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1322 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1323 /* Add common dimming rules */
1324 modest_dimming_rules_group_add_rules (menu_rules_group,
1325 modest_msg_edit_window_menu_dimming_entries,
1326 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1327 MODEST_WINDOW (obj));
1328 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1329 modest_msg_edit_window_toolbar_dimming_entries,
1330 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1331 MODEST_WINDOW (obj));
1332 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1333 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1334 MODEST_WINDOW (obj));
1335 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1336 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1337 MODEST_WINDOW (obj));
1338 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1339 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1340 MODEST_WINDOW (obj));
1341 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1342 modest_msg_edit_window_clipboard_dimming_entries,
1343 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1344 MODEST_WINDOW (obj));
1345 /* Insert dimming rules group for this window */
1346 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1347 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1348 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1349 /* Checks the dimming rules */
1350 g_object_unref (menu_rules_group);
1351 g_object_unref (toolbar_rules_group);
1352 g_object_unref (clipboard_rules_group);
1354 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1356 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1358 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1359 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1360 priv->update_caption_visibility = TRUE;
1362 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1364 /* Track account-removed signal, this window should be closed
1365 in the case we're creating a mail associated to the account
1367 priv->account_removed_handler_id =
1368 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1370 G_CALLBACK(on_account_removed),
1373 return (ModestWindow*) obj;
1377 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1379 GString **string_buffer = (GString **) user_data;
1381 *string_buffer = g_string_append (*string_buffer, buffer);
1387 * @result: A new string which should be freed with g_free().
1390 get_formatted_data (ModestMsgEditWindow *edit_window)
1392 ModestMsgEditWindowPrivate *priv;
1393 GString *string_buffer = g_string_new ("");
1395 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1397 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1399 return g_string_free (string_buffer, FALSE);
1404 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1407 const gchar *account_name;
1408 ModestMsgEditWindowPrivate *priv;
1410 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1412 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1414 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1415 g_return_val_if_fail (account_name, NULL);
1418 /* don't free these (except from) */
1419 data = g_slice_new0 (MsgData);
1420 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1422 data->account_name = g_strdup (account_name);
1423 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1424 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1425 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1426 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1427 if (priv->draft_msg) {
1428 data->draft_msg = g_object_ref (priv->draft_msg);
1429 } else if (priv->outbox_msg) {
1430 data->draft_msg = g_object_ref (priv->outbox_msg);
1432 data->draft_msg = NULL;
1435 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1437 gtk_text_buffer_get_bounds (buf, &b, &e);
1438 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1440 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1441 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1443 data->html_body = NULL;
1445 /* deep-copy the data */
1446 GList *cursor = priv->attachments;
1447 data->attachments = NULL;
1449 if (!(TNY_IS_MIME_PART(cursor->data))) {
1450 g_warning ("strange data in attachment list");
1451 cursor = g_list_next (cursor);
1454 data->attachments = g_list_append (data->attachments,
1455 g_object_ref (cursor->data));
1456 cursor = g_list_next (cursor);
1459 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1460 cursor = priv->images;
1461 data->images = NULL;
1464 if (!(TNY_IS_MIME_PART(cursor->data))) {
1465 g_warning ("strange data in attachment list");
1466 cursor = g_list_next (cursor);
1469 cid = tny_mime_part_get_content_id (cursor->data);
1471 gchar *image_tag_id;
1472 GtkTextTag *image_tag;
1474 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1475 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1476 g_free (image_tag_id);
1478 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1480 ((gtk_text_iter_has_tag (&iter, image_tag))||
1481 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1482 data->images = g_list_append (data->images,
1483 g_object_ref (cursor->data));
1485 cursor = g_list_next (cursor);
1488 data->priority_flags = priv->priority_flags;
1495 unref_gobject (GObject *obj, gpointer data)
1497 if (!G_IS_OBJECT(obj))
1499 g_object_unref (obj);
1503 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1506 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1514 g_free (data->from);
1515 g_free (data->subject);
1516 g_free (data->plain_body);
1517 g_free (data->html_body);
1518 g_free (data->account_name);
1520 if (data->draft_msg != NULL) {
1521 g_object_unref (data->draft_msg);
1522 data->draft_msg = NULL;
1525 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1526 g_list_free (data->attachments);
1527 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1528 g_list_free (data->images);
1530 g_slice_free (MsgData, data);
1534 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1537 ModestMsgEditWindowPrivate *priv = NULL;
1538 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1540 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1542 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1544 return MODEST_MSG_EDIT_FORMAT_HTML;
1546 return MODEST_MSG_EDIT_FORMAT_TEXT;
1550 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1551 ModestMsgEditFormat format)
1553 ModestMsgEditWindowPrivate *priv;
1555 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1556 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1559 case MODEST_MSG_EDIT_FORMAT_HTML:
1560 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1562 case MODEST_MSG_EDIT_FORMAT_TEXT:
1563 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1566 g_return_if_reached ();
1570 ModestMsgEditFormatState *
1571 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1573 ModestMsgEditFormatState *format_state = NULL;
1574 ModestMsgEditWindowPrivate *priv;
1575 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1577 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1578 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1580 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1582 format_state = g_new0 (ModestMsgEditFormatState, 1);
1583 format_state->bold = buffer_format->bold&0x1;
1584 format_state->italics = buffer_format->italic&0x1;
1585 format_state->bullet = buffer_format->bullet&0x1;
1586 format_state->color = buffer_format->color;
1587 format_state->font_size = buffer_format->font_size;
1588 format_state->font_family = wp_get_font_name (buffer_format->font);
1589 format_state->justification = buffer_format->justification;
1590 g_free (buffer_format);
1592 return format_state;
1597 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1598 const ModestMsgEditFormatState *format_state)
1600 ModestMsgEditWindowPrivate *priv;
1601 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1602 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1603 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1604 g_return_if_fail (format_state != NULL);
1606 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1607 gtk_widget_grab_focus (priv->msg_body);
1608 buffer_format->bold = (format_state->bold != FALSE);
1609 buffer_format->italic = (format_state->italics != FALSE);
1610 buffer_format->color = format_state->color;
1611 buffer_format->font_size = format_state->font_size;
1612 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1613 buffer_format->justification = format_state->justification;
1614 buffer_format->bullet = format_state->bullet;
1616 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1618 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1619 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1620 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1621 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1622 buffer_format->cs.font = (buffer_format->font != current_format->font);
1623 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1624 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1626 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1627 if (buffer_format->cs.bold) {
1628 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1630 if (buffer_format->cs.italic) {
1631 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1633 if (buffer_format->cs.color) {
1634 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1636 if (buffer_format->cs.font_size) {
1637 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1639 if (buffer_format->cs.justification) {
1640 switch (buffer_format->justification) {
1641 case GTK_JUSTIFY_LEFT:
1642 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1644 case GTK_JUSTIFY_CENTER:
1645 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1647 case GTK_JUSTIFY_RIGHT:
1648 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1655 if (buffer_format->cs.font) {
1656 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1658 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1659 if (buffer_format->cs.bullet) {
1660 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1662 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1664 g_free (current_format);
1669 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1671 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1673 ModestWindowPrivate *parent_priv;
1674 ModestMsgEditWindowPrivate *priv;
1675 GtkWidget *new_size_menuitem;
1676 GtkWidget *new_font_menuitem;
1678 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1679 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1681 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1682 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
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);
1686 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1687 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1688 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1691 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1693 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1694 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1696 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1697 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1699 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1700 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1702 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1703 G_CALLBACK (modest_msg_edit_window_color_button_change),
1705 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1706 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1707 G_CALLBACK (modest_msg_edit_window_color_button_change),
1710 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1711 buffer_format->font_size))->data);
1712 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1716 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1717 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1718 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1720 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1721 G_CALLBACK (modest_msg_edit_window_size_change),
1723 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1724 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1725 G_CALLBACK (modest_msg_edit_window_size_change),
1729 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1730 buffer_format->font))->data);
1731 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1735 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1736 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1737 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1739 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1740 G_CALLBACK (modest_msg_edit_window_font_change),
1742 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1743 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1744 G_CALLBACK (modest_msg_edit_window_font_change),
1748 g_free (buffer_format);
1752 #ifdef MODEST_HILDON_VERSION_0
1754 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1757 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1758 ModestMsgEditWindowPrivate *priv;
1759 GtkWidget *dialog = NULL;
1761 GdkColor *new_color = NULL;
1763 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1764 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1766 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1767 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1768 g_free (buffer_format);
1770 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1771 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1772 if (new_color != NULL) {
1773 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1774 (gpointer) new_color);
1777 gtk_widget_destroy (dialog);
1782 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1785 ModestMsgEditWindowPrivate *priv;
1786 GtkWidget *dialog = NULL;
1788 GdkColor *old_color = NULL;
1789 const GdkColor *new_color = NULL;
1791 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1792 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1794 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1795 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1797 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1798 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1799 if (new_color != NULL)
1800 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1802 gtk_widget_destroy (dialog);
1808 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1811 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1812 ModestMsgEditWindowPrivate *priv;
1813 GtkWidget *dialog = NULL;
1815 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1816 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1818 dialog = hildon_color_chooser_new ();
1819 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1820 g_free (buffer_format);
1822 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1824 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1825 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1828 gtk_widget_destroy (dialog);
1833 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1836 ModestMsgEditWindowPrivate *priv;
1837 GtkWidget *dialog = NULL;
1838 GdkColor *old_color = NULL;
1840 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1841 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1843 dialog = hildon_color_chooser_new ();
1844 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1846 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1848 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1849 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1851 gtk_widget_destroy (dialog);
1854 #endif /*!MODEST_HILDON_VERSION_0*/
1858 static TnyStream* create_stream_for_uri (const gchar* uri)
1863 TnyStream *result = NULL;
1865 GnomeVFSHandle *handle = NULL;
1866 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1867 if (test == GNOME_VFS_OK) {
1868 /* Create the tinymail stream: */
1869 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1870 result = TNY_STREAM (tny_vfs_stream_new (handle));
1877 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1880 ModestMsgEditWindowPrivate *priv;
1881 GtkWidget *dialog = NULL;
1883 GSList *uris = NULL;
1884 GSList *uri_node = NULL;
1886 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1888 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1889 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1890 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1892 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1894 response = gtk_dialog_run (GTK_DIALOG (dialog));
1896 case GTK_RESPONSE_OK:
1897 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1902 gtk_widget_destroy (dialog);
1904 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1906 GnomeVFSHandle *handle = NULL;
1907 GnomeVFSResult result;
1908 GtkTextIter position;
1909 GtkTextMark *insert_mark;
1911 uri = (const gchar *) uri_node->data;
1912 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1913 if (result == GNOME_VFS_OK) {
1915 GnomeVFSFileInfo info;
1916 gchar *filename, *basename, *escaped_filename;
1917 TnyMimePart *mime_part;
1919 const gchar *mime_type = NULL;
1920 GnomeVFSURI *vfs_uri;
1922 vfs_uri = gnome_vfs_uri_new (uri);
1924 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1925 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1926 g_free (escaped_filename);
1927 gnome_vfs_uri_unref (vfs_uri);
1929 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1930 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1932 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1934 mime_part = tny_platform_factory_new_mime_part
1935 (modest_runtime_get_platform_factory ());
1937 TnyStream *stream = create_stream_for_uri (uri);
1938 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1940 content_id = g_strdup_printf ("%d", priv->last_cid);
1941 tny_mime_part_set_content_id (mime_part, content_id);
1942 g_free (content_id);
1945 basename = g_path_get_basename (filename);
1946 tny_mime_part_set_filename (mime_part, basename);
1949 pixbuf = pixbuf_from_stream (stream, mime_type);
1951 if (pixbuf != NULL) {
1952 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1953 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1954 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1957 priv->images = g_list_prepend (priv->images, mime_part);
1958 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1968 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1970 GtkWidget *dialog = NULL;
1972 GSList *uris = NULL;
1975 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1976 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1977 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1979 response = gtk_dialog_run (GTK_DIALOG (dialog));
1981 case GTK_RESPONSE_OK:
1982 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1987 gtk_widget_destroy (dialog);
1989 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1990 const gchar *uri = (const gchar *) uri_node->data;
1991 modest_msg_edit_window_attach_file_one (window, uri);
1993 g_slist_foreach (uris, (GFunc) g_free, NULL);
1994 g_slist_free (uris);
1998 modest_msg_edit_window_attach_file_one (
1999 ModestMsgEditWindow *window,
2002 g_return_if_fail (window);
2003 g_return_if_fail (uri);
2005 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2008 GnomeVFSHandle *handle = NULL;
2009 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2010 if (result == GNOME_VFS_OK) {
2011 TnyMimePart *mime_part;
2013 const gchar *mime_type = NULL;
2015 gchar *escaped_filename;
2018 GnomeVFSFileInfo info;
2019 GnomeVFSURI *vfs_uri;
2021 vfs_uri = gnome_vfs_uri_new (uri);
2024 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2025 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2026 g_free (escaped_filename);
2027 gnome_vfs_uri_unref (vfs_uri);
2029 if (gnome_vfs_get_file_info (uri,
2031 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2032 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2034 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2035 mime_part = tny_platform_factory_new_mime_part
2036 (modest_runtime_get_platform_factory ());
2037 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2039 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2041 content_id = g_strdup_printf ("%d", priv->last_cid);
2042 tny_mime_part_set_content_id (mime_part, content_id);
2043 g_free (content_id);
2046 basename = g_path_get_basename (filename);
2047 tny_mime_part_set_filename (mime_part, basename);
2050 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2051 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2053 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2054 gtk_widget_show_all (priv->attachments_caption);
2055 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2061 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2064 ModestMsgEditWindowPrivate *priv;
2065 gboolean clean_list = FALSE;
2067 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2068 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2070 if (att_list == NULL) {
2071 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2075 if (att_list == NULL) {
2076 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2078 GtkWidget *confirmation_dialog = NULL;
2079 gboolean dialog_response;
2081 gchar *message = NULL;
2082 gchar *filename = NULL;
2084 if (att_list->next == NULL) {
2085 if (TNY_IS_MSG (att_list->data)) {
2086 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2088 filename = g_strdup (tny_header_get_subject (header));
2089 g_object_unref (header);
2091 if (filename == NULL) {
2092 filename = g_strdup (_("mail_va_no_subject"));
2095 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2098 filename = g_strdup ("");
2100 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2101 att_list->next == NULL), filename);
2103 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2105 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2106 gtk_widget_destroy (confirmation_dialog);
2107 if (!dialog_response) {
2109 g_list_free (att_list);
2112 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2114 for (node = att_list; node != NULL; node = g_list_next (node)) {
2115 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2116 const gchar *att_id;
2117 priv->attachments = g_list_remove (priv->attachments, mime_part);
2119 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2121 if (priv->attachments == NULL)
2122 gtk_widget_hide (priv->attachments_caption);
2123 att_id = tny_mime_part_get_content_id (mime_part);
2125 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2127 g_object_unref (mime_part);
2128 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2133 g_list_free (att_list);
2137 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2140 ModestMsgEditWindowPrivate *priv;
2141 GdkColor *new_color;
2142 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2144 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2145 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2148 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2150 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2152 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2154 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2159 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2162 ModestMsgEditWindowPrivate *priv;
2163 gint new_size_index;
2164 ModestMsgEditWindow *window;
2167 window = MODEST_MSG_EDIT_WINDOW (userdata);
2168 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2169 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2171 if (gtk_check_menu_item_get_active (menu_item)) {
2173 WPTextBufferFormat format;
2175 memset (&format, 0, sizeof (format));
2176 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2178 label = gtk_bin_get_child (GTK_BIN (menu_item));
2180 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2181 format.cs.font_size = TRUE;
2182 format.cs.text_position = TRUE;
2183 format.cs.font = TRUE;
2184 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2185 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2187 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2188 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2189 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2191 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2192 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2193 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2199 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2202 ModestMsgEditWindowPrivate *priv;
2203 gint new_font_index;
2204 ModestMsgEditWindow *window;
2207 window = MODEST_MSG_EDIT_WINDOW (userdata);
2208 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2209 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2211 if (gtk_check_menu_item_get_active (menu_item)) {
2214 label = gtk_bin_get_child (GTK_BIN (menu_item));
2216 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2218 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2219 (gpointer) new_font_index))
2220 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2222 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2223 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2224 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2230 modest_msg_edit_window_set_zoom (ModestWindow *window,
2233 ModestMsgEditWindowPrivate *priv;
2234 ModestWindowPrivate *parent_priv;
2235 GtkRadioAction *zoom_radio_action;
2237 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2239 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2240 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2241 priv->zoom_level = zoom;
2242 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2244 /* Zoom level menu options should be updated with the current zoom level */
2245 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2246 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2247 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2248 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2249 /* FIXME: Not availible before Gtk 2.10 */
2251 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2256 modest_msg_edit_window_get_zoom (ModestWindow *window)
2258 ModestMsgEditWindowPrivate *priv;
2260 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2262 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2263 return priv->zoom_level;
2267 zoom_allowed (ModestMsgEditWindow *window)
2271 focus = gtk_window_get_focus (GTK_WINDOW (window));
2272 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2276 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2278 ModestWindowPrivate *parent_priv;
2279 GtkRadioAction *zoom_radio_action;
2280 GSList *group, *node;
2282 /* First we check if the text view is focused. If not, zooming is not allowed */
2283 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2284 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2288 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2289 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2290 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2292 group = gtk_radio_action_get_group (zoom_radio_action);
2294 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2295 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2299 for (node = group; node != NULL; node = g_slist_next (node)) {
2300 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2301 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2309 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2311 ModestWindowPrivate *parent_priv;
2312 GtkRadioAction *zoom_radio_action;
2313 GSList *group, *node;
2315 /* First we check if the text view is focused. If not, zooming is not allowed */
2316 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2317 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2321 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2322 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2323 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2325 group = gtk_radio_action_get_group (zoom_radio_action);
2327 for (node = group; node != NULL; node = g_slist_next (node)) {
2328 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2329 if (node->next != NULL) {
2330 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2333 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2341 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2343 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2344 ModestWindowPrivate *parent_priv;
2345 ModestWindowMgr *mgr;
2346 gboolean is_fullscreen;
2347 GtkAction *fs_toggle_action;
2350 mgr = modest_runtime_get_window_mgr ();
2351 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2353 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2355 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2356 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2357 if (is_fullscreen != active)
2358 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2366 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2369 ModestMsgEditWindowPrivate *priv = NULL;
2370 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2372 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2373 if (!priv->update_caption_visibility)
2376 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2378 gtk_widget_show (priv->cc_caption);
2380 gtk_widget_hide (priv->cc_caption);
2382 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2386 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2389 ModestMsgEditWindowPrivate *priv = NULL;
2390 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2392 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2393 if (!priv->update_caption_visibility)
2396 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2398 gtk_widget_show (priv->bcc_caption);
2400 gtk_widget_hide (priv->bcc_caption);
2402 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2406 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2407 ModestRecptEditor *editor)
2409 ModestMsgEditWindowPrivate *priv;
2411 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2412 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2413 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2415 if (editor == NULL) {
2416 GtkWidget *view_focus;
2417 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2419 /* This code should be kept in sync with ModestRecptEditor. The
2420 textview inside the recpt editor is the one that really gets the
2421 focus. As it's inside a scrolled window, and this one inside the
2422 hbox recpt editor inherits from, we'll need to go up in the
2423 hierarchy to know if the text view is part of the recpt editor
2424 or if it's a different text entry */
2426 if (gtk_widget_get_parent (view_focus)) {
2427 GtkWidget *first_parent;
2429 first_parent = gtk_widget_get_parent (view_focus);
2430 if (gtk_widget_get_parent (first_parent) &&
2431 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2432 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2437 editor = MODEST_RECPT_EDITOR (priv->to_field);
2441 modest_address_book_select_addresses (editor);
2446 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2448 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2450 modest_msg_edit_window_open_addressbook (window, NULL);
2454 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2455 gboolean show_toolbar)
2457 ModestWindowPrivate *parent_priv;
2458 const gchar *action_name;
2461 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2462 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2464 /* We can not just use the code of
2465 modest_msg_edit_window_setup_toolbar because it has a
2466 mixture of both initialization and creation code. */
2468 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2470 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2472 /* Update also the actions (to update the toggles in the
2473 menus), we have to do it manually because some other window
2474 of the same time could have changed it (remember that the
2475 toolbar fullscreen mode is shared by all the windows of the
2477 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2478 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2480 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2482 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2483 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2489 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2490 TnyHeaderFlags priority_flags)
2492 ModestMsgEditWindowPrivate *priv;
2493 ModestWindowPrivate *parent_priv;
2495 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2497 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2498 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2500 if (priv->priority_flags != priority_flags) {
2501 GtkAction *priority_action = NULL;
2503 priv->priority_flags = priority_flags;
2505 switch (priority_flags) {
2506 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2507 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2508 gtk_widget_show (priv->priority_icon);
2509 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2510 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2512 case TNY_HEADER_FLAG_LOW_PRIORITY:
2513 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2514 gtk_widget_show (priv->priority_icon);
2515 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2516 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2519 gtk_widget_hide (priv->priority_icon);
2520 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2521 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2524 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2525 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2530 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2533 ModestMsgEditWindowPrivate *priv;
2534 ModestWindowPrivate *parent_priv;
2535 gint current_format;
2537 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2539 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2540 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2542 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2543 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2545 if (current_format != file_format) {
2546 switch (file_format) {
2547 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2548 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2549 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2551 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2555 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2556 response = gtk_dialog_run (GTK_DIALOG (dialog));
2557 gtk_widget_destroy (dialog);
2558 if (response == GTK_RESPONSE_OK) {
2559 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2561 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2562 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2567 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2572 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2575 ModestMsgEditWindowPrivate *priv;
2576 WPTextBufferFormat oldfmt, fmt;
2577 gint old_position = 0;
2581 GdkColor *color = NULL;
2582 gboolean bold, bold_set, italic, italic_set;
2583 gboolean underline, underline_set;
2584 gboolean strikethrough, strikethrough_set;
2585 gboolean position_set;
2586 gboolean font_size_set, font_set, color_set;
2589 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2590 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2592 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2594 /* First we get the currently selected font information */
2595 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2596 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2598 switch (oldfmt.text_position) {
2599 case TEXT_POSITION_NORMAL:
2602 case TEXT_POSITION_SUPERSCRIPT:
2610 g_object_set (G_OBJECT (dialog),
2611 "bold", oldfmt.bold != FALSE,
2612 "bold-set", !oldfmt.cs.bold,
2613 "underline", oldfmt.underline != FALSE,
2614 "underline-set", !oldfmt.cs.underline,
2615 "italic", oldfmt.italic != FALSE,
2616 "italic-set", !oldfmt.cs.italic,
2617 "strikethrough", oldfmt.strikethrough != FALSE,
2618 "strikethrough-set", !oldfmt.cs.strikethrough,
2619 "color", &oldfmt.color,
2620 "color-set", !oldfmt.cs.color,
2621 "size", wp_font_size[oldfmt.font_size],
2622 "size-set", !oldfmt.cs.font_size,
2623 "position", old_position,
2624 "position-set", !oldfmt.cs.text_position,
2625 "family", wp_get_font_name (oldfmt.font),
2626 "family-set", !oldfmt.cs.font,
2629 gtk_widget_show_all (dialog);
2630 response = gtk_dialog_run (GTK_DIALOG (dialog));
2631 if (response == GTK_RESPONSE_OK) {
2633 g_object_get( dialog,
2635 "bold-set", &bold_set,
2636 "underline", &underline,
2637 "underline-set", &underline_set,
2639 "italic-set", &italic_set,
2640 "strikethrough", &strikethrough,
2641 "strikethrough-set", &strikethrough_set,
2643 "color-set", &color_set,
2645 "size-set", &font_size_set,
2646 "family", &font_name,
2647 "family-set", &font_set,
2648 "position", &position,
2649 "position-set", &position_set,
2654 if (response == GTK_RESPONSE_OK) {
2655 memset(&fmt, 0, sizeof(fmt));
2661 fmt.italic = italic;
2662 fmt.cs.italic = TRUE;
2664 if (underline_set) {
2665 fmt.underline = underline;
2666 fmt.cs.underline = TRUE;
2668 if (strikethrough_set) {
2669 fmt.strikethrough = strikethrough;
2670 fmt.cs.strikethrough = TRUE;
2675 ? TEXT_POSITION_NORMAL
2676 : ( ( position == 1 )
2677 ? TEXT_POSITION_SUPERSCRIPT
2678 : TEXT_POSITION_SUBSCRIPT );
2679 fmt.cs.text_position = TRUE;
2683 fmt.cs.color = TRUE;
2686 fmt.font = wp_get_font_index(font_name,
2691 if (font_size_set) {
2692 fmt.font_size = wp_get_font_size_index(
2693 font_size, DEFAULT_FONT_SIZE);
2694 fmt.cs.font_size = TRUE;
2696 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2697 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2699 gtk_widget_destroy (dialog);
2701 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2705 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2707 ModestMsgEditWindowPrivate *priv;
2709 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2710 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2712 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2714 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2719 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2721 ModestMsgEditWindowPrivate *priv;
2723 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2724 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2726 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2728 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2733 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2735 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2737 priv->can_undo = can_undo;
2741 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2743 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2745 priv->can_redo = can_redo;
2749 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2751 ModestMsgEditWindowPrivate *priv;
2752 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2753 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2755 return priv->can_undo;
2759 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2761 ModestMsgEditWindowPrivate *priv;
2762 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2763 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2765 return priv->can_redo;
2770 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2773 GtkTextIter match_start, match_end;
2775 if (image_id == NULL)
2778 gtk_text_buffer_get_start_iter (buffer, &iter);
2780 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2781 GSList *tags = gtk_text_iter_get_tags (&match_start);
2783 for (node = tags; node != NULL; node = g_slist_next (node)) {
2784 GtkTextTag *tag = (GtkTextTag *) node->data;
2785 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2786 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2787 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2789 offset = gtk_text_iter_get_offset (&match_start);
2790 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2791 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2795 gtk_text_iter_forward_char (&iter);
2800 message_is_empty (ModestMsgEditWindow *window)
2802 ModestMsgEditWindowPrivate *priv = NULL;
2804 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2805 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2807 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2808 * so we can ignore markup.
2810 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2813 count = gtk_text_buffer_get_char_count (buf);
2819 msg_body_focus (GtkWidget *focus,
2820 GdkEventFocus *event,
2824 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2829 recpt_field_changed (GtkTextBuffer *buffer,
2830 ModestMsgEditWindow *editor)
2832 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2836 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2838 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2842 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2844 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2845 GtkTextBuffer *buffer;
2847 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2848 gtk_text_buffer_set_modified (buffer, FALSE);
2849 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2850 gtk_text_buffer_set_modified (buffer, FALSE);
2851 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2852 gtk_text_buffer_set_modified (buffer, FALSE);
2853 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2857 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2859 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2860 GtkTextBuffer *buffer;
2862 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2863 if (gtk_text_buffer_get_modified (buffer))
2865 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2866 if (gtk_text_buffer_get_modified (buffer))
2868 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2869 if (gtk_text_buffer_get_modified (buffer))
2871 if (gtk_text_buffer_get_modified (priv->text_buffer))
2881 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2883 ModestMsgEditWindowPrivate *priv = NULL;
2885 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2886 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2888 /* check if there's no recipient added */
2889 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2890 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2891 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2892 /* no recipient contents, then select contacts */
2893 modest_msg_edit_window_open_addressbook (window, NULL);
2897 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2898 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2901 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2902 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2905 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2906 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2910 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2911 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2912 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2919 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2920 ModestMsgEditWindow *window)
2922 modest_msg_edit_window_offer_attach_file (window);
2926 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2928 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2930 return priv->clipboard_text;
2934 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2936 ModestMsgEditWindow *window)
2938 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2939 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2941 if (!GTK_WIDGET_VISIBLE (window))
2944 text = gtk_clipboard_wait_for_text (selection_clipboard);
2946 if (priv->clipboard_text != NULL) {
2947 g_free (priv->clipboard_text);
2949 priv->clipboard_text = text;
2951 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2954 subject_field_move_cursor (GtkEntry *entry,
2955 GtkMovementStep step,
2960 if (!GTK_WIDGET_VISIBLE (window))
2963 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2967 update_window_title (ModestMsgEditWindow *window)
2969 ModestMsgEditWindowPrivate *priv = NULL;
2970 const gchar *subject;
2972 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2973 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2974 if (subject == NULL || subject[0] == '\0')
2975 subject = _("mail_va_new_email");
2977 gtk_window_set_title (GTK_WINDOW (window), subject);
2982 subject_field_changed (GtkEditable *editable,
2983 ModestMsgEditWindow *window)
2985 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2986 update_window_title (window);
2987 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2988 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2992 subject_field_insert_text (GtkEditable *editable,
2994 gint new_text_length,
2996 ModestMsgEditWindow *window)
2998 GString *result = g_string_new ("");
3000 gint result_len = 0;
3001 const gchar *entry_text = NULL;
3004 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3005 old_length = g_utf8_strlen (entry_text, -1);
3007 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3008 gunichar c = g_utf8_get_char_validated (current, 8);
3009 /* Invalid unichar, stop */
3015 result = g_string_append_unichar (result, c);
3019 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3020 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3023 /* Prevent endless recursion */
3024 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3025 g_signal_emit_by_name (editable, "insert-text",
3026 (gpointer) result->str, (gpointer) result->len,
3027 (gpointer) position, (gpointer) window);
3028 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3032 if (result_len + old_length > 1000) {
3033 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3034 dgettext("hildon-common-strings",
3035 "ckdg_ib_maximum_characters_reached"));
3038 g_string_free (result, TRUE);
3042 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3045 ModestMsgEditWindowPrivate *priv = NULL;
3047 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3048 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3050 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3053 gtk_widget_show_all (priv->find_toolbar);
3054 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3056 gtk_widget_hide_all (priv->find_toolbar);
3057 gtk_widget_grab_focus (priv->msg_body);
3063 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3065 GtkTextIter *match_start,
3066 GtkTextIter *match_end)
3068 GtkTextIter end_iter;
3069 gchar *str_casefold;
3072 gchar *range_casefold;
3075 gboolean result = FALSE;
3082 gtk_text_iter_forward_to_end (&end_iter);
3084 str_casefold = g_utf8_casefold (str, -1);
3085 str_chars_n = strlen (str);
3087 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3088 range_casefold = g_utf8_casefold (range_text, -1);
3089 range_chars_n = strlen (range_casefold);
3091 if (range_chars_n < str_chars_n) {
3092 g_free (str_casefold);
3093 g_free (range_text);
3094 g_free (range_casefold);
3098 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3099 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3100 if (!g_utf8_collate (range_subtext, str_casefold)) {
3101 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3103 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3104 match_start, match_end, NULL);
3105 g_free (found_text);
3107 g_free (range_subtext);
3111 g_free (str_casefold);
3112 g_free (range_text);
3113 g_free (range_casefold);
3120 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3121 ModestMsgEditWindow *window)
3123 gchar *current_search = NULL;
3124 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3126 GtkTextIter selection_start, selection_end;
3127 GtkTextIter match_start, match_end;
3128 gboolean continue_search = FALSE;
3130 if (message_is_empty (window)) {
3131 g_free (priv->last_search);
3132 priv->last_search = NULL;
3133 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3137 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3138 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3139 g_free (current_search);
3140 g_free (priv->last_search);
3141 priv->last_search = NULL;
3142 /* Information banner about empty search */
3143 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3147 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3148 continue_search = TRUE;
3150 g_free (priv->last_search);
3151 priv->last_search = g_strdup (current_search);
3154 if (continue_search) {
3155 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3156 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3157 &match_start, &match_end);
3159 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3161 GtkTextIter buffer_start;
3162 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3163 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3164 &match_start, &match_end);
3166 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3169 /* Mark as selected the string found in search */
3171 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3172 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3174 g_free (priv->last_search);
3175 priv->last_search = NULL;
3177 g_free (current_search);
3181 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3182 ModestMsgEditWindow *window)
3184 GtkToggleAction *toggle;
3185 ModestWindowPrivate *parent_priv;
3186 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3188 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3189 gtk_toggle_action_set_active (toggle, FALSE);
3193 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3195 ModestMsgEditWindowPrivate *priv;
3197 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3202 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3205 ModestMsgEditWindowPrivate *priv;
3207 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3213 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3216 ModestMsgEditWindowPrivate *priv;
3217 TnyHeader *header = NULL;
3219 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3220 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3222 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3223 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3225 if (priv->draft_msg != NULL) {
3226 g_object_unref (priv->draft_msg);
3229 if (draft != NULL) {
3230 g_object_ref (draft);
3231 header = tny_msg_get_header (draft);
3232 if (priv->msg_uid) {
3233 g_free (priv->msg_uid);
3234 priv->msg_uid = NULL;
3236 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3237 if (GTK_WIDGET_REALIZED (window))
3238 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3241 priv->draft_msg = draft;
3245 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3246 GtkTextIter *start, GtkTextIter *end,
3249 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3250 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3253 if (tag == NULL+13) return;
3254 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3255 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3256 replace_with_images (window, priv->images);
3261 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3264 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3266 g_return_if_fail (TNY_IS_MIME_PART (part));
3267 priv->attachments = g_list_prepend (priv->attachments, part);
3268 g_object_ref (part);
3269 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3270 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3271 gtk_widget_show_all (priv->attachments_caption);
3272 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3276 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3278 ModestMsgEditWindowPrivate *priv;
3280 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3281 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3283 return priv->msg_uid;
3287 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3288 ModestMsgEditWindowWidgetType widget_type)
3290 ModestMsgEditWindowPrivate *priv;
3292 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3293 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3295 switch (widget_type) {
3296 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3297 return priv->msg_body;
3299 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3300 return priv->to_field;
3302 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3303 return priv->cc_field;
3305 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3306 return priv->bcc_field;
3308 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3309 return priv->subject_field;
3311 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3312 return priv->attachments_view;
3320 remove_tags (WPTextBuffer *buffer)
3322 GtkTextIter start, end;
3324 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3325 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3327 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3331 on_account_removed (TnyAccountStore *account_store,
3332 TnyAccount *account,
3335 /* Do nothing if it's a store account, because we use the
3336 transport to send the messages */
3337 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3338 const gchar *parent_acc = NULL;
3339 const gchar *our_acc = NULL;
3341 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3342 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3343 /* Close this window if I'm showing a message of the removed account */
3344 if (strcmp (parent_acc, our_acc) == 0)
3345 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));