1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include <modest-utils.h>
79 #include "modest-maemo-utils.h"
82 #define DEFAULT_FONT_SIZE 3
83 #define DEFAULT_FONT 2
84 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
85 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
86 #define DEFAULT_MAIN_VBOX_SPACING 6
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #define DEFAULT_FONT_SCALE 1.5
91 static gboolean is_wp_text_buffer_started = FALSE;
93 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
94 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
95 static void modest_msg_edit_window_finalize (GObject *obj);
97 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
98 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
99 static void attachments_selection_changed (ModestAttachmentsView *buffer, ModestMsgEditWindow *editor);
100 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
102 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
103 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
104 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
105 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
106 GtkTextIter *start, GtkTextIter *end,
108 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
109 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
110 static void subject_field_insert_text (GtkEditable *editable,
112 gint new_text_length,
114 ModestMsgEditWindow *window);
115 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
117 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
119 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
121 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
122 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
123 GdkEventWindowState *event,
125 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
126 ModestRecptEditor *editor);
127 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
128 ModestMsgEditWindow *window);
130 /* ModestWindow methods implementation */
131 static void modest_msg_edit_window_disconnect_signals (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 gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
162 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
164 static gdouble get_zoom_do_nothing (ModestWindow *window);
166 static void init_window (ModestMsgEditWindow *obj);
168 static void DEBUG_BUFFER (WPTextBuffer *buffer)
172 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
174 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
175 while (!gtk_text_iter_is_end (&iter)) {
176 GString *output = g_string_new ("");
177 GSList *toggled_tags;
180 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
181 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
182 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
183 GtkTextTag *tag = (GtkTextTag *) node->data;
185 g_object_get (G_OBJECT (tag), "name", &name, NULL);
186 output = g_string_append (output, name);
187 g_string_append (output, " ");
189 output = g_string_append (output, "] OPENED [ ");
190 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
191 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
192 GtkTextTag *tag = (GtkTextTag *) node->data;
194 g_object_get (G_OBJECT (tag), "name", &name, NULL);
195 output = g_string_append (output, name);
196 g_string_append (output, " ");
198 output = g_string_append (output, "]\n");
199 g_message ("%s", output->str);
200 g_string_free (output, TRUE);
201 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
203 g_message ("END BUFFER");
208 /* static gboolean */
209 /* on_key_pressed (GtkWidget *self, */
210 /* GdkEventKey *event, */
211 /* gpointer user_data); */
213 /* list my signals */
220 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
221 struct _ModestMsgEditWindowPrivate {
223 GtkWidget *header_box;
225 ModestPairList *from_field_protos;
226 GtkWidget *from_field;
230 GtkWidget *bcc_field;
231 GtkWidget *subject_field;
232 GtkWidget *attachments_view;
233 GtkWidget *priority_icon;
234 GtkWidget *add_attachment_button;
236 GtkWidget *cc_caption;
237 GtkWidget *bcc_caption;
238 gboolean update_caption_visibility;
239 GtkWidget *attachments_caption;
241 GtkTextBuffer *text_buffer;
243 GtkWidget *font_size_toolitem;
244 GtkWidget *font_face_toolitem;
245 GtkWidget *font_color_button;
246 GSList *font_items_group;
247 GtkWidget *font_tool_button_label;
248 GSList *size_items_group;
249 GtkWidget *size_tool_button_label;
251 GtkWidget *find_toolbar;
255 GtkWidget *scroll_area;
256 gint last_vadj_upper;
259 TnyList *attachments;
262 TnyHeaderFlags priority_flags;
264 gboolean can_undo, can_redo;
265 gulong clipboard_change_handler_id;
266 gulong default_clipboard_change_handler_id;
267 gulong account_removed_handler_id;
268 gchar *clipboard_text;
277 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
278 MODEST_TYPE_MSG_EDIT_WINDOW, \
279 ModestMsgEditWindowPrivate))
281 static GtkWindowClass *parent_class = NULL;
283 /* uncomment the following if you have defined any signals */
284 /* static guint signals[LAST_SIGNAL] = {0}; */
287 modest_msg_edit_window_get_type (void)
289 static GType my_type = 0;
291 static const GTypeInfo my_info = {
292 sizeof(ModestMsgEditWindowClass),
293 NULL, /* base init */
294 NULL, /* base finalize */
295 (GClassInitFunc) modest_msg_edit_window_class_init,
296 NULL, /* class finalize */
297 NULL, /* class data */
298 sizeof(ModestMsgEditWindow),
300 (GInstanceInitFunc) modest_msg_edit_window_init,
303 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
304 "ModestMsgEditWindow",
312 save_state (ModestWindow *self)
314 modest_widget_memory_save (modest_runtime_get_conf(),
315 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
320 restore_settings (ModestMsgEditWindow *self)
322 ModestConf *conf = NULL;
324 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
326 conf = modest_runtime_get_conf ();
327 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
328 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
329 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
330 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
331 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
332 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
333 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
334 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
336 /* set initial state of cc and bcc */
337 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
338 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
339 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
340 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
341 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
342 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
344 /* Dim at start clipboard actions */
345 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
346 gtk_action_set_sensitive (action, FALSE);
347 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
348 gtk_action_set_sensitive (action, FALSE);
349 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
350 gtk_action_set_sensitive (action, FALSE);
352 modest_widget_memory_restore (conf,
353 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
358 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
360 GObjectClass *gobject_class;
361 ModestWindowClass *modest_window_class;
362 gobject_class = (GObjectClass*) klass;
363 modest_window_class = (ModestWindowClass*) klass;
365 parent_class = g_type_class_peek_parent (klass);
366 gobject_class->finalize = modest_msg_edit_window_finalize;
368 modest_window_class->set_zoom_func = set_zoom_do_nothing;
369 modest_window_class->get_zoom_func = get_zoom_do_nothing;
370 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
371 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
372 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
373 modest_window_class->save_state_func = save_state;
374 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
376 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
380 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
382 ModestMsgEditWindowPrivate *priv;
383 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
385 priv->msg_body = NULL;
386 priv->from_field = NULL;
387 priv->to_field = NULL;
388 priv->cc_field = NULL;
389 priv->bcc_field = NULL;
390 priv->subject_field = NULL;
391 priv->attachments = TNY_LIST (tny_simple_list_new ());
392 priv->images = TNY_LIST (tny_simple_list_new ());
395 priv->cc_caption = NULL;
396 priv->bcc_caption = NULL;
397 priv->update_caption_visibility = FALSE;
399 priv->priority_flags = 0;
401 priv->find_toolbar = NULL;
402 priv->last_search = NULL;
404 priv->draft_msg = NULL;
405 priv->outbox_msg = NULL;
406 priv->msg_uid = NULL;
408 priv->can_undo = FALSE;
409 priv->can_redo = FALSE;
410 priv->clipboard_change_handler_id = 0;
411 priv->default_clipboard_change_handler_id = 0;
412 priv->account_removed_handler_id = 0;
413 priv->clipboard_text = NULL;
416 priv->last_vadj_upper = 0;
418 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
419 GTK_WINDOW(obj),"applications_email_editor");
421 if (!is_wp_text_buffer_started) {
422 is_wp_text_buffer_started = TRUE;
423 wp_text_buffer_library_init ();
428 hildon_program_add_window (hildon_program_get_instance(),
433 /* FIXME: this is a dup from the one in gtk/ */
436 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
438 static ModestPairList*
439 get_transports (void)
441 GSList *transports = NULL;
443 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
444 GSList *accounts = modest_account_mgr_account_names (account_mgr,
445 TRUE /* only enabled accounts. */);
447 GSList *cursor = accounts;
449 gchar *account_name = cursor->data;
450 gchar *from_string = NULL;
452 from_string = modest_account_mgr_get_from_string (account_mgr,
456 if (from_string && account_name) {
457 gchar *name = account_name;
458 ModestPair *pair = modest_pair_new ((gpointer) name,
459 (gpointer) from_string , TRUE);
460 transports = g_slist_prepend (transports, pair);
463 cursor = cursor->next;
465 g_slist_free (accounts); /* only free the accounts, not the elements,
466 * because they are used in the pairlist */
470 void vadj_changed (GtkAdjustment *adj,
471 ModestMsgEditWindow *window)
473 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
475 GdkRectangle rectangle, cursor_rectangle;
476 GtkTextIter position;
480 /* We detect if cursor is visible using the full height, not only the center. This
482 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
483 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
485 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
486 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
488 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
489 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
491 if (gtk_widget_is_focus (priv->msg_body) &&
493 if (priv->last_vadj_upper != adj->upper) {
496 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
497 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
498 insert, 0.1, FALSE, 0.0, 0.0);
501 priv->last_vadj_upper = adj->upper;
506 connect_signals (ModestMsgEditWindow *obj)
508 ModestMsgEditWindowPrivate *priv;
510 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
512 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
513 G_CALLBACK (text_buffer_refresh_attributes), obj);
514 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
515 G_CALLBACK (text_buffer_can_undo), obj);
516 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
517 G_CALLBACK (text_buffer_can_redo), obj);
518 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
519 G_CALLBACK (body_changed), obj);
520 g_signal_connect (G_OBJECT (priv->attachments_view), "selection-changed",
521 G_CALLBACK (attachments_selection_changed), obj);
522 g_signal_connect (G_OBJECT (obj), "window-state-event",
523 G_CALLBACK (modest_msg_edit_window_window_state_event),
525 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
526 G_CALLBACK (text_buffer_apply_tag), obj);
527 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
528 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
529 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
530 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
531 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
532 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
534 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
535 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
537 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
538 G_CALLBACK (msg_body_focus), obj);
539 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
540 G_CALLBACK (msg_body_focus), obj);
541 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
542 "changed", G_CALLBACK (recpt_field_changed), obj);
543 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
544 "changed", G_CALLBACK (recpt_field_changed), obj);
545 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
546 "changed", G_CALLBACK (recpt_field_changed), obj);
547 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
548 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
549 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
551 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
552 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
554 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
556 G_CALLBACK (vadj_changed),
559 priv->clipboard_change_handler_id =
560 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
561 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
562 priv->default_clipboard_change_handler_id =
563 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
564 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
569 init_window (ModestMsgEditWindow *obj)
571 GtkWidget *from_caption, *to_caption, *subject_caption;
572 GtkWidget *main_vbox;
573 ModestMsgEditWindowPrivate *priv;
574 GtkActionGroup *action_group;
575 ModestWindowPrivate *parent_priv;
576 GdkPixbuf *window_icon = NULL;
577 GError *error = NULL;
579 GtkSizeGroup *size_group;
581 GtkWidget *subject_box;
582 GtkWidget *attachment_icon;
583 GtkWidget *window_box;
584 #if (GTK_MINOR_VERSION >= 10)
585 GdkAtom deserialize_type;
587 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
588 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
590 parent_priv->ui_manager = gtk_ui_manager_new();
591 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
592 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
594 /* Add common actions */
595 gtk_action_group_add_actions (action_group,
596 modest_msg_edit_action_entries,
597 G_N_ELEMENTS (modest_msg_edit_action_entries),
599 gtk_action_group_add_toggle_actions (action_group,
600 modest_msg_edit_toggle_action_entries,
601 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
603 gtk_action_group_add_radio_actions (action_group,
604 modest_msg_edit_alignment_radio_action_entries,
605 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
607 G_CALLBACK (modest_ui_actions_on_change_justify),
609 gtk_action_group_add_radio_actions (action_group,
610 modest_msg_edit_priority_action_entries,
611 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
613 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
615 gtk_action_group_add_radio_actions (action_group,
616 modest_msg_edit_file_format_action_entries,
617 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
618 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
619 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
621 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
622 g_object_unref (action_group);
624 /* Load the UI definition */
625 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
628 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
629 g_clear_error (&error);
632 /* Add accelerators */
633 gtk_window_add_accel_group (GTK_WINDOW (obj),
634 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
636 parent_priv->menubar = NULL;
638 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
640 /* Note: This ModestPairList* must exist for as long as the combo
641 * that uses it, because the ModestComboBox uses the ID opaquely,
642 * so it can't know how to manage its memory. */
643 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
645 priv->to_field = modest_recpt_editor_new ();
646 priv->cc_field = modest_recpt_editor_new ();
647 priv->bcc_field = modest_recpt_editor_new ();
648 subject_box = gtk_hbox_new (FALSE, 0);
649 priv->priority_icon = gtk_image_new ();
650 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
651 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
652 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
653 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
654 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
655 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
656 priv->add_attachment_button = gtk_button_new ();
657 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
658 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
659 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
660 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
661 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
662 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
663 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
664 priv->attachments_view = modest_attachments_view_new (NULL);
666 priv->header_box = gtk_vbox_new (FALSE, 0);
668 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
669 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
670 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
671 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
672 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
673 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
674 g_object_unref (size_group);
676 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
677 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
678 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
679 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
680 gtk_size_group_add_widget (size_group, priv->subject_field);
681 gtk_size_group_add_widget (size_group, priv->attachments_view);
682 g_object_unref (size_group);
684 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
685 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
686 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
687 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
688 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
689 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
690 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
693 priv->msg_body = wp_text_view_new ();
694 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
695 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
696 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
697 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
698 #if (GTK_MINOR_VERSION >= 10)
699 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
700 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
702 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
703 deserialize_type, TRUE);
705 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
707 priv->find_toolbar = hildon_find_toolbar_new (NULL);
708 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
710 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
712 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
713 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
714 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
715 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
717 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
719 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
720 frame = gtk_frame_new (NULL);
721 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
723 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
724 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
725 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
727 G_CALLBACK (vadj_changed),
729 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
731 window_box = gtk_vbox_new (FALSE, 0);
732 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
733 gtk_container_add (GTK_CONTAINER(obj), window_box);
734 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
735 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
737 /* Set window icon */
738 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
740 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
741 g_object_unref (window_icon);
746 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
748 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
750 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
751 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
752 priv->clipboard_change_handler_id))
753 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
754 priv->clipboard_change_handler_id);
755 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
756 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
757 priv->default_clipboard_change_handler_id))
758 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
759 priv->default_clipboard_change_handler_id);
761 if (priv->account_removed_handler_id &&
762 g_signal_handler_is_connected (modest_runtime_get_account_store (),
763 priv->account_removed_handler_id))
764 g_signal_handler_disconnect(modest_runtime_get_account_store (),
765 priv->account_removed_handler_id);
769 modest_msg_edit_window_finalize (GObject *obj)
771 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
773 /* Sanity check: shouldn't be needed, the window mgr should
774 call this function before */
775 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
777 if (priv->clipboard_text != NULL) {
778 g_free (priv->clipboard_text);
779 priv->clipboard_text = NULL;
782 if (priv->draft_msg != NULL) {
783 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
784 if (TNY_IS_HEADER (header)) {
785 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
786 modest_window_mgr_unregister_header (mgr, header);
788 g_object_unref (priv->draft_msg);
789 priv->draft_msg = NULL;
791 if (priv->outbox_msg != NULL) {
792 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
793 if (TNY_IS_HEADER (header)) {
794 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
795 modest_window_mgr_unregister_header (mgr, header);
797 g_object_unref (priv->outbox_msg);
798 priv->outbox_msg = NULL;
800 g_free (priv->msg_uid);
801 g_free (priv->last_search);
802 g_slist_free (priv->font_items_group);
803 g_slist_free (priv->size_items_group);
804 g_object_unref (priv->attachments);
805 g_object_unref (priv->images);
807 /* This had to stay alive for as long as the combobox that used it: */
808 modest_pair_list_free (priv->from_field_protos);
810 G_OBJECT_CLASS(parent_class)->finalize (obj);
814 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
816 GdkPixbufLoader *loader;
819 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
824 tny_stream_reset (TNY_STREAM (stream));
825 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
826 unsigned char read_buffer[128];
828 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
829 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
833 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
834 g_object_ref (pixbuf);
835 gdk_pixbuf_loader_close (loader, NULL);
836 g_object_unref (loader);
838 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
839 GdkPixbuf *new_pixbuf;
841 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
842 gdk_pixbuf_get_width (pixbuf);
843 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
844 g_object_unref (pixbuf);
852 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
854 ModestMsgEditWindowPrivate *priv;
857 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
859 for (iter = tny_list_create_iterator (attachments);
860 !tny_iterator_is_done (iter);
861 tny_iterator_next (iter)) {
862 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
863 const gchar *cid = tny_mime_part_get_content_id (part);
864 const gchar *mime_type = tny_mime_part_get_content_type (part);
865 if ((cid != NULL)&&(mime_type != NULL)) {
866 TnyStream *stream = tny_mime_part_get_stream (part);
867 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
868 g_object_unref (stream);
870 if (pixbuf != NULL) {
871 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
872 g_object_unref (pixbuf);
875 g_object_unref (part);
880 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
882 TnyMimePart *parent = NULL;
883 const gchar *content_type = NULL;
884 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
886 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
888 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
889 parent = g_object_ref (msg);
890 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
891 TnyList *parts = TNY_LIST (tny_simple_list_new ());
894 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
895 iter = tny_list_create_iterator (parts);
896 while (!tny_iterator_is_done (iter)) {
898 part = TNY_MIME_PART (tny_iterator_get_current (iter));
899 content_type = tny_mime_part_get_content_type (part);
900 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
904 g_object_unref (part);
906 tny_iterator_next (iter);
908 g_object_unref (iter);
909 g_object_unref (parts);
912 if (parent != NULL) {
913 TnyList *parts = TNY_LIST (tny_simple_list_new ());
916 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
917 iter = tny_list_create_iterator (parts);
918 while (!tny_iterator_is_done (iter)) {
920 part = TNY_MIME_PART (tny_iterator_get_current (iter));
921 content_type = tny_mime_part_get_content_type (part);
922 if (content_type && g_str_has_prefix (content_type, "image/")) {
923 tny_list_prepend (priv->images, (GObject *) part);
925 g_object_unref (part);
926 tny_iterator_next (iter);
928 g_object_unref (iter);
929 g_object_unref (parts);
930 g_object_unref (parent);
935 update_last_cid (ModestMsgEditWindow *self, TnyList *attachments)
938 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
940 for (iter = tny_list_create_iterator (attachments) ;
941 !tny_iterator_is_done (iter);
942 tny_iterator_next (iter)) {
943 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
944 const gchar *cid = tny_mime_part_get_content_id (part);
946 char *invalid = NULL;
947 gint int_cid = strtol (cid, &invalid, 10);
948 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
949 priv->last_cid = int_cid;
952 g_object_unref (part);
957 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
960 const gchar *to, *cc, *bcc, *subject;
962 ModestMsgEditWindowPrivate *priv;
964 TnyHeaderFlags priority_flags;
965 TnyFolder *msg_folder;
966 gboolean is_html = FALSE;
968 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
969 g_return_if_fail (TNY_IS_MSG (msg));
971 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
973 header = tny_msg_get_header (msg);
974 to = tny_header_get_to (header);
975 cc = tny_header_get_cc (header);
976 bcc = tny_header_get_bcc (header);
977 subject = tny_header_get_subject (header);
978 priority_flags = tny_header_get_priority (header);
981 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
983 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
984 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
985 gtk_widget_show (priv->cc_caption);
986 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
987 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
988 gtk_widget_hide (priv->cc_caption);
991 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
992 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
993 gtk_widget_show (priv->bcc_caption);
994 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
995 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
996 gtk_widget_hide (priv->bcc_caption);
999 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1000 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1003 update_window_title (self);
1005 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1006 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1008 if ((body == NULL)||(body[0] == '\0')) {
1010 body = modest_text_utils_convert_to_html ("");
1013 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1014 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1017 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1020 /* Add attachments to the view */
1021 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1022 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1023 if (tny_list_get_length (priv->attachments) == 0) {
1024 gtk_widget_hide (priv->attachments_caption);
1026 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1027 gtk_widget_show_all (priv->attachments_caption);
1029 get_related_images (self, msg);
1030 update_last_cid (self, priv->attachments);
1031 update_last_cid (self, priv->images);
1032 replace_with_images (self, priv->images);
1034 if (preserve_is_rich && !is_html) {
1035 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1036 /* Get the default format required from configuration */
1037 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1038 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1041 /* Set the default focus depending on having already a To: field or not */
1042 if ((!to)||(*to == '\0')) {
1043 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1045 gtk_widget_grab_focus (priv->msg_body);
1048 /* TODO: lower priority, select in the From: combo to the
1049 value that comes from msg <- not sure, should it be
1052 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1054 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1055 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1057 modest_msg_edit_window_reset_modified (self);
1059 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (self));
1060 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1061 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1063 if (priv->msg_uid) {
1064 g_free (priv->msg_uid);
1065 priv->msg_uid = NULL;
1068 /* we should set a reference to the incoming message if it is a draft */
1069 msg_folder = tny_msg_get_folder (msg);
1071 if (modest_tny_folder_is_local_folder (msg_folder)) {
1072 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1073 if (type == TNY_FOLDER_TYPE_INVALID)
1074 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1076 if (type == TNY_FOLDER_TYPE_DRAFTS)
1077 priv->draft_msg = g_object_ref(msg);
1078 if (type == TNY_FOLDER_TYPE_OUTBOX)
1079 priv->outbox_msg = g_object_ref(msg);
1080 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1082 g_object_unref (msg_folder);
1087 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1090 GList *item_children, *node;
1091 GtkWidget *bin_child;
1093 bin_child = gtk_bin_get_child (GTK_BIN(item));
1095 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1097 for (node = item_children; node != NULL; node = g_list_next (node)) {
1098 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1099 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1102 g_list_free (item_children);
1106 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1109 GList *item_children, *node;
1111 box = gtk_bin_get_child (GTK_BIN (item));
1112 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1113 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1115 for (node = item_children; node != NULL; node = g_list_next (node)) {
1116 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1117 if (GTK_IS_TOGGLE_BUTTON (node->data))
1118 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1119 else if (GTK_IS_BUTTON (node->data))
1120 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1122 g_list_free (item_children);
1127 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1129 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1130 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1131 GtkWidget *placeholder;
1132 GtkWidget *tool_item;
1137 GtkWidget *sizes_menu;
1138 GtkWidget *fonts_menu;
1139 GSList *radio_group = NULL;
1140 GSList *node = NULL;
1144 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1145 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1147 /* Font color placeholder */
1148 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1149 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1152 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1153 priv->font_color_button = hildon_color_button_new ();
1154 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1155 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1156 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1157 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1158 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1159 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1160 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1162 G_CALLBACK (modest_msg_edit_window_color_button_change),
1165 /* Font size and face placeholder */
1166 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1167 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1169 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1170 priv->size_tool_button_label = gtk_label_new (NULL);
1171 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1172 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1173 size_text,"</span>", NULL);
1174 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1176 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1177 sizes_menu = gtk_menu_new ();
1178 priv->size_items_group = NULL;
1180 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1181 GtkWidget *size_menu_item;
1183 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1184 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1185 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1186 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1187 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1188 gtk_widget_show (size_menu_item);
1190 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1194 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1195 GtkWidget *item = (GtkWidget *) node->data;
1196 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1200 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1201 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1202 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1203 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1204 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1205 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1206 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1207 priv->font_size_toolitem = tool_item;
1210 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1211 priv->font_tool_button_label = gtk_label_new (NULL);
1212 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1213 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1215 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1216 fonts_menu = gtk_menu_new ();
1217 priv->font_items_group = NULL;
1219 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1220 GtkWidget *font_menu_item;
1221 GtkWidget *child_label;
1223 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1224 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1225 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1226 wp_get_font_name (font_index), "</span>", NULL);
1227 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1230 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1231 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1232 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1233 gtk_widget_show (font_menu_item);
1235 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1238 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1239 GtkWidget *item = (GtkWidget *) node->data;
1240 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1243 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1244 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1245 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1246 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1247 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1248 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1249 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1250 priv->font_face_toolitem = tool_item;
1252 /* Set expand and homogeneous for remaining items */
1253 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1254 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1255 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1256 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
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/ActionsItalics");
1260 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1261 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1263 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1264 will not show the tool items added to the placeholders) */
1265 gtk_widget_show_all (parent_priv->toolbar);
1267 /* Set the no show all *after* showing all items. We do not
1268 want the toolbar to be shown with a show all because it
1269 could go agains the gconf setting regarding showing or not
1270 the toolbar of the editor window */
1271 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1277 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1280 ModestWindowPrivate *parent_priv;
1281 ModestMsgEditWindowPrivate *priv;
1282 ModestPair *account_pair = NULL;
1283 ModestDimmingRulesGroup *window_rules_group = NULL;
1284 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1285 ModestWindowMgr *mgr = NULL;
1287 g_return_val_if_fail (msg, NULL);
1288 g_return_val_if_fail (account_name, NULL);
1290 mgr = modest_runtime_get_window_mgr ();
1292 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1294 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1295 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1297 /* Menubar. Update the state of some toggles */
1298 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1299 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1300 priv->from_field_protos = get_transports ();
1301 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1302 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1303 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1306 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1308 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1310 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1312 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1313 if (account_pair != NULL)
1314 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1316 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1317 window_rules_group = modest_dimming_rules_group_new ("ModestWindowDimmingRules", TRUE);
1318 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1319 /* Add common dimming rules */
1320 modest_dimming_rules_group_add_rules (window_rules_group,
1321 modest_msg_edit_window_toolbar_dimming_entries,
1322 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1323 MODEST_WINDOW (obj));
1324 modest_dimming_rules_group_add_rules (window_rules_group,
1325 modest_msg_edit_window_menu_dimming_entries,
1326 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1327 MODEST_WINDOW (obj));
1328 modest_dimming_rules_group_add_widget_rule (window_rules_group, priv->font_color_button,
1329 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1330 MODEST_WINDOW (obj));
1331 modest_dimming_rules_group_add_widget_rule (window_rules_group, priv->font_size_toolitem,
1332 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1333 MODEST_WINDOW (obj));
1334 modest_dimming_rules_group_add_widget_rule (window_rules_group, priv->font_face_toolitem,
1335 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1336 MODEST_WINDOW (obj));
1337 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1338 modest_msg_edit_window_clipboard_dimming_entries,
1339 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1340 MODEST_WINDOW (obj));
1341 /* Insert dimming rules group for this window */
1342 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, window_rules_group);
1343 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1344 /* Checks the dimming rules */
1345 g_object_unref (window_rules_group);
1346 g_object_unref (clipboard_rules_group);
1347 gtk_widget_show_all (GTK_WIDGET (obj));
1349 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1351 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1353 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (obj));
1354 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1355 priv->update_caption_visibility = TRUE;
1357 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1359 /* Track account-removed signal, this window should be closed
1360 in the case we're creating a mail associated to the account
1362 priv->account_removed_handler_id =
1363 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1365 G_CALLBACK(on_account_removed),
1368 return (ModestWindow*) obj;
1372 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1374 GString **string_buffer = (GString **) user_data;
1376 *string_buffer = g_string_append (*string_buffer, buffer);
1382 * @result: A new string which should be freed with g_free().
1385 get_formatted_data (ModestMsgEditWindow *edit_window)
1387 ModestMsgEditWindowPrivate *priv;
1388 GString *string_buffer = g_string_new ("");
1390 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1392 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1394 return g_string_free (string_buffer, FALSE);
1399 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1402 const gchar *account_name;
1403 ModestMsgEditWindowPrivate *priv;
1404 TnyIterator *att_iter;
1406 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1408 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1410 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1411 g_return_val_if_fail (account_name, NULL);
1414 /* don't free these (except from) */
1415 data = g_slice_new0 (MsgData);
1416 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1418 data->account_name = g_strdup (account_name);
1419 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1420 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1421 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1422 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1423 if (priv->draft_msg) {
1424 data->draft_msg = g_object_ref (priv->draft_msg);
1425 } else if (priv->outbox_msg) {
1426 data->draft_msg = g_object_ref (priv->outbox_msg);
1428 data->draft_msg = NULL;
1431 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1433 gtk_text_buffer_get_bounds (buf, &b, &e);
1434 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1436 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1437 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1439 data->html_body = NULL;
1441 /* deep-copy the data */
1442 att_iter = tny_list_create_iterator (priv->attachments);
1443 data->attachments = NULL;
1444 while (!tny_iterator_is_done (att_iter)) {
1445 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1446 if (!(TNY_IS_MIME_PART(part))) {
1447 g_warning ("strange data in attachment list");
1448 g_object_unref (part);
1449 tny_iterator_next (att_iter);
1452 data->attachments = g_list_append (data->attachments,
1454 tny_iterator_next (att_iter);
1456 g_object_unref (att_iter);
1458 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1459 att_iter = tny_list_create_iterator (priv->images);
1460 data->images = NULL;
1461 while (!tny_iterator_is_done (att_iter)) {
1462 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1464 if (!(TNY_IS_MIME_PART(part))) {
1465 g_warning ("strange data in attachment list");
1466 g_object_unref (part);
1467 tny_iterator_next (att_iter);
1470 cid = tny_mime_part_get_content_id (part);
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 (part));
1486 g_object_unref (part);
1487 tny_iterator_next (att_iter);
1490 data->priority_flags = priv->priority_flags;
1497 unref_gobject (GObject *obj, gpointer data)
1499 if (!G_IS_OBJECT(obj))
1501 g_object_unref (obj);
1505 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1508 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1516 g_free (data->from);
1517 g_free (data->subject);
1518 g_free (data->plain_body);
1519 g_free (data->html_body);
1520 g_free (data->account_name);
1522 if (data->draft_msg != NULL) {
1523 g_object_unref (data->draft_msg);
1524 data->draft_msg = NULL;
1527 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1528 g_list_free (data->attachments);
1529 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1530 g_list_free (data->images);
1532 g_slice_free (MsgData, data);
1536 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1539 ModestMsgEditWindowPrivate *priv = NULL;
1540 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1542 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1544 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1546 return MODEST_MSG_EDIT_FORMAT_HTML;
1548 return MODEST_MSG_EDIT_FORMAT_TEXT;
1552 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1553 ModestMsgEditFormat format)
1555 ModestMsgEditWindowPrivate *priv;
1557 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1558 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1561 case MODEST_MSG_EDIT_FORMAT_HTML:
1562 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1564 case MODEST_MSG_EDIT_FORMAT_TEXT:
1565 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1568 g_return_if_reached ();
1572 ModestMsgEditFormatState *
1573 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1575 ModestMsgEditFormatState *format_state = NULL;
1576 ModestMsgEditWindowPrivate *priv;
1577 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1579 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1580 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1582 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1584 format_state = g_new0 (ModestMsgEditFormatState, 1);
1585 format_state->bold = buffer_format->bold&0x1;
1586 format_state->italics = buffer_format->italic&0x1;
1587 format_state->bullet = buffer_format->bullet&0x1;
1588 format_state->color = buffer_format->color;
1589 format_state->font_size = buffer_format->font_size;
1590 format_state->font_family = wp_get_font_name (buffer_format->font);
1591 format_state->justification = buffer_format->justification;
1592 g_free (buffer_format);
1594 return format_state;
1599 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1600 const ModestMsgEditFormatState *format_state)
1602 ModestMsgEditWindowPrivate *priv;
1603 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1604 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1605 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1606 g_return_if_fail (format_state != NULL);
1608 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1609 gtk_widget_grab_focus (priv->msg_body);
1610 buffer_format->bold = (format_state->bold != FALSE);
1611 buffer_format->italic = (format_state->italics != FALSE);
1612 buffer_format->color = format_state->color;
1613 buffer_format->font_size = format_state->font_size;
1614 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1615 buffer_format->justification = format_state->justification;
1616 buffer_format->bullet = format_state->bullet;
1618 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1620 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1621 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1622 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1623 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1624 buffer_format->cs.font = (buffer_format->font != current_format->font);
1625 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1626 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1628 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1629 if (buffer_format->cs.bold) {
1630 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1631 GINT_TO_POINTER (buffer_format->bold&0x1));
1633 if (buffer_format->cs.italic) {
1634 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1635 GINT_TO_POINTER (buffer_format->italic&0x1));
1637 if (buffer_format->cs.color) {
1638 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1639 GINT_TO_POINTER (&(buffer_format->color)));
1641 if (buffer_format->cs.font_size) {
1642 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1643 GINT_TO_POINTER (buffer_format->font_size));
1645 if (buffer_format->cs.justification) {
1646 switch (buffer_format->justification) {
1647 case GTK_JUSTIFY_LEFT:
1648 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1649 GINT_TO_POINTER(TRUE));
1651 case GTK_JUSTIFY_CENTER:
1652 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1653 GINT_TO_POINTER(TRUE));
1655 case GTK_JUSTIFY_RIGHT:
1656 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1657 GINT_TO_POINTER(TRUE));
1664 if (buffer_format->cs.font) {
1665 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1666 GINT_TO_POINTER (buffer_format->font));
1668 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1669 if (buffer_format->cs.bullet) {
1670 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1671 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1673 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1675 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1677 g_free (current_format);
1682 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1684 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1686 ModestWindowPrivate *parent_priv;
1687 ModestMsgEditWindowPrivate *priv;
1688 GtkWidget *new_size_menuitem;
1689 GtkWidget *new_font_menuitem;
1691 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1692 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1694 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1695 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1696 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1697 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1699 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1700 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1701 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1704 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1706 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1707 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1709 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1710 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1712 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1713 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1716 switch (buffer_format->justification)
1718 case GTK_JUSTIFY_LEFT:
1719 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentLeftMenu");
1721 case GTK_JUSTIFY_CENTER:
1722 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentCenterMenu");
1724 case GTK_JUSTIFY_RIGHT:
1725 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentRightMenu");
1732 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1734 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1735 G_CALLBACK (modest_msg_edit_window_color_button_change),
1737 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1738 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1739 G_CALLBACK (modest_msg_edit_window_color_button_change),
1742 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1743 buffer_format->font_size))->data);
1744 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1748 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1749 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1750 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1752 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1753 G_CALLBACK (modest_msg_edit_window_size_change),
1755 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1756 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1757 G_CALLBACK (modest_msg_edit_window_size_change),
1761 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1762 buffer_format->font))->data);
1763 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1767 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1768 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1769 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1771 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1772 G_CALLBACK (modest_msg_edit_window_font_change),
1774 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1775 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1776 G_CALLBACK (modest_msg_edit_window_font_change),
1780 g_free (buffer_format);
1784 #ifdef MODEST_HILDON_VERSION_0
1786 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1789 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1790 ModestMsgEditWindowPrivate *priv;
1791 GtkWidget *dialog = NULL;
1793 GdkColor *new_color = NULL;
1795 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1796 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1798 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1799 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1800 g_free (buffer_format);
1802 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1803 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1804 if (new_color != NULL) {
1805 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1806 (gpointer) new_color);
1809 gtk_widget_destroy (dialog);
1814 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1817 ModestMsgEditWindowPrivate *priv;
1818 GtkWidget *dialog = NULL;
1820 GdkColor *old_color = NULL;
1821 const GdkColor *new_color = NULL;
1823 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1824 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1826 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1827 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1829 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1830 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1831 if (new_color != NULL)
1832 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1834 gtk_widget_destroy (dialog);
1840 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1843 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1844 ModestMsgEditWindowPrivate *priv;
1845 GtkWidget *dialog = NULL;
1847 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1848 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1850 dialog = hildon_color_chooser_new ();
1851 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1852 g_free (buffer_format);
1854 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1856 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1857 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1860 gtk_widget_destroy (dialog);
1865 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1868 ModestMsgEditWindowPrivate *priv;
1869 GtkWidget *dialog = NULL;
1870 GdkColor *old_color = NULL;
1872 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1873 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1875 dialog = hildon_color_chooser_new ();
1876 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1878 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1880 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1881 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1883 gtk_widget_destroy (dialog);
1886 #endif /*!MODEST_HILDON_VERSION_0*/
1890 static TnyStream* create_stream_for_uri (const gchar* uri)
1895 TnyStream *result = NULL;
1897 GnomeVFSHandle *handle = NULL;
1898 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1899 if (test == GNOME_VFS_OK) {
1900 /* Create the tinymail stream: */
1901 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1902 result = TNY_STREAM (tny_vfs_stream_new (handle));
1909 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1912 ModestMsgEditWindowPrivate *priv;
1913 GtkWidget *dialog = NULL;
1915 GSList *uris = NULL;
1916 GSList *uri_node = NULL;
1918 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1920 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1921 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1922 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1924 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1926 response = gtk_dialog_run (GTK_DIALOG (dialog));
1928 case GTK_RESPONSE_OK:
1929 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1934 gtk_widget_destroy (dialog);
1936 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1938 GnomeVFSHandle *handle = NULL;
1939 GnomeVFSResult result;
1940 GtkTextIter position;
1941 GtkTextMark *insert_mark;
1943 uri = (const gchar *) uri_node->data;
1944 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1945 if (result == GNOME_VFS_OK) {
1947 GnomeVFSFileInfo info;
1948 gchar *filename, *basename, *escaped_filename;
1949 TnyMimePart *mime_part;
1951 const gchar *mime_type = NULL;
1952 GnomeVFSURI *vfs_uri;
1954 vfs_uri = gnome_vfs_uri_new (uri);
1956 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1957 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1958 g_free (escaped_filename);
1959 gnome_vfs_uri_unref (vfs_uri);
1961 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1962 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1964 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1966 mime_part = tny_platform_factory_new_mime_part
1967 (modest_runtime_get_platform_factory ());
1969 TnyStream *stream = create_stream_for_uri (uri);
1970 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1972 content_id = g_strdup_printf ("%d", priv->last_cid);
1973 tny_mime_part_set_content_id (mime_part, content_id);
1974 g_free (content_id);
1977 basename = g_path_get_basename (filename);
1978 tny_mime_part_set_filename (mime_part, basename);
1981 pixbuf = pixbuf_from_stream (stream, mime_type);
1983 if (pixbuf != NULL) {
1984 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1985 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1986 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1989 tny_list_prepend (priv->images, (GObject *) mime_part);
1990 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1992 g_object_unref (mime_part);
2001 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2003 GtkWidget *dialog = NULL;
2005 GSList *uris = NULL;
2008 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2009 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2010 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2012 response = gtk_dialog_run (GTK_DIALOG (dialog));
2014 case GTK_RESPONSE_OK:
2015 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2020 gtk_widget_destroy (dialog);
2022 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2023 const gchar *uri = (const gchar *) uri_node->data;
2024 modest_msg_edit_window_attach_file_one (window, uri);
2026 g_slist_foreach (uris, (GFunc) g_free, NULL);
2027 g_slist_free (uris);
2031 modest_msg_edit_window_attach_file_one (
2032 ModestMsgEditWindow *window,
2035 g_return_if_fail (window);
2036 g_return_if_fail (uri);
2038 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2041 GnomeVFSHandle *handle = NULL;
2042 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2043 if (result == GNOME_VFS_OK) {
2044 TnyMimePart *mime_part;
2046 const gchar *mime_type = NULL;
2048 gchar *escaped_filename;
2051 GnomeVFSFileInfo info;
2052 GnomeVFSURI *vfs_uri;
2054 vfs_uri = gnome_vfs_uri_new (uri);
2057 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2058 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2059 g_free (escaped_filename);
2060 gnome_vfs_uri_unref (vfs_uri);
2062 if (gnome_vfs_get_file_info (uri,
2064 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2066 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2067 mime_part = tny_platform_factory_new_mime_part
2068 (modest_runtime_get_platform_factory ());
2069 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2071 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2073 g_object_unref (stream);
2075 content_id = g_strdup_printf ("%d", priv->last_cid);
2076 tny_mime_part_set_content_id (mime_part, content_id);
2077 g_free (content_id);
2080 basename = g_path_get_basename (filename);
2081 tny_mime_part_set_filename (mime_part, basename);
2084 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2085 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2087 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2088 gtk_widget_show_all (priv->attachments_caption);
2089 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2091 g_object_unref (mime_part);
2096 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2099 ModestMsgEditWindowPrivate *priv;
2102 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2103 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2105 if (att_list == NULL) {
2106 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2108 g_object_ref (att_list);
2111 if (tny_list_get_length (att_list) == 0) {
2112 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2114 GtkWidget *confirmation_dialog = NULL;
2115 gboolean dialog_response;
2116 gchar *message = NULL;
2117 gchar *filename = NULL;
2119 if (tny_list_get_length (att_list) == 1) {
2121 iter = tny_list_create_iterator (att_list);
2122 part = (TnyMimePart *) tny_iterator_get_current (iter);
2123 g_object_unref (iter);
2124 if (TNY_IS_MSG (part)) {
2125 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2127 filename = g_strdup (tny_header_get_subject (header));
2128 g_object_unref (header);
2130 if (filename == NULL) {
2131 filename = g_strdup (_("mail_va_no_subject"));
2134 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2136 g_object_unref (part);
2138 filename = g_strdup ("");
2140 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2141 (tny_list_get_length (att_list) == 1)), filename);
2143 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2145 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2146 gtk_widget_destroy (confirmation_dialog);
2147 if (!dialog_response) {
2148 g_object_unref (att_list);
2151 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2153 for (iter = tny_list_create_iterator (att_list);
2154 !tny_iterator_is_done (iter);
2155 tny_iterator_next (iter)) {
2156 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2157 const gchar *att_id;
2158 tny_list_remove (priv->attachments, (GObject *) mime_part);
2160 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2162 if (tny_list_get_length (priv->attachments) == 0)
2163 gtk_widget_hide (priv->attachments_caption);
2164 att_id = tny_mime_part_get_content_id (mime_part);
2166 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2168 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2169 g_object_unref (mime_part);
2173 g_object_unref (att_list);
2175 /* if the last attachment has been removed, focus the Subject: field */
2176 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2177 gtk_widget_grab_focus (priv->subject_field);
2181 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2184 ModestMsgEditWindowPrivate *priv;
2185 GdkColor *new_color;
2186 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2188 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2189 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2192 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2194 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2196 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2198 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2203 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2206 ModestMsgEditWindowPrivate *priv;
2207 gint new_size_index;
2208 ModestMsgEditWindow *window;
2211 window = MODEST_MSG_EDIT_WINDOW (userdata);
2212 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2213 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2215 if (gtk_check_menu_item_get_active (menu_item)) {
2217 WPTextBufferFormat format;
2219 memset (&format, 0, sizeof (format));
2220 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2222 label = gtk_bin_get_child (GTK_BIN (menu_item));
2224 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2225 format.cs.font_size = TRUE;
2226 format.cs.text_position = TRUE;
2227 format.cs.font = TRUE;
2228 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2229 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2231 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2232 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2233 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2235 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2236 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2237 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2243 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2246 ModestMsgEditWindowPrivate *priv;
2247 gint new_font_index;
2248 ModestMsgEditWindow *window;
2251 window = MODEST_MSG_EDIT_WINDOW (userdata);
2252 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2253 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2255 if (gtk_check_menu_item_get_active (menu_item)) {
2258 label = gtk_bin_get_child (GTK_BIN (menu_item));
2260 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2262 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2263 GINT_TO_POINTER(new_font_index)))
2264 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2266 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2267 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2268 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2274 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2276 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2277 ModestWindowPrivate *parent_priv;
2278 ModestWindowMgr *mgr;
2279 gboolean is_fullscreen;
2280 GtkAction *fs_toggle_action;
2283 mgr = modest_runtime_get_window_mgr ();
2284 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2286 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2288 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2289 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2290 if (is_fullscreen != active)
2291 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2299 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2302 ModestMsgEditWindowPrivate *priv = NULL;
2303 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2305 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2306 if (!priv->update_caption_visibility)
2309 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2311 gtk_widget_show (priv->cc_caption);
2313 gtk_widget_hide (priv->cc_caption);
2315 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2319 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2322 ModestMsgEditWindowPrivate *priv = NULL;
2323 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2325 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2326 if (!priv->update_caption_visibility)
2329 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2331 gtk_widget_show (priv->bcc_caption);
2333 gtk_widget_hide (priv->bcc_caption);
2335 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2339 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2340 ModestRecptEditor *editor)
2342 ModestMsgEditWindowPrivate *priv;
2344 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2345 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2346 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2348 if (editor == NULL) {
2349 GtkWidget *view_focus;
2350 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2352 /* This code should be kept in sync with ModestRecptEditor. The
2353 textview inside the recpt editor is the one that really gets the
2354 focus. As it's inside a scrolled window, and this one inside the
2355 hbox recpt editor inherits from, we'll need to go up in the
2356 hierarchy to know if the text view is part of the recpt editor
2357 or if it's a different text entry */
2359 if (gtk_widget_get_parent (view_focus)) {
2360 GtkWidget *first_parent;
2362 first_parent = gtk_widget_get_parent (view_focus);
2363 if (gtk_widget_get_parent (first_parent) &&
2364 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2365 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2370 editor = MODEST_RECPT_EDITOR (priv->to_field);
2374 modest_address_book_select_addresses (editor);
2379 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2381 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2383 modest_msg_edit_window_open_addressbook (window, NULL);
2387 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2388 gboolean show_toolbar)
2390 ModestWindowPrivate *parent_priv;
2391 const gchar *action_name;
2394 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2395 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2397 /* We can not just use the code of
2398 modest_msg_edit_window_setup_toolbar because it has a
2399 mixture of both initialization and creation code. */
2401 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2403 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2405 /* Update also the actions (to update the toggles in the
2406 menus), we have to do it manually because some other window
2407 of the same time could have changed it (remember that the
2408 toolbar fullscreen mode is shared by all the windows of the
2410 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2411 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2413 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2415 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2416 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2422 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2423 TnyHeaderFlags priority_flags)
2425 ModestMsgEditWindowPrivate *priv;
2426 ModestWindowPrivate *parent_priv;
2428 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2430 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2431 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2433 if (priv->priority_flags != priority_flags) {
2434 GtkAction *priority_action = NULL;
2436 priv->priority_flags = priority_flags;
2438 switch (priority_flags) {
2439 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2440 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2441 gtk_widget_show (priv->priority_icon);
2442 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2443 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2445 case TNY_HEADER_FLAG_LOW_PRIORITY:
2446 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2447 gtk_widget_show (priv->priority_icon);
2448 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2449 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2452 gtk_widget_hide (priv->priority_icon);
2453 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2454 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2457 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2458 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2463 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2466 ModestMsgEditWindowPrivate *priv;
2467 ModestWindowPrivate *parent_priv;
2468 gint current_format;
2470 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2472 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2473 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2475 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2476 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2478 if (current_format != file_format) {
2479 switch (file_format) {
2480 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2481 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2482 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2484 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2488 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2489 response = gtk_dialog_run (GTK_DIALOG (dialog));
2490 gtk_widget_destroy (dialog);
2491 if (response == GTK_RESPONSE_OK) {
2492 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2494 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2495 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2500 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2505 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2508 ModestMsgEditWindowPrivate *priv;
2509 WPTextBufferFormat oldfmt, fmt;
2510 gint old_position = 0;
2514 GdkColor *color = NULL;
2515 gboolean bold, bold_set, italic, italic_set;
2516 gboolean underline, underline_set;
2517 gboolean strikethrough, strikethrough_set;
2518 gboolean position_set;
2519 gboolean font_size_set, font_set, color_set;
2522 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2523 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2525 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2527 /* First we get the currently selected font information */
2528 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2530 switch (oldfmt.text_position) {
2531 case TEXT_POSITION_NORMAL:
2534 case TEXT_POSITION_SUPERSCRIPT:
2542 g_object_set (G_OBJECT (dialog),
2543 "bold", oldfmt.bold != FALSE,
2544 "bold-set", !oldfmt.cs.bold,
2545 "underline", oldfmt.underline != FALSE,
2546 "underline-set", !oldfmt.cs.underline,
2547 "italic", oldfmt.italic != FALSE,
2548 "italic-set", !oldfmt.cs.italic,
2549 "strikethrough", oldfmt.strikethrough != FALSE,
2550 "strikethrough-set", !oldfmt.cs.strikethrough,
2551 "color", &oldfmt.color,
2552 "color-set", !oldfmt.cs.color,
2553 "size", wp_font_size[oldfmt.font_size],
2554 "size-set", !oldfmt.cs.font_size,
2555 "position", old_position,
2556 "position-set", !oldfmt.cs.text_position,
2557 "family", wp_get_font_name (oldfmt.font),
2558 "family-set", !oldfmt.cs.font,
2561 gtk_widget_show_all (dialog);
2562 response = gtk_dialog_run (GTK_DIALOG (dialog));
2563 if (response == GTK_RESPONSE_OK) {
2565 g_object_get( dialog,
2567 "bold-set", &bold_set,
2568 "underline", &underline,
2569 "underline-set", &underline_set,
2571 "italic-set", &italic_set,
2572 "strikethrough", &strikethrough,
2573 "strikethrough-set", &strikethrough_set,
2575 "color-set", &color_set,
2577 "size-set", &font_size_set,
2578 "family", &font_name,
2579 "family-set", &font_set,
2580 "position", &position,
2581 "position-set", &position_set,
2586 if (response == GTK_RESPONSE_OK) {
2587 memset(&fmt, 0, sizeof(fmt));
2593 fmt.italic = italic;
2594 fmt.cs.italic = TRUE;
2596 if (underline_set) {
2597 fmt.underline = underline;
2598 fmt.cs.underline = TRUE;
2600 if (strikethrough_set) {
2601 fmt.strikethrough = strikethrough;
2602 fmt.cs.strikethrough = TRUE;
2607 ? TEXT_POSITION_NORMAL
2608 : ( ( position == 1 )
2609 ? TEXT_POSITION_SUPERSCRIPT
2610 : TEXT_POSITION_SUBSCRIPT );
2611 fmt.cs.text_position = TRUE;
2612 fmt.font_size = oldfmt.font_size;
2616 fmt.cs.color = TRUE;
2619 fmt.font = wp_get_font_index(font_name,
2624 if (font_size_set) {
2625 fmt.cs.font_size = TRUE;
2626 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2628 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2629 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2631 gtk_widget_destroy (dialog);
2633 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2637 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2639 ModestMsgEditWindowPrivate *priv;
2641 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2642 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2644 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2646 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2651 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2653 ModestMsgEditWindowPrivate *priv;
2655 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2656 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2658 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2660 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2665 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2667 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2669 priv->can_undo = can_undo;
2673 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2675 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2677 priv->can_redo = can_redo;
2681 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2683 ModestMsgEditWindowPrivate *priv;
2684 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2685 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2687 return priv->can_undo;
2691 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2693 ModestMsgEditWindowPrivate *priv;
2694 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2695 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2697 return priv->can_redo;
2702 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2705 GtkTextIter match_start, match_end;
2707 if (image_id == NULL)
2710 gtk_text_buffer_get_start_iter (buffer, &iter);
2712 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2713 GSList *tags = gtk_text_iter_get_tags (&match_start);
2715 for (node = tags; node != NULL; node = g_slist_next (node)) {
2716 GtkTextTag *tag = (GtkTextTag *) node->data;
2717 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2718 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2719 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2721 offset = gtk_text_iter_get_offset (&match_start);
2722 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2723 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2727 gtk_text_iter_forward_char (&iter);
2732 message_is_empty (ModestMsgEditWindow *window)
2734 ModestMsgEditWindowPrivate *priv = NULL;
2736 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2737 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2739 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2740 * so we can ignore markup.
2742 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2745 count = gtk_text_buffer_get_char_count (buf);
2751 msg_body_focus (GtkWidget *focus,
2752 GdkEventFocus *event,
2756 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (userdata));
2761 recpt_field_changed (GtkTextBuffer *buffer,
2762 ModestMsgEditWindow *editor)
2764 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (editor));
2768 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2770 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (editor));
2774 attachments_selection_changed (ModestAttachmentsView *atts_view, ModestMsgEditWindow *window)
2776 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2780 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2782 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2783 GtkTextBuffer *buffer;
2785 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2786 gtk_text_buffer_set_modified (buffer, FALSE);
2787 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2788 gtk_text_buffer_set_modified (buffer, FALSE);
2789 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2790 gtk_text_buffer_set_modified (buffer, FALSE);
2791 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2795 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2797 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2798 GtkTextBuffer *buffer;
2800 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2801 if (gtk_text_buffer_get_modified (buffer))
2803 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2804 if (gtk_text_buffer_get_modified (buffer))
2806 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2807 if (gtk_text_buffer_get_modified (buffer))
2809 if (gtk_text_buffer_get_modified (priv->text_buffer))
2819 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2821 ModestMsgEditWindowPrivate *priv = NULL;
2823 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2824 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2826 /* check if there's no recipient added */
2827 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2828 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2829 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2830 /* no recipient contents, then select contacts */
2831 modest_msg_edit_window_open_addressbook (window, NULL);
2835 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2836 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2839 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2840 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2843 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2844 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2848 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2849 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2850 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2857 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2858 ModestMsgEditWindow *window)
2860 modest_msg_edit_window_offer_attach_file (window);
2864 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2866 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2868 return priv->clipboard_text;
2872 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2874 ModestMsgEditWindow *window)
2876 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2877 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2879 if (!GTK_WIDGET_VISIBLE (window))
2882 text = gtk_clipboard_wait_for_text (selection_clipboard);
2884 if (priv->clipboard_text != NULL) {
2885 g_free (priv->clipboard_text);
2887 priv->clipboard_text = text;
2889 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2892 subject_field_move_cursor (GtkEntry *entry,
2893 GtkMovementStep step,
2898 if (!GTK_WIDGET_VISIBLE (window))
2901 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2905 update_window_title (ModestMsgEditWindow *window)
2907 ModestMsgEditWindowPrivate *priv = NULL;
2908 const gchar *subject;
2910 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2911 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2912 if (subject == NULL || subject[0] == '\0')
2913 subject = _("mail_va_new_email");
2915 gtk_window_set_title (GTK_WINDOW (window), subject);
2920 subject_field_changed (GtkEditable *editable,
2921 ModestMsgEditWindow *window)
2923 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2924 update_window_title (window);
2925 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2926 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2930 subject_field_insert_text (GtkEditable *editable,
2932 gint new_text_length,
2934 ModestMsgEditWindow *window)
2936 GString *result = g_string_new ("");
2938 gint result_len = 0;
2939 const gchar *entry_text = NULL;
2942 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2943 old_length = g_utf8_strlen (entry_text, -1);
2945 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2946 gunichar c = g_utf8_get_char_validated (current, 8);
2947 /* Invalid unichar, stop */
2953 result = g_string_append_unichar (result, c);
2957 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2958 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2961 /* Prevent endless recursion */
2962 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2963 g_signal_emit_by_name (editable, "insert-text",
2964 (gpointer) result->str, (gpointer) result->len,
2965 (gpointer) position, (gpointer) window);
2966 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2970 if (result_len + old_length > 1000) {
2971 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2972 dgettext("hildon-common-strings",
2973 "ckdg_ib_maximum_characters_reached"));
2976 g_string_free (result, TRUE);
2980 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2983 ModestMsgEditWindowPrivate *priv = NULL;
2985 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2986 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2988 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2991 gtk_widget_show_all (priv->find_toolbar);
2992 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2994 gtk_widget_hide_all (priv->find_toolbar);
2995 gtk_widget_grab_focus (priv->msg_body);
3001 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3003 GtkTextIter *match_start,
3004 GtkTextIter *match_end)
3006 GtkTextIter end_iter;
3007 gchar *str_casefold;
3010 gchar *range_casefold;
3013 gboolean result = FALSE;
3020 gtk_text_iter_forward_to_end (&end_iter);
3022 str_casefold = g_utf8_casefold (str, -1);
3023 str_chars_n = strlen (str);
3025 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3026 range_casefold = g_utf8_casefold (range_text, -1);
3027 range_chars_n = strlen (range_casefold);
3029 if (range_chars_n < str_chars_n) {
3030 g_free (str_casefold);
3031 g_free (range_text);
3032 g_free (range_casefold);
3036 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3037 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3038 if (!g_utf8_collate (range_subtext, str_casefold)) {
3039 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3041 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3042 match_start, match_end, NULL);
3043 g_free (found_text);
3045 g_free (range_subtext);
3049 g_free (str_casefold);
3050 g_free (range_text);
3051 g_free (range_casefold);
3058 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3059 ModestMsgEditWindow *window)
3061 gchar *current_search = NULL;
3062 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3064 GtkTextIter selection_start, selection_end;
3065 GtkTextIter match_start, match_end;
3066 gboolean continue_search = FALSE;
3068 if (message_is_empty (window)) {
3069 g_free (priv->last_search);
3070 priv->last_search = NULL;
3071 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3075 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3076 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3077 g_free (current_search);
3078 g_free (priv->last_search);
3079 priv->last_search = NULL;
3080 /* Information banner about empty search */
3081 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3085 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3086 continue_search = TRUE;
3088 g_free (priv->last_search);
3089 priv->last_search = g_strdup (current_search);
3092 if (continue_search) {
3093 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3094 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3095 &match_start, &match_end);
3097 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3099 GtkTextIter buffer_start;
3100 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3101 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3102 &match_start, &match_end);
3104 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3107 /* Mark as selected the string found in search */
3109 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3110 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3112 g_free (priv->last_search);
3113 priv->last_search = NULL;
3115 g_free (current_search);
3119 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3120 ModestMsgEditWindow *window)
3122 GtkToggleAction *toggle;
3123 ModestWindowPrivate *parent_priv;
3124 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3126 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3127 gtk_toggle_action_set_active (toggle, FALSE);
3131 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3133 ModestMsgEditWindowPrivate *priv;
3135 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3140 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3143 ModestMsgEditWindowPrivate *priv;
3145 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3151 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3154 ModestMsgEditWindowPrivate *priv;
3155 TnyHeader *header = NULL;
3157 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3158 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3160 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3161 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3163 if (priv->draft_msg != NULL) {
3164 g_object_unref (priv->draft_msg);
3167 if (draft != NULL) {
3168 g_object_ref (draft);
3169 header = tny_msg_get_header (draft);
3170 if (priv->msg_uid) {
3171 g_free (priv->msg_uid);
3172 priv->msg_uid = NULL;
3174 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3175 if (GTK_WIDGET_REALIZED (window))
3176 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3179 priv->draft_msg = draft;
3183 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3184 GtkTextIter *start, GtkTextIter *end,
3187 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3188 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3191 if (tag == NULL+13) return;
3192 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3193 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3194 replace_with_images (window, priv->images);
3199 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3202 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3204 g_return_if_fail (TNY_IS_MIME_PART (part));
3205 tny_list_prepend (priv->attachments, (GObject *) part);
3206 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3207 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3208 gtk_widget_show_all (priv->attachments_caption);
3209 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3213 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3215 ModestMsgEditWindowPrivate *priv;
3217 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3218 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3220 return priv->msg_uid;
3224 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3225 ModestMsgEditWindowWidgetType widget_type)
3227 ModestMsgEditWindowPrivate *priv;
3229 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3232 switch (widget_type) {
3233 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3234 return priv->msg_body;
3236 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3237 return priv->to_field;
3239 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3240 return priv->cc_field;
3242 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3243 return priv->bcc_field;
3245 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3246 return priv->subject_field;
3248 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3249 return priv->attachments_view;
3257 remove_tags (WPTextBuffer *buffer)
3259 GtkTextIter start, end;
3261 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3262 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3264 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3268 on_account_removed (TnyAccountStore *account_store,
3269 TnyAccount *account,
3272 /* Do nothing if it's a store account, because we use the
3273 transport to send the messages */
3274 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3275 const gchar *parent_acc = NULL;
3276 const gchar *our_acc = NULL;
3278 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3279 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3280 /* Close this window if I'm showing a message of the removed account */
3281 if (strcmp (parent_acc, our_acc) == 0)
3282 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3287 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3289 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3291 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3297 set_zoom_do_nothing (ModestWindow *window,
3303 get_zoom_do_nothing (ModestWindow *window)