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 parent_priv->menubar = NULL;
642 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
644 /* Note: This ModestPairList* must exist for as long as the combo
645 * that uses it, because the ModestComboBox uses the ID opaquely,
646 * so it can't know how to manage its memory. */
647 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
649 priv->to_field = modest_recpt_editor_new ();
650 priv->cc_field = modest_recpt_editor_new ();
651 priv->bcc_field = modest_recpt_editor_new ();
652 subject_box = gtk_hbox_new (FALSE, 0);
653 priv->priority_icon = gtk_image_new ();
654 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
655 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
656 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
657 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
658 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
659 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
660 priv->add_attachment_button = gtk_button_new ();
661 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
662 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
663 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
664 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
665 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
666 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
667 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
668 priv->attachments_view = modest_attachments_view_new (NULL);
670 priv->header_box = gtk_vbox_new (FALSE, 0);
672 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
673 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
674 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
675 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
676 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
677 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
678 g_object_unref (size_group);
680 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
681 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
682 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
683 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
684 gtk_size_group_add_widget (size_group, priv->subject_field);
685 gtk_size_group_add_widget (size_group, priv->attachments_view);
686 g_object_unref (size_group);
688 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
689 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
690 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
691 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
692 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
694 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
697 priv->msg_body = wp_text_view_new ();
698 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
699 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
700 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
701 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
702 #if (GTK_MINOR_VERSION >= 10)
703 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
704 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
706 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
707 deserialize_type, TRUE);
709 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
711 priv->find_toolbar = hildon_find_toolbar_new (NULL);
712 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
714 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
716 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
717 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
718 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
719 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
721 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
723 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
724 frame = gtk_frame_new (NULL);
725 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
727 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
728 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
729 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
731 G_CALLBACK (vadj_changed),
733 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
735 window_box = gtk_vbox_new (FALSE, 0);
736 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
737 gtk_container_add (GTK_CONTAINER(obj), window_box);
738 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
739 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
741 /* Set window icon */
742 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
744 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
745 g_object_unref (window_icon);
751 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
753 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
755 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
756 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
757 priv->clipboard_change_handler_id))
758 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
759 priv->clipboard_change_handler_id);
760 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
761 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
762 priv->default_clipboard_change_handler_id))
763 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
764 priv->default_clipboard_change_handler_id);
766 if (priv->account_removed_handler_id &&
767 g_signal_handler_is_connected (modest_runtime_get_account_store (),
768 priv->account_removed_handler_id))
769 g_signal_handler_disconnect(modest_runtime_get_account_store (),
770 priv->account_removed_handler_id);
774 modest_msg_edit_window_finalize (GObject *obj)
776 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
778 /* Sanity check: shouldn't be needed, the window mgr should
779 call this function before */
780 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
782 if (priv->clipboard_text != NULL) {
783 g_free (priv->clipboard_text);
784 priv->clipboard_text = NULL;
787 if (priv->draft_msg != NULL) {
788 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
789 if (TNY_IS_HEADER (header)) {
790 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
791 modest_window_mgr_unregister_header (mgr, header);
793 g_object_unref (priv->draft_msg);
794 priv->draft_msg = NULL;
796 if (priv->outbox_msg != NULL) {
797 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
798 if (TNY_IS_HEADER (header)) {
799 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
800 modest_window_mgr_unregister_header (mgr, header);
802 g_object_unref (priv->outbox_msg);
803 priv->outbox_msg = NULL;
805 g_free (priv->msg_uid);
806 g_free (priv->last_search);
807 g_slist_free (priv->font_items_group);
808 g_slist_free (priv->size_items_group);
809 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
810 g_list_free (priv->attachments);
811 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
812 g_list_free (priv->images);
814 /* This had to stay alive for as long as the combobox that used it: */
815 modest_pair_list_free (priv->from_field_protos);
817 G_OBJECT_CLASS(parent_class)->finalize (obj);
821 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
823 GdkPixbufLoader *loader;
826 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
831 tny_stream_reset (TNY_STREAM (stream));
832 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
833 unsigned char read_buffer[128];
835 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
836 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
840 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
841 g_object_ref (pixbuf);
842 gdk_pixbuf_loader_close (loader, NULL);
843 g_object_unref (loader);
845 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
846 GdkPixbuf *new_pixbuf;
848 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
849 gdk_pixbuf_get_width (pixbuf);
850 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
851 g_object_unref (pixbuf);
859 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
861 ModestMsgEditWindowPrivate *priv;
864 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
866 for (node = attachments; node != NULL; node = g_list_next (node)) {
867 TnyMimePart *part = (TnyMimePart *) node->data;
868 const gchar *cid = tny_mime_part_get_content_id (part);
869 const gchar *mime_type = tny_mime_part_get_content_type (part);
870 if ((cid != NULL)&&(mime_type != NULL)) {
871 TnyStream *stream = tny_mime_part_get_stream (part);
872 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
873 g_object_unref (stream);
875 if (pixbuf != NULL) {
876 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
877 g_object_unref (pixbuf);
884 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
886 TnyMimePart *parent = NULL;
887 const gchar *content_type = NULL;
888 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
890 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
892 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
893 parent = g_object_ref (msg);
894 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
895 TnyList *parts = TNY_LIST (tny_simple_list_new ());
898 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
899 iter = tny_list_create_iterator (parts);
900 while (!tny_iterator_is_done (iter)) {
902 part = TNY_MIME_PART (tny_iterator_get_current (iter));
903 content_type = tny_mime_part_get_content_type (part);
904 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
908 g_object_unref (part);
910 tny_iterator_next (iter);
912 g_object_unref (iter);
913 g_object_unref (parts);
916 if (parent != NULL) {
917 TnyList *parts = TNY_LIST (tny_simple_list_new ());
920 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
921 iter = tny_list_create_iterator (parts);
922 while (!tny_iterator_is_done (iter)) {
924 part = TNY_MIME_PART (tny_iterator_get_current (iter));
925 content_type = tny_mime_part_get_content_type (part);
926 if (content_type && g_str_has_prefix (content_type, "image/")) {
927 priv->images = g_list_prepend (priv->images, part);
929 g_object_unref (part);
931 tny_iterator_next (iter);
933 g_object_unref (iter);
934 g_object_unref (parts);
935 g_object_unref (parent);
940 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
943 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
945 for (node = attachments; node != NULL; node = g_list_next (node)) {
946 TnyMimePart *part = (TnyMimePart *) node->data;
947 const gchar *cid = tny_mime_part_get_content_id (part);
949 char *invalid = NULL;
950 gint int_cid = strtol (cid, &invalid, 10);
951 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
952 priv->last_cid = int_cid;
960 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
963 const gchar *to, *cc, *bcc, *subject;
965 ModestMsgEditWindowPrivate *priv;
967 TnyHeaderFlags priority_flags;
968 TnyFolder *msg_folder;
969 gboolean is_html = FALSE;
971 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
972 g_return_if_fail (TNY_IS_MSG (msg));
974 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
976 header = tny_msg_get_header (msg);
977 to = tny_header_get_to (header);
978 cc = tny_header_get_cc (header);
979 bcc = tny_header_get_bcc (header);
980 subject = tny_header_get_subject (header);
981 priority_flags = tny_header_get_priority (header);
984 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
986 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
987 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
988 gtk_widget_show (priv->cc_caption);
989 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
990 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
991 gtk_widget_hide (priv->cc_caption);
994 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
995 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
996 gtk_widget_show (priv->bcc_caption);
997 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
998 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
999 gtk_widget_hide (priv->bcc_caption);
1002 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1003 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1006 update_window_title (self);
1008 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1009 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1011 if ((body == NULL)||(body[0] == '\0')) {
1013 body = modest_text_utils_convert_to_html ("");
1016 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1017 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1020 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1023 /* Add attachments to the view */
1024 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1025 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1026 if (priv->attachments == NULL) {
1027 gtk_widget_hide (priv->attachments_caption);
1029 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1030 gtk_widget_show_all (priv->attachments_caption);
1032 get_related_images (self, msg);
1033 update_last_cid (self, priv->attachments);
1034 update_last_cid (self, priv->images);
1035 replace_with_images (self, priv->images);
1037 if (preserve_is_rich && !is_html) {
1038 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1039 /* Get the default format required from configuration */
1040 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1041 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1044 /* Set the default focus depending on having already a To: field or not */
1045 if ((!to)||(*to == '\0')) {
1046 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1048 gtk_widget_grab_focus (priv->msg_body);
1051 /* TODO: lower priority, select in the From: combo to the
1052 value that comes from msg <- not sure, should it be
1055 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1057 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1058 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1060 modest_msg_edit_window_reset_modified (self);
1062 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1063 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1064 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1066 if (priv->msg_uid) {
1067 g_free (priv->msg_uid);
1068 priv->msg_uid = NULL;
1071 /* we should set a reference to the incoming message if it is a draft */
1072 msg_folder = tny_msg_get_folder (msg);
1074 if (modest_tny_folder_is_local_folder (msg_folder)) {
1075 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1076 if (type == TNY_FOLDER_TYPE_INVALID)
1077 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1079 if (type == TNY_FOLDER_TYPE_DRAFTS)
1080 priv->draft_msg = g_object_ref(msg);
1081 if (type == TNY_FOLDER_TYPE_OUTBOX)
1082 priv->outbox_msg = g_object_ref(msg);
1083 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1085 g_object_unref (msg_folder);
1090 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1093 GList *item_children, *node;
1094 GtkWidget *bin_child;
1096 bin_child = gtk_bin_get_child (GTK_BIN(item));
1098 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1100 for (node = item_children; node != NULL; node = g_list_next (node)) {
1101 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1102 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1105 g_list_free (item_children);
1109 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1112 GList *item_children, *node;
1114 box = gtk_bin_get_child (GTK_BIN (item));
1115 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1116 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1118 for (node = item_children; node != NULL; node = g_list_next (node)) {
1119 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1120 if (GTK_IS_TOGGLE_BUTTON (node->data))
1121 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1122 else if (GTK_IS_BUTTON (node->data))
1123 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1125 g_list_free (item_children);
1130 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1132 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1133 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1134 GtkWidget *placeholder;
1135 GtkWidget *tool_item;
1140 GtkWidget *sizes_menu;
1141 GtkWidget *fonts_menu;
1142 GSList *radio_group = NULL;
1143 GSList *node = NULL;
1147 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1148 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1150 /* Font color placeholder */
1151 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1152 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1155 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1156 priv->font_color_button = hildon_color_button_new ();
1157 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1158 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1159 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1160 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1161 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1162 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1163 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1165 G_CALLBACK (modest_msg_edit_window_color_button_change),
1168 /* Font size and face placeholder */
1169 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1170 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1172 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1173 priv->size_tool_button_label = gtk_label_new (NULL);
1174 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1175 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1176 size_text,"</span>", NULL);
1177 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1179 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1180 sizes_menu = gtk_menu_new ();
1181 priv->size_items_group = NULL;
1183 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1184 GtkWidget *size_menu_item;
1186 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1187 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1188 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1189 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1190 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1191 gtk_widget_show (size_menu_item);
1193 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1197 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1198 GtkWidget *item = (GtkWidget *) node->data;
1199 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1203 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1204 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1205 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1206 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1207 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1208 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1209 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1210 priv->font_size_toolitem = tool_item;
1213 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1214 priv->font_tool_button_label = gtk_label_new (NULL);
1215 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1216 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1218 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1219 fonts_menu = gtk_menu_new ();
1220 priv->font_items_group = NULL;
1222 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1223 GtkWidget *font_menu_item;
1224 GtkWidget *child_label;
1226 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1227 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1228 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1229 wp_get_font_name (font_index), "</span>", NULL);
1230 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1233 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1234 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1235 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1236 gtk_widget_show (font_menu_item);
1238 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1241 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1242 GtkWidget *item = (GtkWidget *) node->data;
1243 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1246 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1247 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1248 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1249 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1250 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1251 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1252 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1253 priv->font_face_toolitem = tool_item;
1255 /* Set expand and homogeneous for remaining items */
1256 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1257 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1258 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1259 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1260 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1261 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1262 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1263 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1264 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1266 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1267 will not show the tool items added to the placeholders) */
1268 gtk_widget_show_all (parent_priv->toolbar);
1270 /* Set the no show all *after* showing all items. We do not
1271 want the toolbar to be shown with a show all because it
1272 could go agains the gconf setting regarding showing or not
1273 the toolbar of the editor window */
1274 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1280 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1283 ModestWindowPrivate *parent_priv;
1284 ModestMsgEditWindowPrivate *priv;
1285 ModestPair *account_pair = NULL;
1286 ModestDimmingRulesGroup *menu_rules_group = NULL;
1287 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1288 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1289 ModestWindowMgr *mgr = NULL;
1291 g_return_val_if_fail (msg, NULL);
1292 g_return_val_if_fail (account_name, NULL);
1294 mgr = modest_runtime_get_window_mgr ();
1296 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1298 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1299 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1301 /* Menubar. Update the state of some toggles */
1302 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1303 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1304 priv->from_field_protos = get_transports ();
1305 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1306 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1307 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1310 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1312 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1314 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1316 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1317 if (account_pair != NULL)
1318 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1320 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1321 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1322 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1323 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1324 /* Add common dimming rules */
1325 modest_dimming_rules_group_add_rules (menu_rules_group,
1326 modest_msg_edit_window_menu_dimming_entries,
1327 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1328 MODEST_WINDOW (obj));
1329 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1330 modest_msg_edit_window_toolbar_dimming_entries,
1331 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1332 MODEST_WINDOW (obj));
1333 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1334 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1335 MODEST_WINDOW (obj));
1336 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1337 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1338 MODEST_WINDOW (obj));
1339 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1340 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1341 MODEST_WINDOW (obj));
1342 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1343 modest_msg_edit_window_clipboard_dimming_entries,
1344 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1345 MODEST_WINDOW (obj));
1346 /* Insert dimming rules group for this window */
1347 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1348 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1349 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1350 /* Checks the dimming rules */
1351 g_object_unref (menu_rules_group);
1352 g_object_unref (toolbar_rules_group);
1353 g_object_unref (clipboard_rules_group);
1355 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1357 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1359 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1360 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1361 priv->update_caption_visibility = TRUE;
1363 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1365 /* Track account-removed signal, this window should be closed
1366 in the case we're creating a mail associated to the account
1368 priv->account_removed_handler_id =
1369 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1371 G_CALLBACK(on_account_removed),
1374 return (ModestWindow*) obj;
1378 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1380 GString **string_buffer = (GString **) user_data;
1382 *string_buffer = g_string_append (*string_buffer, buffer);
1388 * @result: A new string which should be freed with g_free().
1391 get_formatted_data (ModestMsgEditWindow *edit_window)
1393 ModestMsgEditWindowPrivate *priv;
1394 GString *string_buffer = g_string_new ("");
1396 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1398 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1400 return g_string_free (string_buffer, FALSE);
1405 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1408 const gchar *account_name;
1409 ModestMsgEditWindowPrivate *priv;
1411 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1413 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1415 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1416 g_return_val_if_fail (account_name, NULL);
1419 /* don't free these (except from) */
1420 data = g_slice_new0 (MsgData);
1421 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1423 data->account_name = g_strdup (account_name);
1424 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1425 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1426 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1427 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1428 if (priv->draft_msg) {
1429 data->draft_msg = g_object_ref (priv->draft_msg);
1430 } else if (priv->outbox_msg) {
1431 data->draft_msg = g_object_ref (priv->outbox_msg);
1433 data->draft_msg = NULL;
1436 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1438 gtk_text_buffer_get_bounds (buf, &b, &e);
1439 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1441 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1442 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1444 data->html_body = NULL;
1446 /* deep-copy the data */
1447 GList *cursor = priv->attachments;
1448 data->attachments = NULL;
1450 if (!(TNY_IS_MIME_PART(cursor->data))) {
1451 g_warning ("strange data in attachment list");
1452 cursor = g_list_next (cursor);
1455 data->attachments = g_list_append (data->attachments,
1456 g_object_ref (cursor->data));
1457 cursor = g_list_next (cursor);
1460 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1461 cursor = priv->images;
1462 data->images = NULL;
1465 if (!(TNY_IS_MIME_PART(cursor->data))) {
1466 g_warning ("strange data in attachment list");
1467 cursor = g_list_next (cursor);
1470 cid = tny_mime_part_get_content_id (cursor->data);
1472 gchar *image_tag_id;
1473 GtkTextTag *image_tag;
1475 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1476 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1477 g_free (image_tag_id);
1479 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1481 ((gtk_text_iter_has_tag (&iter, image_tag))||
1482 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1483 data->images = g_list_append (data->images,
1484 g_object_ref (cursor->data));
1486 cursor = g_list_next (cursor);
1489 data->priority_flags = priv->priority_flags;
1496 unref_gobject (GObject *obj, gpointer data)
1498 if (!G_IS_OBJECT(obj))
1500 g_object_unref (obj);
1504 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1507 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1515 g_free (data->from);
1516 g_free (data->subject);
1517 g_free (data->plain_body);
1518 g_free (data->html_body);
1519 g_free (data->account_name);
1521 if (data->draft_msg != NULL) {
1522 g_object_unref (data->draft_msg);
1523 data->draft_msg = NULL;
1526 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1527 g_list_free (data->attachments);
1528 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1529 g_list_free (data->images);
1531 g_slice_free (MsgData, data);
1535 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1538 ModestMsgEditWindowPrivate *priv = NULL;
1539 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1541 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1543 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1545 return MODEST_MSG_EDIT_FORMAT_HTML;
1547 return MODEST_MSG_EDIT_FORMAT_TEXT;
1551 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1552 ModestMsgEditFormat format)
1554 ModestMsgEditWindowPrivate *priv;
1556 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1557 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1560 case MODEST_MSG_EDIT_FORMAT_HTML:
1561 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1563 case MODEST_MSG_EDIT_FORMAT_TEXT:
1564 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1567 g_return_if_reached ();
1571 ModestMsgEditFormatState *
1572 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1574 ModestMsgEditFormatState *format_state = NULL;
1575 ModestMsgEditWindowPrivate *priv;
1576 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1578 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1579 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1581 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1583 format_state = g_new0 (ModestMsgEditFormatState, 1);
1584 format_state->bold = buffer_format->bold&0x1;
1585 format_state->italics = buffer_format->italic&0x1;
1586 format_state->bullet = buffer_format->bullet&0x1;
1587 format_state->color = buffer_format->color;
1588 format_state->font_size = buffer_format->font_size;
1589 format_state->font_family = wp_get_font_name (buffer_format->font);
1590 format_state->justification = buffer_format->justification;
1591 g_free (buffer_format);
1593 return format_state;
1598 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1599 const ModestMsgEditFormatState *format_state)
1601 ModestMsgEditWindowPrivate *priv;
1602 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1603 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1604 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1605 g_return_if_fail (format_state != NULL);
1607 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1608 gtk_widget_grab_focus (priv->msg_body);
1609 buffer_format->bold = (format_state->bold != FALSE);
1610 buffer_format->italic = (format_state->italics != FALSE);
1611 buffer_format->color = format_state->color;
1612 buffer_format->font_size = format_state->font_size;
1613 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1614 buffer_format->justification = format_state->justification;
1615 buffer_format->bullet = format_state->bullet;
1617 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1619 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1620 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1621 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1622 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1623 buffer_format->cs.font = (buffer_format->font != current_format->font);
1624 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1625 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1627 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1628 if (buffer_format->cs.bold) {
1629 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1631 if (buffer_format->cs.italic) {
1632 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1634 if (buffer_format->cs.color) {
1635 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1637 if (buffer_format->cs.font_size) {
1638 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1640 if (buffer_format->cs.justification) {
1641 switch (buffer_format->justification) {
1642 case GTK_JUSTIFY_LEFT:
1643 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1645 case GTK_JUSTIFY_CENTER:
1646 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1648 case GTK_JUSTIFY_RIGHT:
1649 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1656 if (buffer_format->cs.font) {
1657 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1659 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1660 if (buffer_format->cs.bullet) {
1661 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1663 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1665 g_free (current_format);
1670 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1672 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1674 ModestWindowPrivate *parent_priv;
1675 ModestMsgEditWindowPrivate *priv;
1676 GtkWidget *new_size_menuitem;
1677 GtkWidget *new_font_menuitem;
1679 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1680 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1682 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1683 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1684 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1685 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1687 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1688 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1689 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1692 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1694 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1695 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1697 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1698 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1700 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1701 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1703 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1704 G_CALLBACK (modest_msg_edit_window_color_button_change),
1706 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1707 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1708 G_CALLBACK (modest_msg_edit_window_color_button_change),
1711 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1712 buffer_format->font_size))->data);
1713 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1717 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1718 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1719 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1721 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1722 G_CALLBACK (modest_msg_edit_window_size_change),
1724 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1725 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1726 G_CALLBACK (modest_msg_edit_window_size_change),
1730 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1731 buffer_format->font))->data);
1732 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1736 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1737 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1738 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1740 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1741 G_CALLBACK (modest_msg_edit_window_font_change),
1743 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1744 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1745 G_CALLBACK (modest_msg_edit_window_font_change),
1749 g_free (buffer_format);
1753 #ifdef MODEST_HILDON_VERSION_0
1755 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1758 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1759 ModestMsgEditWindowPrivate *priv;
1760 GtkWidget *dialog = NULL;
1762 GdkColor *new_color = NULL;
1764 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1765 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1767 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1768 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1769 g_free (buffer_format);
1771 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1772 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1773 if (new_color != NULL) {
1774 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1775 (gpointer) new_color);
1778 gtk_widget_destroy (dialog);
1783 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1786 ModestMsgEditWindowPrivate *priv;
1787 GtkWidget *dialog = NULL;
1789 GdkColor *old_color = NULL;
1790 const GdkColor *new_color = NULL;
1792 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1793 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1795 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1796 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1798 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1799 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1800 if (new_color != NULL)
1801 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1803 gtk_widget_destroy (dialog);
1809 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1812 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1813 ModestMsgEditWindowPrivate *priv;
1814 GtkWidget *dialog = NULL;
1816 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1817 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1819 dialog = hildon_color_chooser_new ();
1820 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1821 g_free (buffer_format);
1823 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1825 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1826 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1829 gtk_widget_destroy (dialog);
1834 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1837 ModestMsgEditWindowPrivate *priv;
1838 GtkWidget *dialog = NULL;
1839 GdkColor *old_color = NULL;
1841 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1842 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1844 dialog = hildon_color_chooser_new ();
1845 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1847 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1849 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1850 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1852 gtk_widget_destroy (dialog);
1855 #endif /*!MODEST_HILDON_VERSION_0*/
1859 static TnyStream* create_stream_for_uri (const gchar* uri)
1864 TnyStream *result = NULL;
1866 GnomeVFSHandle *handle = NULL;
1867 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1868 if (test == GNOME_VFS_OK) {
1869 /* Create the tinymail stream: */
1870 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1871 result = TNY_STREAM (tny_vfs_stream_new (handle));
1878 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1881 ModestMsgEditWindowPrivate *priv;
1882 GtkWidget *dialog = NULL;
1884 GSList *uris = NULL;
1885 GSList *uri_node = NULL;
1887 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1889 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1890 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1891 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1893 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1895 response = gtk_dialog_run (GTK_DIALOG (dialog));
1897 case GTK_RESPONSE_OK:
1898 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1903 gtk_widget_destroy (dialog);
1905 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1907 GnomeVFSHandle *handle = NULL;
1908 GnomeVFSResult result;
1909 GtkTextIter position;
1910 GtkTextMark *insert_mark;
1912 uri = (const gchar *) uri_node->data;
1913 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1914 if (result == GNOME_VFS_OK) {
1916 GnomeVFSFileInfo info;
1917 gchar *filename, *basename, *escaped_filename;
1918 TnyMimePart *mime_part;
1920 const gchar *mime_type = NULL;
1921 GnomeVFSURI *vfs_uri;
1923 vfs_uri = gnome_vfs_uri_new (uri);
1925 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1926 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1927 g_free (escaped_filename);
1928 gnome_vfs_uri_unref (vfs_uri);
1930 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1931 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1933 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1935 mime_part = tny_platform_factory_new_mime_part
1936 (modest_runtime_get_platform_factory ());
1938 TnyStream *stream = create_stream_for_uri (uri);
1939 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1941 content_id = g_strdup_printf ("%d", priv->last_cid);
1942 tny_mime_part_set_content_id (mime_part, content_id);
1943 g_free (content_id);
1946 basename = g_path_get_basename (filename);
1947 tny_mime_part_set_filename (mime_part, basename);
1950 pixbuf = pixbuf_from_stream (stream, mime_type);
1952 if (pixbuf != NULL) {
1953 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1954 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1955 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1958 priv->images = g_list_prepend (priv->images, mime_part);
1959 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1969 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1971 GtkWidget *dialog = NULL;
1973 GSList *uris = NULL;
1976 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1977 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1978 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1980 response = gtk_dialog_run (GTK_DIALOG (dialog));
1982 case GTK_RESPONSE_OK:
1983 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1988 gtk_widget_destroy (dialog);
1990 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1991 const gchar *uri = (const gchar *) uri_node->data;
1992 modest_msg_edit_window_attach_file_one (window, uri);
1994 g_slist_foreach (uris, (GFunc) g_free, NULL);
1995 g_slist_free (uris);
1999 modest_msg_edit_window_attach_file_one (
2000 ModestMsgEditWindow *window,
2003 g_return_if_fail (window);
2004 g_return_if_fail (uri);
2006 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2009 GnomeVFSHandle *handle = NULL;
2010 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2011 if (result == GNOME_VFS_OK) {
2012 TnyMimePart *mime_part;
2014 const gchar *mime_type = NULL;
2016 gchar *escaped_filename;
2019 GnomeVFSFileInfo info;
2020 GnomeVFSURI *vfs_uri;
2022 vfs_uri = gnome_vfs_uri_new (uri);
2025 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2026 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2027 g_free (escaped_filename);
2028 gnome_vfs_uri_unref (vfs_uri);
2030 if (gnome_vfs_get_file_info (uri,
2032 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2033 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2035 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2036 mime_part = tny_platform_factory_new_mime_part
2037 (modest_runtime_get_platform_factory ());
2038 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2040 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2042 content_id = g_strdup_printf ("%d", priv->last_cid);
2043 tny_mime_part_set_content_id (mime_part, content_id);
2044 g_free (content_id);
2047 basename = g_path_get_basename (filename);
2048 tny_mime_part_set_filename (mime_part, basename);
2051 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2052 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2054 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2055 gtk_widget_show_all (priv->attachments_caption);
2056 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2062 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2065 ModestMsgEditWindowPrivate *priv;
2066 gboolean clean_list = FALSE;
2068 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2069 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2071 if (att_list == NULL) {
2072 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2076 if (att_list == NULL) {
2077 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2079 GtkWidget *confirmation_dialog = NULL;
2080 gboolean dialog_response;
2082 gchar *message = NULL;
2083 gchar *filename = NULL;
2085 if (att_list->next == NULL) {
2086 if (TNY_IS_MSG (att_list->data)) {
2087 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2089 filename = g_strdup (tny_header_get_subject (header));
2090 g_object_unref (header);
2092 if (filename == NULL) {
2093 filename = g_strdup (_("mail_va_no_subject"));
2096 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2099 filename = g_strdup ("");
2101 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2102 att_list->next == NULL), filename);
2104 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2106 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2107 gtk_widget_destroy (confirmation_dialog);
2108 if (!dialog_response) {
2110 g_list_free (att_list);
2113 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2115 for (node = att_list; node != NULL; node = g_list_next (node)) {
2116 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2117 const gchar *att_id;
2118 priv->attachments = g_list_remove (priv->attachments, mime_part);
2120 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2122 if (priv->attachments == NULL)
2123 gtk_widget_hide (priv->attachments_caption);
2124 att_id = tny_mime_part_get_content_id (mime_part);
2126 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2128 g_object_unref (mime_part);
2129 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2134 g_list_free (att_list);
2138 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2141 ModestMsgEditWindowPrivate *priv;
2142 GdkColor *new_color;
2143 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2145 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2146 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2149 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2151 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2153 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2155 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2160 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2163 ModestMsgEditWindowPrivate *priv;
2164 gint new_size_index;
2165 ModestMsgEditWindow *window;
2168 window = MODEST_MSG_EDIT_WINDOW (userdata);
2169 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2170 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2172 if (gtk_check_menu_item_get_active (menu_item)) {
2174 WPTextBufferFormat format;
2176 memset (&format, 0, sizeof (format));
2177 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2179 label = gtk_bin_get_child (GTK_BIN (menu_item));
2181 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2182 format.cs.font_size = TRUE;
2183 format.cs.text_position = TRUE;
2184 format.cs.font = TRUE;
2185 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2186 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2188 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2189 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2190 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2192 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2193 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2194 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2200 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2203 ModestMsgEditWindowPrivate *priv;
2204 gint new_font_index;
2205 ModestMsgEditWindow *window;
2208 window = MODEST_MSG_EDIT_WINDOW (userdata);
2209 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2210 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2212 if (gtk_check_menu_item_get_active (menu_item)) {
2215 label = gtk_bin_get_child (GTK_BIN (menu_item));
2217 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2219 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2220 (gpointer) new_font_index))
2221 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2223 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2224 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2225 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2231 modest_msg_edit_window_set_zoom (ModestWindow *window,
2234 ModestMsgEditWindowPrivate *priv;
2235 ModestWindowPrivate *parent_priv;
2236 GtkRadioAction *zoom_radio_action;
2238 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2240 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2241 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2242 priv->zoom_level = zoom;
2243 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2245 /* Zoom level menu options should be updated with the current zoom level */
2246 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2247 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2248 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2249 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2250 /* FIXME: Not availible before Gtk 2.10 */
2252 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2257 modest_msg_edit_window_get_zoom (ModestWindow *window)
2259 ModestMsgEditWindowPrivate *priv;
2261 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2263 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2264 return priv->zoom_level;
2268 zoom_allowed (ModestMsgEditWindow *window)
2272 focus = gtk_window_get_focus (GTK_WINDOW (window));
2273 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2277 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2279 ModestWindowPrivate *parent_priv;
2280 GtkRadioAction *zoom_radio_action;
2281 GSList *group, *node;
2283 /* First we check if the text view is focused. If not, zooming is not allowed */
2284 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2285 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2289 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2290 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2291 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2293 group = gtk_radio_action_get_group (zoom_radio_action);
2295 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2296 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2300 for (node = group; node != NULL; node = g_slist_next (node)) {
2301 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2302 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2310 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2312 ModestWindowPrivate *parent_priv;
2313 GtkRadioAction *zoom_radio_action;
2314 GSList *group, *node;
2316 /* First we check if the text view is focused. If not, zooming is not allowed */
2317 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2318 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2322 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2323 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2324 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2326 group = gtk_radio_action_get_group (zoom_radio_action);
2328 for (node = group; node != NULL; node = g_slist_next (node)) {
2329 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2330 if (node->next != NULL) {
2331 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2334 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2342 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2344 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2345 ModestWindowPrivate *parent_priv;
2346 ModestWindowMgr *mgr;
2347 gboolean is_fullscreen;
2348 GtkAction *fs_toggle_action;
2351 mgr = modest_runtime_get_window_mgr ();
2352 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2354 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2356 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2357 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2358 if (is_fullscreen != active)
2359 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2367 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2370 ModestMsgEditWindowPrivate *priv = NULL;
2371 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2373 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2374 if (!priv->update_caption_visibility)
2377 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2379 gtk_widget_show (priv->cc_caption);
2381 gtk_widget_hide (priv->cc_caption);
2383 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2387 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2390 ModestMsgEditWindowPrivate *priv = NULL;
2391 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2393 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2394 if (!priv->update_caption_visibility)
2397 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2399 gtk_widget_show (priv->bcc_caption);
2401 gtk_widget_hide (priv->bcc_caption);
2403 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2407 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2408 ModestRecptEditor *editor)
2410 ModestMsgEditWindowPrivate *priv;
2412 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2413 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2414 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2416 if (editor == NULL) {
2417 GtkWidget *view_focus;
2418 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2420 /* This code should be kept in sync with ModestRecptEditor. The
2421 textview inside the recpt editor is the one that really gets the
2422 focus. As it's inside a scrolled window, and this one inside the
2423 hbox recpt editor inherits from, we'll need to go up in the
2424 hierarchy to know if the text view is part of the recpt editor
2425 or if it's a different text entry */
2427 if (gtk_widget_get_parent (view_focus)) {
2428 GtkWidget *first_parent;
2430 first_parent = gtk_widget_get_parent (view_focus);
2431 if (gtk_widget_get_parent (first_parent) &&
2432 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2433 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2438 editor = MODEST_RECPT_EDITOR (priv->to_field);
2442 modest_address_book_select_addresses (editor);
2447 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2449 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2451 modest_msg_edit_window_open_addressbook (window, NULL);
2455 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2456 gboolean show_toolbar)
2458 ModestWindowPrivate *parent_priv;
2459 const gchar *action_name;
2462 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2463 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2465 /* We can not just use the code of
2466 modest_msg_edit_window_setup_toolbar because it has a
2467 mixture of both initialization and creation code. */
2469 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2471 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2473 /* Update also the actions (to update the toggles in the
2474 menus), we have to do it manually because some other window
2475 of the same time could have changed it (remember that the
2476 toolbar fullscreen mode is shared by all the windows of the
2478 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2479 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2481 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2483 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2484 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2490 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2491 TnyHeaderFlags priority_flags)
2493 ModestMsgEditWindowPrivate *priv;
2494 ModestWindowPrivate *parent_priv;
2496 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2498 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2499 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2501 if (priv->priority_flags != priority_flags) {
2502 GtkAction *priority_action = NULL;
2504 priv->priority_flags = priority_flags;
2506 switch (priority_flags) {
2507 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2508 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2509 gtk_widget_show (priv->priority_icon);
2510 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2511 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2513 case TNY_HEADER_FLAG_LOW_PRIORITY:
2514 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2515 gtk_widget_show (priv->priority_icon);
2516 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2517 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2520 gtk_widget_hide (priv->priority_icon);
2521 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2522 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2525 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2526 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2531 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2534 ModestMsgEditWindowPrivate *priv;
2535 ModestWindowPrivate *parent_priv;
2536 gint current_format;
2538 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2540 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2541 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2543 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2544 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2546 if (current_format != file_format) {
2547 switch (file_format) {
2548 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2549 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2550 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2552 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2556 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2557 response = gtk_dialog_run (GTK_DIALOG (dialog));
2558 gtk_widget_destroy (dialog);
2559 if (response == GTK_RESPONSE_OK) {
2560 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2562 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2563 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2568 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2573 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2576 ModestMsgEditWindowPrivate *priv;
2577 WPTextBufferFormat oldfmt, fmt;
2578 gint old_position = 0;
2582 GdkColor *color = NULL;
2583 gboolean bold, bold_set, italic, italic_set;
2584 gboolean underline, underline_set;
2585 gboolean strikethrough, strikethrough_set;
2586 gboolean position_set;
2587 gboolean font_size_set, font_set, color_set;
2590 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2591 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2593 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2595 /* First we get the currently selected font information */
2596 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2597 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2599 switch (oldfmt.text_position) {
2600 case TEXT_POSITION_NORMAL:
2603 case TEXT_POSITION_SUPERSCRIPT:
2611 g_object_set (G_OBJECT (dialog),
2612 "bold", oldfmt.bold != FALSE,
2613 "bold-set", !oldfmt.cs.bold,
2614 "underline", oldfmt.underline != FALSE,
2615 "underline-set", !oldfmt.cs.underline,
2616 "italic", oldfmt.italic != FALSE,
2617 "italic-set", !oldfmt.cs.italic,
2618 "strikethrough", oldfmt.strikethrough != FALSE,
2619 "strikethrough-set", !oldfmt.cs.strikethrough,
2620 "color", &oldfmt.color,
2621 "color-set", !oldfmt.cs.color,
2622 "size", wp_font_size[oldfmt.font_size],
2623 "size-set", !oldfmt.cs.font_size,
2624 "position", old_position,
2625 "position-set", !oldfmt.cs.text_position,
2626 "family", wp_get_font_name (oldfmt.font),
2627 "family-set", !oldfmt.cs.font,
2630 gtk_widget_show_all (dialog);
2631 response = gtk_dialog_run (GTK_DIALOG (dialog));
2632 if (response == GTK_RESPONSE_OK) {
2634 g_object_get( dialog,
2636 "bold-set", &bold_set,
2637 "underline", &underline,
2638 "underline-set", &underline_set,
2640 "italic-set", &italic_set,
2641 "strikethrough", &strikethrough,
2642 "strikethrough-set", &strikethrough_set,
2644 "color-set", &color_set,
2646 "size-set", &font_size_set,
2647 "family", &font_name,
2648 "family-set", &font_set,
2649 "position", &position,
2650 "position-set", &position_set,
2655 if (response == GTK_RESPONSE_OK) {
2656 memset(&fmt, 0, sizeof(fmt));
2662 fmt.italic = italic;
2663 fmt.cs.italic = TRUE;
2665 if (underline_set) {
2666 fmt.underline = underline;
2667 fmt.cs.underline = TRUE;
2669 if (strikethrough_set) {
2670 fmt.strikethrough = strikethrough;
2671 fmt.cs.strikethrough = TRUE;
2676 ? TEXT_POSITION_NORMAL
2677 : ( ( position == 1 )
2678 ? TEXT_POSITION_SUPERSCRIPT
2679 : TEXT_POSITION_SUBSCRIPT );
2680 fmt.cs.text_position = TRUE;
2684 fmt.cs.color = TRUE;
2687 fmt.font = wp_get_font_index(font_name,
2692 if (font_size_set) {
2693 fmt.font_size = wp_get_font_size_index(
2694 font_size, DEFAULT_FONT_SIZE);
2695 fmt.cs.font_size = TRUE;
2697 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2698 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2700 gtk_widget_destroy (dialog);
2702 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2706 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2708 ModestMsgEditWindowPrivate *priv;
2710 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2711 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2713 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2715 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2720 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2722 ModestMsgEditWindowPrivate *priv;
2724 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2725 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2727 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2729 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2734 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2736 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2738 priv->can_undo = can_undo;
2742 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2744 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2746 priv->can_redo = can_redo;
2750 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2752 ModestMsgEditWindowPrivate *priv;
2753 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2754 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2756 return priv->can_undo;
2760 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2762 ModestMsgEditWindowPrivate *priv;
2763 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2764 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2766 return priv->can_redo;
2771 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2774 GtkTextIter match_start, match_end;
2776 if (image_id == NULL)
2779 gtk_text_buffer_get_start_iter (buffer, &iter);
2781 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2782 GSList *tags = gtk_text_iter_get_tags (&match_start);
2784 for (node = tags; node != NULL; node = g_slist_next (node)) {
2785 GtkTextTag *tag = (GtkTextTag *) node->data;
2786 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2787 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2788 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2790 offset = gtk_text_iter_get_offset (&match_start);
2791 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2792 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2796 gtk_text_iter_forward_char (&iter);
2801 message_is_empty (ModestMsgEditWindow *window)
2803 ModestMsgEditWindowPrivate *priv = NULL;
2805 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2806 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2808 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2809 * so we can ignore markup.
2811 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2814 count = gtk_text_buffer_get_char_count (buf);
2820 msg_body_focus (GtkWidget *focus,
2821 GdkEventFocus *event,
2825 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2830 recpt_field_changed (GtkTextBuffer *buffer,
2831 ModestMsgEditWindow *editor)
2833 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2837 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2839 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2843 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2845 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2846 GtkTextBuffer *buffer;
2848 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2849 gtk_text_buffer_set_modified (buffer, FALSE);
2850 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2851 gtk_text_buffer_set_modified (buffer, FALSE);
2852 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2853 gtk_text_buffer_set_modified (buffer, FALSE);
2854 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2858 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2860 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2861 GtkTextBuffer *buffer;
2863 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2864 if (gtk_text_buffer_get_modified (buffer))
2866 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2867 if (gtk_text_buffer_get_modified (buffer))
2869 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2870 if (gtk_text_buffer_get_modified (buffer))
2872 if (gtk_text_buffer_get_modified (priv->text_buffer))
2882 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2884 ModestMsgEditWindowPrivate *priv = NULL;
2886 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2887 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2889 /* check if there's no recipient added */
2890 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2891 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2892 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2893 /* no recipient contents, then select contacts */
2894 modest_msg_edit_window_open_addressbook (window, NULL);
2898 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2899 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2902 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2903 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2906 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2907 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2911 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2912 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2913 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2920 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2921 ModestMsgEditWindow *window)
2923 modest_msg_edit_window_offer_attach_file (window);
2927 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2929 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2931 return priv->clipboard_text;
2935 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2937 ModestMsgEditWindow *window)
2939 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2940 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2942 if (!GTK_WIDGET_VISIBLE (window))
2945 text = gtk_clipboard_wait_for_text (selection_clipboard);
2947 if (priv->clipboard_text != NULL) {
2948 g_free (priv->clipboard_text);
2950 priv->clipboard_text = text;
2952 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2955 subject_field_move_cursor (GtkEntry *entry,
2956 GtkMovementStep step,
2961 if (!GTK_WIDGET_VISIBLE (window))
2964 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2968 update_window_title (ModestMsgEditWindow *window)
2970 ModestMsgEditWindowPrivate *priv = NULL;
2971 const gchar *subject;
2973 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2974 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2975 if (subject == NULL || subject[0] == '\0')
2976 subject = _("mail_va_new_email");
2978 gtk_window_set_title (GTK_WINDOW (window), subject);
2983 subject_field_changed (GtkEditable *editable,
2984 ModestMsgEditWindow *window)
2986 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2987 update_window_title (window);
2988 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2989 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2993 subject_field_insert_text (GtkEditable *editable,
2995 gint new_text_length,
2997 ModestMsgEditWindow *window)
2999 GString *result = g_string_new ("");
3001 gint result_len = 0;
3002 const gchar *entry_text = NULL;
3005 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3006 old_length = g_utf8_strlen (entry_text, -1);
3008 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3009 gunichar c = g_utf8_get_char_validated (current, 8);
3010 /* Invalid unichar, stop */
3016 result = g_string_append_unichar (result, c);
3020 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3021 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3024 /* Prevent endless recursion */
3025 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3026 g_signal_emit_by_name (editable, "insert-text",
3027 (gpointer) result->str, (gpointer) result->len,
3028 (gpointer) position, (gpointer) window);
3029 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3033 if (result_len + old_length > 1000) {
3034 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3035 dgettext("hildon-common-strings",
3036 "ckdg_ib_maximum_characters_reached"));
3039 g_string_free (result, TRUE);
3043 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3046 ModestMsgEditWindowPrivate *priv = NULL;
3048 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3049 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3051 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3054 gtk_widget_show_all (priv->find_toolbar);
3055 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3057 gtk_widget_hide_all (priv->find_toolbar);
3058 gtk_widget_grab_focus (priv->msg_body);
3064 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3066 GtkTextIter *match_start,
3067 GtkTextIter *match_end)
3069 GtkTextIter end_iter;
3070 gchar *str_casefold;
3073 gchar *range_casefold;
3076 gboolean result = FALSE;
3083 gtk_text_iter_forward_to_end (&end_iter);
3085 str_casefold = g_utf8_casefold (str, -1);
3086 str_chars_n = strlen (str);
3088 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3089 range_casefold = g_utf8_casefold (range_text, -1);
3090 range_chars_n = strlen (range_casefold);
3092 if (range_chars_n < str_chars_n) {
3093 g_free (str_casefold);
3094 g_free (range_text);
3095 g_free (range_casefold);
3099 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3100 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3101 if (!g_utf8_collate (range_subtext, str_casefold)) {
3102 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3104 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3105 match_start, match_end, NULL);
3106 g_free (found_text);
3108 g_free (range_subtext);
3112 g_free (str_casefold);
3113 g_free (range_text);
3114 g_free (range_casefold);
3121 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3122 ModestMsgEditWindow *window)
3124 gchar *current_search = NULL;
3125 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3127 GtkTextIter selection_start, selection_end;
3128 GtkTextIter match_start, match_end;
3129 gboolean continue_search = FALSE;
3131 if (message_is_empty (window)) {
3132 g_free (priv->last_search);
3133 priv->last_search = NULL;
3134 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3138 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3139 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3140 g_free (current_search);
3141 g_free (priv->last_search);
3142 priv->last_search = NULL;
3143 /* Information banner about empty search */
3144 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3148 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3149 continue_search = TRUE;
3151 g_free (priv->last_search);
3152 priv->last_search = g_strdup (current_search);
3155 if (continue_search) {
3156 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3157 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3158 &match_start, &match_end);
3160 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3162 GtkTextIter buffer_start;
3163 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3164 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3165 &match_start, &match_end);
3167 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3170 /* Mark as selected the string found in search */
3172 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3173 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3175 g_free (priv->last_search);
3176 priv->last_search = NULL;
3178 g_free (current_search);
3182 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3183 ModestMsgEditWindow *window)
3185 GtkToggleAction *toggle;
3186 ModestWindowPrivate *parent_priv;
3187 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3189 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3190 gtk_toggle_action_set_active (toggle, FALSE);
3194 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3196 ModestMsgEditWindowPrivate *priv;
3198 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3203 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3206 ModestMsgEditWindowPrivate *priv;
3208 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3214 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3217 ModestMsgEditWindowPrivate *priv;
3218 TnyHeader *header = NULL;
3220 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3221 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3223 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3224 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3226 if (priv->draft_msg != NULL) {
3227 g_object_unref (priv->draft_msg);
3230 if (draft != NULL) {
3231 g_object_ref (draft);
3232 header = tny_msg_get_header (draft);
3233 if (priv->msg_uid) {
3234 g_free (priv->msg_uid);
3235 priv->msg_uid = NULL;
3237 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3238 if (GTK_WIDGET_REALIZED (window))
3239 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3242 priv->draft_msg = draft;
3246 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3247 GtkTextIter *start, GtkTextIter *end,
3250 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3251 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3254 if (tag == NULL+13) return;
3255 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3256 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3257 replace_with_images (window, priv->images);
3262 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3265 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3267 g_return_if_fail (TNY_IS_MIME_PART (part));
3268 priv->attachments = g_list_prepend (priv->attachments, part);
3269 g_object_ref (part);
3270 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3271 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3272 gtk_widget_show_all (priv->attachments_caption);
3273 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3277 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3279 ModestMsgEditWindowPrivate *priv;
3281 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3282 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3284 return priv->msg_uid;
3288 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3289 ModestMsgEditWindowWidgetType widget_type)
3291 ModestMsgEditWindowPrivate *priv;
3293 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3294 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3296 switch (widget_type) {
3297 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3298 return priv->msg_body;
3300 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3301 return priv->to_field;
3303 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3304 return priv->cc_field;
3306 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3307 return priv->bcc_field;
3309 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3310 return priv->subject_field;
3312 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3313 return priv->attachments_view;
3321 remove_tags (WPTextBuffer *buffer)
3323 GtkTextIter start, end;
3325 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3326 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3328 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3332 on_account_removed (TnyAccountStore *account_store,
3333 TnyAccount *account,
3336 /* Do nothing if it's a store account, because we use the
3337 transport to send the messages */
3338 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3339 const gchar *parent_acc = NULL;
3340 const gchar *our_acc = NULL;
3342 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3343 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3344 /* Close this window if I'm showing a message of the removed account */
3345 if (strcmp (parent_acc, our_acc) == 0)
3346 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));