1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include <modest-utils.h>
79 #include "modest-maemo-utils.h"
82 #define DEFAULT_FONT_SIZE 3
83 #define DEFAULT_FONT 2
84 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
85 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
86 #define DEFAULT_MAIN_VBOX_SPACING 6
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #define DEFAULT_FONT_SCALE 1.5
91 static gboolean is_wp_text_buffer_started = FALSE;
93 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
94 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
95 static void modest_msg_edit_window_finalize (GObject *obj);
97 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
98 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
99 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
101 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
102 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
103 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
104 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
105 GtkTextIter *start, GtkTextIter *end,
107 static void text_buffer_insert_text (GtkTextBuffer *buffer,
108 GtkTextIter *location,
111 ModestMsgEditWindow *window);
112 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
113 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
114 static void subject_field_insert_text (GtkEditable *editable,
116 gint new_text_length,
118 ModestMsgEditWindow *window);
119 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
121 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
123 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
125 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
126 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
127 GdkEventWindowState *event,
129 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
130 ModestRecptEditor *editor);
131 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
132 ModestMsgEditWindow *window);
134 /* ModestWindow methods implementation */
135 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
136 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
137 gboolean show_toolbar);
138 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
140 ModestMsgEditWindow *window);
141 static void subject_field_move_cursor (GtkEntry *entry,
142 GtkMovementStep step,
146 static void update_window_title (ModestMsgEditWindow *window);
149 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
150 ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
152 ModestMsgEditWindow *window);
153 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
155 GtkTextIter *match_start,
156 GtkTextIter *match_end);
158 static void remove_tags (WPTextBuffer *buffer);
160 static void on_account_removed (TnyAccountStore *account_store,
164 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
166 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
168 static gdouble get_zoom_do_nothing (ModestWindow *window);
170 static void init_window (ModestMsgEditWindow *obj);
172 static void DEBUG_BUFFER (WPTextBuffer *buffer)
176 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
178 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
179 while (!gtk_text_iter_is_end (&iter)) {
180 GString *output = g_string_new ("");
181 GSList *toggled_tags;
184 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
185 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
186 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
187 GtkTextTag *tag = (GtkTextTag *) node->data;
189 g_object_get (G_OBJECT (tag), "name", &name, NULL);
190 output = g_string_append (output, name);
191 g_string_append (output, " ");
193 output = g_string_append (output, "] OPENED [ ");
194 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
195 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
196 GtkTextTag *tag = (GtkTextTag *) node->data;
198 g_object_get (G_OBJECT (tag), "name", &name, NULL);
199 output = g_string_append (output, name);
200 g_string_append (output, " ");
202 output = g_string_append (output, "]\n");
203 g_message ("%s", output->str);
204 g_string_free (output, TRUE);
205 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
207 g_message ("END BUFFER");
212 /* static gboolean */
213 /* on_key_pressed (GtkWidget *self, */
214 /* GdkEventKey *event, */
215 /* gpointer user_data); */
217 /* list my signals */
224 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
225 struct _ModestMsgEditWindowPrivate {
227 GtkWidget *header_box;
229 ModestPairList *from_field_protos;
230 GtkWidget *from_field;
234 GtkWidget *bcc_field;
235 GtkWidget *subject_field;
236 GtkWidget *attachments_view;
237 GtkWidget *priority_icon;
238 GtkWidget *add_attachment_button;
240 GtkWidget *cc_caption;
241 GtkWidget *bcc_caption;
242 gboolean update_caption_visibility;
243 GtkWidget *attachments_caption;
245 GtkTextBuffer *text_buffer;
247 GtkWidget *font_size_toolitem;
248 GtkWidget *font_face_toolitem;
249 GtkWidget *font_color_button;
250 GSList *font_items_group;
251 GtkWidget *font_tool_button_label;
252 GSList *size_items_group;
253 GtkWidget *size_tool_button_label;
255 GtkWidget *find_toolbar;
259 GtkWidget *scroll_area;
260 gint last_vadj_upper;
263 TnyList *attachments;
266 TnyHeaderFlags priority_flags;
268 gboolean can_undo, can_redo;
269 gulong clipboard_change_handler_id;
270 gulong default_clipboard_change_handler_id;
271 gulong account_removed_handler_id;
272 gchar *clipboard_text;
281 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
282 MODEST_TYPE_MSG_EDIT_WINDOW, \
283 ModestMsgEditWindowPrivate))
285 static GtkWindowClass *parent_class = NULL;
287 /* uncomment the following if you have defined any signals */
288 /* static guint signals[LAST_SIGNAL] = {0}; */
291 modest_msg_edit_window_get_type (void)
293 static GType my_type = 0;
295 static const GTypeInfo my_info = {
296 sizeof(ModestMsgEditWindowClass),
297 NULL, /* base init */
298 NULL, /* base finalize */
299 (GClassInitFunc) modest_msg_edit_window_class_init,
300 NULL, /* class finalize */
301 NULL, /* class data */
302 sizeof(ModestMsgEditWindow),
304 (GInstanceInitFunc) modest_msg_edit_window_init,
307 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
308 "ModestMsgEditWindow",
316 save_state (ModestWindow *self)
318 modest_widget_memory_save (modest_runtime_get_conf(),
319 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
324 restore_settings (ModestMsgEditWindow *self)
326 ModestConf *conf = NULL;
328 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
330 conf = modest_runtime_get_conf ();
331 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
332 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
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, NULL));
335 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
336 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
337 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
338 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
340 /* set initial state of cc and bcc */
341 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
342 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
343 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
344 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
345 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
346 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
348 /* Dim at start clipboard actions */
349 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
350 gtk_action_set_sensitive (action, FALSE);
351 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
352 gtk_action_set_sensitive (action, FALSE);
353 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
354 gtk_action_set_sensitive (action, FALSE);
356 modest_widget_memory_restore (conf,
357 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
362 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
364 GObjectClass *gobject_class;
365 ModestWindowClass *modest_window_class;
366 gobject_class = (GObjectClass*) klass;
367 modest_window_class = (ModestWindowClass*) klass;
369 parent_class = g_type_class_peek_parent (klass);
370 gobject_class->finalize = modest_msg_edit_window_finalize;
372 modest_window_class->set_zoom_func = set_zoom_do_nothing;
373 modest_window_class->get_zoom_func = get_zoom_do_nothing;
374 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
375 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
376 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
377 modest_window_class->save_state_func = save_state;
378 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
380 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
384 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
386 ModestMsgEditWindowPrivate *priv;
387 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
389 priv->msg_body = NULL;
390 priv->from_field = NULL;
391 priv->to_field = NULL;
392 priv->cc_field = NULL;
393 priv->bcc_field = NULL;
394 priv->subject_field = NULL;
395 priv->attachments = TNY_LIST (tny_simple_list_new ());
396 priv->images = TNY_LIST (tny_simple_list_new ());
399 priv->cc_caption = NULL;
400 priv->bcc_caption = NULL;
401 priv->update_caption_visibility = FALSE;
403 priv->priority_flags = 0;
405 priv->find_toolbar = NULL;
406 priv->last_search = NULL;
408 priv->draft_msg = NULL;
409 priv->outbox_msg = NULL;
410 priv->msg_uid = NULL;
412 priv->can_undo = FALSE;
413 priv->can_redo = FALSE;
414 priv->clipboard_change_handler_id = 0;
415 priv->default_clipboard_change_handler_id = 0;
416 priv->account_removed_handler_id = 0;
417 priv->clipboard_text = NULL;
420 priv->last_vadj_upper = 0;
422 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
423 GTK_WINDOW(obj),"applications_email_editor");
425 if (!is_wp_text_buffer_started) {
426 is_wp_text_buffer_started = TRUE;
427 wp_text_buffer_library_init ();
432 hildon_program_add_window (hildon_program_get_instance(),
437 /* FIXME: this is a dup from the one in gtk/ */
440 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
442 static ModestPairList*
443 get_transports (void)
445 GSList *transports = NULL;
447 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
448 GSList *accounts = modest_account_mgr_account_names (account_mgr,
449 TRUE /* only enabled accounts. */);
451 GSList *cursor = accounts;
453 gchar *account_name = cursor->data;
454 gchar *from_string = NULL;
456 from_string = modest_account_mgr_get_from_string (account_mgr,
460 if (from_string && account_name) {
461 gchar *name = account_name;
462 ModestPair *pair = modest_pair_new ((gpointer) name,
463 (gpointer) from_string , TRUE);
464 transports = g_slist_prepend (transports, pair);
467 cursor = cursor->next;
469 g_slist_free (accounts); /* only free the accounts, not the elements,
470 * because they are used in the pairlist */
474 void vadj_changed (GtkAdjustment *adj,
475 ModestMsgEditWindow *window)
477 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
479 GdkRectangle rectangle, cursor_rectangle;
480 GtkTextIter position;
484 /* We detect if cursor is visible using the full height, not only the center. This
486 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
487 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
489 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
490 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
492 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
493 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
495 if (gtk_widget_is_focus (priv->msg_body) &&
497 if (priv->last_vadj_upper != adj->upper) {
500 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
501 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
502 insert, 0.1, FALSE, 0.0, 0.0);
505 priv->last_vadj_upper = adj->upper;
508 static void window_focus (GtkWindow *window,
512 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
517 connect_signals (ModestMsgEditWindow *obj)
519 ModestMsgEditWindowPrivate *priv;
521 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
523 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
524 G_CALLBACK (text_buffer_refresh_attributes), obj);
525 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
526 G_CALLBACK (text_buffer_can_undo), obj);
527 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
528 G_CALLBACK (text_buffer_can_redo), obj);
529 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
530 G_CALLBACK (body_changed), obj);
531 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
532 G_CALLBACK (text_buffer_insert_text), obj);
533 g_signal_connect (G_OBJECT (obj), "window-state-event",
534 G_CALLBACK (modest_msg_edit_window_window_state_event),
536 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
537 G_CALLBACK (text_buffer_apply_tag), obj);
538 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
539 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
540 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
541 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
542 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
543 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
545 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
546 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
548 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
549 G_CALLBACK (msg_body_focus), obj);
550 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
551 G_CALLBACK (msg_body_focus), obj);
552 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
553 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
554 "changed", G_CALLBACK (recpt_field_changed), obj);
555 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
556 "changed", G_CALLBACK (recpt_field_changed), obj);
557 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
558 "changed", G_CALLBACK (recpt_field_changed), obj);
559 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
560 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
561 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
563 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
564 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
566 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
568 G_CALLBACK (vadj_changed),
571 priv->clipboard_change_handler_id =
572 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
573 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
574 priv->default_clipboard_change_handler_id =
575 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
576 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
581 init_window (ModestMsgEditWindow *obj)
583 GtkWidget *from_caption, *to_caption, *subject_caption;
584 GtkWidget *main_vbox;
585 ModestMsgEditWindowPrivate *priv;
586 GtkActionGroup *action_group;
587 ModestWindowPrivate *parent_priv;
588 GdkPixbuf *window_icon = NULL;
589 GError *error = NULL;
591 GtkSizeGroup *size_group;
593 GtkWidget *subject_box;
594 GtkWidget *attachment_icon;
595 GtkWidget *window_box;
596 #if (GTK_MINOR_VERSION >= 10)
597 GdkAtom deserialize_type;
599 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
600 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
602 parent_priv->ui_manager = gtk_ui_manager_new();
603 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
604 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
606 /* Add common actions */
607 gtk_action_group_add_actions (action_group,
608 modest_msg_edit_action_entries,
609 G_N_ELEMENTS (modest_msg_edit_action_entries),
611 gtk_action_group_add_toggle_actions (action_group,
612 modest_msg_edit_toggle_action_entries,
613 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
615 gtk_action_group_add_radio_actions (action_group,
616 modest_msg_edit_alignment_radio_action_entries,
617 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
619 G_CALLBACK (modest_ui_actions_on_change_justify),
621 gtk_action_group_add_radio_actions (action_group,
622 modest_msg_edit_priority_action_entries,
623 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
625 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
627 gtk_action_group_add_radio_actions (action_group,
628 modest_msg_edit_file_format_action_entries,
629 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
630 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
631 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
633 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
634 g_object_unref (action_group);
636 /* Load the UI definition */
637 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
640 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
641 g_clear_error (&error);
644 /* Add accelerators */
645 gtk_window_add_accel_group (GTK_WINDOW (obj),
646 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
648 parent_priv->menubar = NULL;
650 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
652 /* Note: This ModestPairList* must exist for as long as the combo
653 * that uses it, because the ModestComboBox uses the ID opaquely,
654 * so it can't know how to manage its memory. */
655 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
657 priv->to_field = modest_recpt_editor_new ();
658 priv->cc_field = modest_recpt_editor_new ();
659 priv->bcc_field = modest_recpt_editor_new ();
660 subject_box = gtk_hbox_new (FALSE, 0);
661 priv->priority_icon = gtk_image_new ();
662 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
663 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
664 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
665 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
666 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
667 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
668 priv->add_attachment_button = gtk_button_new ();
669 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
670 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
671 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
672 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
673 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
674 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
675 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
676 priv->attachments_view = modest_attachments_view_new (NULL);
678 priv->header_box = gtk_vbox_new (FALSE, 0);
680 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
681 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
682 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
683 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
684 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
685 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
686 g_object_unref (size_group);
688 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
689 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
690 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
691 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
692 gtk_size_group_add_widget (size_group, priv->subject_field);
693 gtk_size_group_add_widget (size_group, priv->attachments_view);
694 g_object_unref (size_group);
696 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
697 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
698 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
699 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
700 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
701 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
702 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
705 priv->msg_body = wp_text_view_new ();
706 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
707 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
708 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
709 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
710 #if (GTK_MINOR_VERSION >= 10)
711 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
712 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
714 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
715 deserialize_type, TRUE);
717 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
719 priv->find_toolbar = hildon_find_toolbar_new (NULL);
720 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
722 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
724 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
725 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
726 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
727 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
729 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
731 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
732 frame = gtk_frame_new (NULL);
733 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
735 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
736 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
737 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
739 G_CALLBACK (vadj_changed),
741 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
743 window_box = gtk_vbox_new (FALSE, 0);
744 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
745 gtk_container_add (GTK_CONTAINER(obj), window_box);
746 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
747 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
749 /* Set window icon */
750 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
752 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
753 g_object_unref (window_icon);
758 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
760 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
762 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
763 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
764 priv->clipboard_change_handler_id))
765 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
766 priv->clipboard_change_handler_id);
767 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
768 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
769 priv->default_clipboard_change_handler_id))
770 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
771 priv->default_clipboard_change_handler_id);
773 if (priv->account_removed_handler_id &&
774 g_signal_handler_is_connected (modest_runtime_get_account_store (),
775 priv->account_removed_handler_id))
776 g_signal_handler_disconnect(modest_runtime_get_account_store (),
777 priv->account_removed_handler_id);
781 modest_msg_edit_window_finalize (GObject *obj)
783 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
785 /* Sanity check: shouldn't be needed, the window mgr should
786 call this function before */
787 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
789 if (priv->clipboard_text != NULL) {
790 g_free (priv->clipboard_text);
791 priv->clipboard_text = NULL;
794 if (priv->draft_msg != NULL) {
795 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
796 if (TNY_IS_HEADER (header)) {
797 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
798 modest_window_mgr_unregister_header (mgr, header);
800 g_object_unref (priv->draft_msg);
801 priv->draft_msg = NULL;
803 if (priv->outbox_msg != NULL) {
804 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
805 if (TNY_IS_HEADER (header)) {
806 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
807 modest_window_mgr_unregister_header (mgr, header);
809 g_object_unref (priv->outbox_msg);
810 priv->outbox_msg = NULL;
812 g_free (priv->msg_uid);
813 g_free (priv->last_search);
814 g_slist_free (priv->font_items_group);
815 g_slist_free (priv->size_items_group);
816 g_object_unref (priv->attachments);
817 g_object_unref (priv->images);
819 /* This had to stay alive for as long as the combobox that used it: */
820 modest_pair_list_free (priv->from_field_protos);
822 G_OBJECT_CLASS(parent_class)->finalize (obj);
826 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
828 GdkPixbufLoader *loader;
831 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
836 tny_stream_reset (TNY_STREAM (stream));
837 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
838 unsigned char read_buffer[128];
840 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
841 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
845 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
846 g_object_ref (pixbuf);
847 gdk_pixbuf_loader_close (loader, NULL);
848 g_object_unref (loader);
850 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
851 GdkPixbuf *new_pixbuf;
853 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
854 gdk_pixbuf_get_width (pixbuf);
855 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
856 g_object_unref (pixbuf);
864 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
866 ModestMsgEditWindowPrivate *priv;
869 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
871 for (iter = tny_list_create_iterator (attachments);
872 !tny_iterator_is_done (iter);
873 tny_iterator_next (iter)) {
874 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
875 const gchar *cid = tny_mime_part_get_content_id (part);
876 const gchar *mime_type = tny_mime_part_get_content_type (part);
877 if ((cid != NULL)&&(mime_type != NULL)) {
878 TnyStream *stream = tny_mime_part_get_stream (part);
879 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
880 g_object_unref (stream);
882 if (pixbuf != NULL) {
883 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
884 g_object_unref (pixbuf);
887 g_object_unref (part);
892 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
894 TnyMimePart *parent = NULL;
895 const gchar *content_type = NULL;
896 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
898 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
900 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
901 parent = g_object_ref (msg);
902 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
903 TnyList *parts = TNY_LIST (tny_simple_list_new ());
906 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
907 iter = tny_list_create_iterator (parts);
908 while (!tny_iterator_is_done (iter)) {
910 part = TNY_MIME_PART (tny_iterator_get_current (iter));
911 content_type = tny_mime_part_get_content_type (part);
912 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
916 g_object_unref (part);
918 tny_iterator_next (iter);
920 g_object_unref (iter);
921 g_object_unref (parts);
924 if (parent != NULL) {
925 TnyList *parts = TNY_LIST (tny_simple_list_new ());
928 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
929 iter = tny_list_create_iterator (parts);
930 while (!tny_iterator_is_done (iter)) {
932 part = TNY_MIME_PART (tny_iterator_get_current (iter));
933 content_type = tny_mime_part_get_content_type (part);
934 if (content_type && g_str_has_prefix (content_type, "image/")) {
935 tny_list_prepend (priv->images, (GObject *) part);
937 g_object_unref (part);
938 tny_iterator_next (iter);
940 g_object_unref (iter);
941 g_object_unref (parts);
942 g_object_unref (parent);
947 update_last_cid (ModestMsgEditWindow *self, TnyList *attachments)
950 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
952 for (iter = tny_list_create_iterator (attachments) ;
953 !tny_iterator_is_done (iter);
954 tny_iterator_next (iter)) {
955 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
956 const gchar *cid = tny_mime_part_get_content_id (part);
958 char *invalid = NULL;
959 gint int_cid = strtol (cid, &invalid, 10);
960 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
961 priv->last_cid = int_cid;
964 g_object_unref (part);
969 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
972 const gchar *to, *cc, *bcc, *subject;
974 ModestMsgEditWindowPrivate *priv;
976 TnyHeaderFlags priority_flags;
977 TnyFolder *msg_folder;
978 gboolean is_html = FALSE;
980 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
981 g_return_if_fail (TNY_IS_MSG (msg));
983 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
985 header = tny_msg_get_header (msg);
986 to = tny_header_get_to (header);
987 cc = tny_header_get_cc (header);
988 bcc = tny_header_get_bcc (header);
989 subject = tny_header_get_subject (header);
990 priority_flags = tny_header_get_priority (header);
993 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
995 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
996 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
997 gtk_widget_show (priv->cc_caption);
998 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
999 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1000 gtk_widget_hide (priv->cc_caption);
1003 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1004 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1005 gtk_widget_show (priv->bcc_caption);
1006 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1007 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1008 gtk_widget_hide (priv->bcc_caption);
1011 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1012 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1015 update_window_title (self);
1017 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1018 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1020 if ((body == NULL)||(body[0] == '\0')) {
1022 body = modest_text_utils_convert_to_html ("");
1025 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1026 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1029 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1032 /* Add attachments to the view */
1033 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1034 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1035 if (tny_list_get_length (priv->attachments) == 0) {
1036 gtk_widget_hide (priv->attachments_caption);
1038 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1039 gtk_widget_show_all (priv->attachments_caption);
1041 get_related_images (self, msg);
1042 update_last_cid (self, priv->attachments);
1043 update_last_cid (self, priv->images);
1044 replace_with_images (self, priv->images);
1046 if (preserve_is_rich && !is_html) {
1047 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1048 /* Get the default format required from configuration */
1049 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1050 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1053 /* Set the default focus depending on having already a To: field or not */
1054 if ((!to)||(*to == '\0')) {
1055 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1057 gtk_widget_grab_focus (priv->msg_body);
1060 /* TODO: lower priority, select in the From: combo to the
1061 value that comes from msg <- not sure, should it be
1064 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1066 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1067 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1069 modest_msg_edit_window_reset_modified (self);
1071 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1072 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1073 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1074 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1076 if (priv->msg_uid) {
1077 g_free (priv->msg_uid);
1078 priv->msg_uid = NULL;
1081 /* we should set a reference to the incoming message if it is a draft */
1082 msg_folder = tny_msg_get_folder (msg);
1084 if (modest_tny_folder_is_local_folder (msg_folder)) {
1085 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1086 if (type == TNY_FOLDER_TYPE_INVALID)
1087 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1089 if (type == TNY_FOLDER_TYPE_DRAFTS)
1090 priv->draft_msg = g_object_ref(msg);
1091 if (type == TNY_FOLDER_TYPE_OUTBOX)
1092 priv->outbox_msg = g_object_ref(msg);
1093 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1095 g_object_unref (msg_folder);
1100 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1103 GList *item_children, *node;
1104 GtkWidget *bin_child;
1106 bin_child = gtk_bin_get_child (GTK_BIN(item));
1108 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1110 for (node = item_children; node != NULL; node = g_list_next (node)) {
1111 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1112 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1115 g_list_free (item_children);
1119 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1122 GList *item_children, *node;
1124 box = gtk_bin_get_child (GTK_BIN (item));
1125 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1126 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1128 for (node = item_children; node != NULL; node = g_list_next (node)) {
1129 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1130 if (GTK_IS_TOGGLE_BUTTON (node->data))
1131 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1132 else if (GTK_IS_BUTTON (node->data))
1133 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1135 g_list_free (item_children);
1140 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1142 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1143 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1144 GtkWidget *placeholder;
1145 GtkWidget *tool_item;
1150 GtkWidget *sizes_menu;
1151 GtkWidget *fonts_menu;
1152 GSList *radio_group = NULL;
1153 GSList *node = NULL;
1157 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1158 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1160 /* Font color placeholder */
1161 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1162 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1165 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1166 priv->font_color_button = hildon_color_button_new ();
1167 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1168 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1169 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1170 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1171 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1172 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1173 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1175 G_CALLBACK (modest_msg_edit_window_color_button_change),
1178 /* Font size and face placeholder */
1179 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1180 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1182 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1183 priv->size_tool_button_label = gtk_label_new (NULL);
1184 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1185 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1186 size_text,"</span>", NULL);
1187 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1189 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1190 sizes_menu = gtk_menu_new ();
1191 priv->size_items_group = NULL;
1193 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1194 GtkWidget *size_menu_item;
1196 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1197 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1198 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1199 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1200 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1201 gtk_widget_show (size_menu_item);
1203 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1207 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1208 GtkWidget *item = (GtkWidget *) node->data;
1209 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1213 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1214 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1215 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1216 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1217 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1218 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1219 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1220 priv->font_size_toolitem = tool_item;
1223 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1224 priv->font_tool_button_label = gtk_label_new (NULL);
1225 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1226 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1228 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1229 fonts_menu = gtk_menu_new ();
1230 priv->font_items_group = NULL;
1232 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1233 GtkWidget *font_menu_item;
1234 GtkWidget *child_label;
1236 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1237 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1238 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1239 wp_get_font_name (font_index), "</span>", NULL);
1240 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1243 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1244 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1245 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1246 gtk_widget_show (font_menu_item);
1248 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1251 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1252 GtkWidget *item = (GtkWidget *) node->data;
1253 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1256 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1257 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1258 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1259 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1260 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1261 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1262 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1263 priv->font_face_toolitem = tool_item;
1265 /* Set expand and homogeneous for remaining items */
1266 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1267 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1268 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1269 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1270 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1271 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1272 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1273 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1274 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1276 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1277 will not show the tool items added to the placeholders) */
1278 gtk_widget_show_all (parent_priv->toolbar);
1280 /* Set the no show all *after* showing all items. We do not
1281 want the toolbar to be shown with a show all because it
1282 could go agains the gconf setting regarding showing or not
1283 the toolbar of the editor window */
1284 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1290 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1293 ModestWindowPrivate *parent_priv;
1294 ModestMsgEditWindowPrivate *priv;
1295 ModestPair *account_pair = NULL;
1296 ModestDimmingRulesGroup *menu_rules_group = NULL;
1297 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1298 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1299 ModestWindowMgr *mgr = NULL;
1301 g_return_val_if_fail (msg, NULL);
1302 g_return_val_if_fail (account_name, NULL);
1304 mgr = modest_runtime_get_window_mgr ();
1306 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1308 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1309 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1311 /* Menubar. Update the state of some toggles */
1312 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1313 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1314 priv->from_field_protos = get_transports ();
1315 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1316 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1317 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1320 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1322 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1324 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1326 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1327 if (account_pair != NULL)
1328 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1330 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1331 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1332 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1333 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1334 /* Add common dimming rules */
1335 modest_dimming_rules_group_add_rules (menu_rules_group,
1336 modest_msg_edit_window_menu_dimming_entries,
1337 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1338 MODEST_WINDOW (obj));
1339 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1340 modest_msg_edit_window_toolbar_dimming_entries,
1341 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1342 MODEST_WINDOW (obj));
1343 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1344 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1345 MODEST_WINDOW (obj));
1346 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1347 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1348 MODEST_WINDOW (obj));
1349 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1350 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1351 MODEST_WINDOW (obj));
1352 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1353 modest_msg_edit_window_clipboard_dimming_entries,
1354 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1355 MODEST_WINDOW (obj));
1356 /* Insert dimming rules group for this window */
1357 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1358 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1359 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1360 /* Checks the dimming rules */
1361 g_object_unref (menu_rules_group);
1362 g_object_unref (toolbar_rules_group);
1363 g_object_unref (clipboard_rules_group);
1364 gtk_widget_show_all (GTK_WIDGET (obj));
1366 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1368 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1370 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1371 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1372 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1373 priv->update_caption_visibility = TRUE;
1375 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1377 /* Track account-removed signal, this window should be closed
1378 in the case we're creating a mail associated to the account
1380 priv->account_removed_handler_id =
1381 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1383 G_CALLBACK(on_account_removed),
1386 return (ModestWindow*) obj;
1390 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1392 GString **string_buffer = (GString **) user_data;
1394 *string_buffer = g_string_append (*string_buffer, buffer);
1400 * @result: A new string which should be freed with g_free().
1403 get_formatted_data (ModestMsgEditWindow *edit_window)
1405 ModestMsgEditWindowPrivate *priv;
1406 GString *string_buffer = g_string_new ("");
1408 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1410 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1412 return g_string_free (string_buffer, FALSE);
1417 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1420 const gchar *account_name;
1421 ModestMsgEditWindowPrivate *priv;
1422 TnyIterator *att_iter;
1424 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1426 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1428 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1429 g_return_val_if_fail (account_name, NULL);
1432 /* don't free these (except from) */
1433 data = g_slice_new0 (MsgData);
1434 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1436 data->account_name = g_strdup (account_name);
1437 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1438 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1439 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1440 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1441 if (priv->draft_msg) {
1442 data->draft_msg = g_object_ref (priv->draft_msg);
1443 } else if (priv->outbox_msg) {
1444 data->draft_msg = g_object_ref (priv->outbox_msg);
1446 data->draft_msg = NULL;
1449 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1451 gtk_text_buffer_get_bounds (buf, &b, &e);
1452 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1454 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1455 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1457 data->html_body = NULL;
1459 /* deep-copy the data */
1460 att_iter = tny_list_create_iterator (priv->attachments);
1461 data->attachments = NULL;
1462 while (!tny_iterator_is_done (att_iter)) {
1463 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 data->attachments = g_list_append (data->attachments,
1472 tny_iterator_next (att_iter);
1474 g_object_unref (att_iter);
1476 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1477 att_iter = tny_list_create_iterator (priv->images);
1478 data->images = NULL;
1479 while (!tny_iterator_is_done (att_iter)) {
1480 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1482 if (!(TNY_IS_MIME_PART(part))) {
1483 g_warning ("strange data in attachment list");
1484 g_object_unref (part);
1485 tny_iterator_next (att_iter);
1488 cid = tny_mime_part_get_content_id (part);
1490 gchar *image_tag_id;
1491 GtkTextTag *image_tag;
1493 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1494 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1495 g_free (image_tag_id);
1497 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1499 ((gtk_text_iter_has_tag (&iter, image_tag))||
1500 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1501 data->images = g_list_append (data->images,
1502 g_object_ref (part));
1504 g_object_unref (part);
1505 tny_iterator_next (att_iter);
1508 data->priority_flags = priv->priority_flags;
1515 unref_gobject (GObject *obj, gpointer data)
1517 if (!G_IS_OBJECT(obj))
1519 g_object_unref (obj);
1523 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1526 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1534 g_free (data->from);
1535 g_free (data->subject);
1536 g_free (data->plain_body);
1537 g_free (data->html_body);
1538 g_free (data->account_name);
1540 if (data->draft_msg != NULL) {
1541 g_object_unref (data->draft_msg);
1542 data->draft_msg = NULL;
1545 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1546 g_list_free (data->attachments);
1547 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1548 g_list_free (data->images);
1550 g_slice_free (MsgData, data);
1554 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1557 ModestMsgEditWindowPrivate *priv = NULL;
1558 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1560 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1562 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1564 return MODEST_MSG_EDIT_FORMAT_HTML;
1566 return MODEST_MSG_EDIT_FORMAT_TEXT;
1570 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1571 ModestMsgEditFormat format)
1573 ModestMsgEditWindowPrivate *priv;
1575 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1576 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1579 case MODEST_MSG_EDIT_FORMAT_HTML:
1580 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1582 case MODEST_MSG_EDIT_FORMAT_TEXT:
1583 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1586 g_return_if_reached ();
1590 ModestMsgEditFormatState *
1591 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1593 ModestMsgEditFormatState *format_state = NULL;
1594 ModestMsgEditWindowPrivate *priv;
1595 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1597 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1598 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1600 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1602 format_state = g_new0 (ModestMsgEditFormatState, 1);
1603 format_state->bold = buffer_format->bold&0x1;
1604 format_state->italics = buffer_format->italic&0x1;
1605 format_state->bullet = buffer_format->bullet&0x1;
1606 format_state->color = buffer_format->color;
1607 format_state->font_size = buffer_format->font_size;
1608 format_state->font_family = wp_get_font_name (buffer_format->font);
1609 format_state->justification = buffer_format->justification;
1610 g_free (buffer_format);
1612 return format_state;
1617 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1618 const ModestMsgEditFormatState *format_state)
1620 ModestMsgEditWindowPrivate *priv;
1621 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1622 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1623 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1624 g_return_if_fail (format_state != NULL);
1626 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1627 gtk_widget_grab_focus (priv->msg_body);
1628 buffer_format->bold = (format_state->bold != FALSE);
1629 buffer_format->italic = (format_state->italics != FALSE);
1630 buffer_format->color = format_state->color;
1631 buffer_format->font_size = format_state->font_size;
1632 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1633 buffer_format->justification = format_state->justification;
1634 buffer_format->bullet = format_state->bullet;
1636 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1638 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1639 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1640 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1641 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1642 buffer_format->cs.font = (buffer_format->font != current_format->font);
1643 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1644 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1646 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1647 if (buffer_format->cs.bold) {
1648 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1649 GINT_TO_POINTER (buffer_format->bold&0x1));
1651 if (buffer_format->cs.italic) {
1652 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1653 GINT_TO_POINTER (buffer_format->italic&0x1));
1655 if (buffer_format->cs.color) {
1656 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1657 GINT_TO_POINTER (&(buffer_format->color)));
1659 if (buffer_format->cs.font_size) {
1660 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1661 GINT_TO_POINTER (buffer_format->font_size));
1663 if (buffer_format->cs.justification) {
1664 switch (buffer_format->justification) {
1665 case GTK_JUSTIFY_LEFT:
1666 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1667 GINT_TO_POINTER(TRUE));
1669 case GTK_JUSTIFY_CENTER:
1670 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1671 GINT_TO_POINTER(TRUE));
1673 case GTK_JUSTIFY_RIGHT:
1674 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1675 GINT_TO_POINTER(TRUE));
1682 if (buffer_format->cs.font) {
1683 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1684 GINT_TO_POINTER (buffer_format->font));
1686 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1687 if (buffer_format->cs.bullet) {
1688 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1689 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1691 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1693 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1695 g_free (current_format);
1700 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1702 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1704 ModestWindowPrivate *parent_priv;
1705 ModestMsgEditWindowPrivate *priv;
1706 GtkWidget *new_size_menuitem;
1707 GtkWidget *new_font_menuitem;
1709 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1710 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1712 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1713 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1714 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1715 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1717 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1718 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1719 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1722 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1724 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1725 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1727 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1728 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1730 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1731 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1734 switch (buffer_format->justification)
1736 case GTK_JUSTIFY_LEFT:
1737 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentLeftMenu");
1739 case GTK_JUSTIFY_CENTER:
1740 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentCenterMenu");
1742 case GTK_JUSTIFY_RIGHT:
1743 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentRightMenu");
1750 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1752 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1753 G_CALLBACK (modest_msg_edit_window_color_button_change),
1755 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1756 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1757 G_CALLBACK (modest_msg_edit_window_color_button_change),
1760 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1761 buffer_format->font_size))->data);
1762 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1766 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1767 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1768 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1770 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1771 G_CALLBACK (modest_msg_edit_window_size_change),
1773 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1774 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1775 G_CALLBACK (modest_msg_edit_window_size_change),
1779 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1780 buffer_format->font))->data);
1781 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1785 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1786 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1787 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1789 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1790 G_CALLBACK (modest_msg_edit_window_font_change),
1792 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1793 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1794 G_CALLBACK (modest_msg_edit_window_font_change),
1798 g_free (buffer_format);
1802 #ifdef MODEST_HILDON_VERSION_0
1804 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1807 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1808 ModestMsgEditWindowPrivate *priv;
1809 GtkWidget *dialog = NULL;
1811 GdkColor *new_color = NULL;
1813 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1814 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1816 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1817 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1818 g_free (buffer_format);
1820 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1821 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1822 if (new_color != NULL) {
1823 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1824 (gpointer) new_color);
1827 gtk_widget_destroy (dialog);
1832 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1835 ModestMsgEditWindowPrivate *priv;
1836 GtkWidget *dialog = NULL;
1838 GdkColor *old_color = NULL;
1839 const GdkColor *new_color = NULL;
1841 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1842 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1844 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1845 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1847 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1848 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1849 if (new_color != NULL)
1850 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1852 gtk_widget_destroy (dialog);
1858 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1861 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1862 ModestMsgEditWindowPrivate *priv;
1863 GtkWidget *dialog = NULL;
1865 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1866 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1868 dialog = hildon_color_chooser_new ();
1869 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1870 g_free (buffer_format);
1872 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1874 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1875 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1878 gtk_widget_destroy (dialog);
1883 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1886 ModestMsgEditWindowPrivate *priv;
1887 GtkWidget *dialog = NULL;
1888 GdkColor *old_color = NULL;
1890 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1891 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1893 dialog = hildon_color_chooser_new ();
1894 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1896 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1898 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1899 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1901 gtk_widget_destroy (dialog);
1904 #endif /*!MODEST_HILDON_VERSION_0*/
1908 static TnyStream* create_stream_for_uri (const gchar* uri)
1913 TnyStream *result = NULL;
1915 GnomeVFSHandle *handle = NULL;
1916 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1917 if (test == GNOME_VFS_OK) {
1918 /* Create the tinymail stream: */
1919 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1920 result = TNY_STREAM (tny_vfs_stream_new (handle));
1927 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1930 ModestMsgEditWindowPrivate *priv;
1931 GtkWidget *dialog = NULL;
1933 GSList *uris = NULL;
1934 GSList *uri_node = NULL;
1936 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1938 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1939 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1940 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1942 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1944 response = gtk_dialog_run (GTK_DIALOG (dialog));
1946 case GTK_RESPONSE_OK:
1947 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1952 gtk_widget_destroy (dialog);
1954 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1956 GnomeVFSHandle *handle = NULL;
1957 GnomeVFSResult result;
1958 GtkTextIter position;
1959 GtkTextMark *insert_mark;
1961 uri = (const gchar *) uri_node->data;
1962 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1963 if (result == GNOME_VFS_OK) {
1965 GnomeVFSFileInfo info;
1966 gchar *filename, *basename, *escaped_filename;
1967 TnyMimePart *mime_part;
1969 const gchar *mime_type = NULL;
1970 GnomeVFSURI *vfs_uri;
1972 vfs_uri = gnome_vfs_uri_new (uri);
1974 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1975 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1976 g_free (escaped_filename);
1977 gnome_vfs_uri_unref (vfs_uri);
1979 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1980 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1982 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1984 mime_part = tny_platform_factory_new_mime_part
1985 (modest_runtime_get_platform_factory ());
1987 TnyStream *stream = create_stream_for_uri (uri);
1988 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
1990 content_id = g_strdup_printf ("%d", priv->last_cid);
1991 tny_mime_part_set_content_id (mime_part, content_id);
1992 g_free (content_id);
1995 basename = g_path_get_basename (filename);
1996 tny_mime_part_set_filename (mime_part, basename);
1999 pixbuf = pixbuf_from_stream (stream, mime_type);
2001 if (pixbuf != NULL) {
2002 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2003 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2004 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2007 tny_list_prepend (priv->images, (GObject *) mime_part);
2008 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2010 g_object_unref (mime_part);
2019 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2021 GtkWidget *dialog = NULL;
2023 GSList *uris = NULL;
2026 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2027 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2028 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2030 response = gtk_dialog_run (GTK_DIALOG (dialog));
2032 case GTK_RESPONSE_OK:
2033 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2038 gtk_widget_destroy (dialog);
2040 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2041 const gchar *uri = (const gchar *) uri_node->data;
2042 modest_msg_edit_window_attach_file_one (window, uri);
2044 g_slist_foreach (uris, (GFunc) g_free, NULL);
2045 g_slist_free (uris);
2049 modest_msg_edit_window_attach_file_one (
2050 ModestMsgEditWindow *window,
2053 g_return_if_fail (window);
2054 g_return_if_fail (uri);
2056 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2059 GnomeVFSHandle *handle = NULL;
2060 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2061 if (result == GNOME_VFS_OK) {
2062 TnyMimePart *mime_part;
2064 const gchar *mime_type = NULL;
2066 gchar *escaped_filename;
2069 GnomeVFSFileInfo info;
2070 GnomeVFSURI *vfs_uri;
2072 vfs_uri = gnome_vfs_uri_new (uri);
2075 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2076 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2077 g_free (escaped_filename);
2078 gnome_vfs_uri_unref (vfs_uri);
2080 if (gnome_vfs_get_file_info (uri,
2082 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2084 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2085 mime_part = tny_platform_factory_new_mime_part
2086 (modest_runtime_get_platform_factory ());
2087 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2089 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2091 g_object_unref (stream);
2093 content_id = g_strdup_printf ("%d", priv->last_cid);
2094 tny_mime_part_set_content_id (mime_part, content_id);
2095 g_free (content_id);
2098 basename = g_path_get_basename (filename);
2099 tny_mime_part_set_filename (mime_part, basename);
2102 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2103 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2105 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2106 gtk_widget_show_all (priv->attachments_caption);
2107 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2109 g_object_unref (mime_part);
2114 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2117 ModestMsgEditWindowPrivate *priv;
2120 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2121 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2123 if (att_list == NULL) {
2124 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2126 g_object_ref (att_list);
2129 if (tny_list_get_length (att_list) == 0) {
2130 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2132 GtkWidget *confirmation_dialog = NULL;
2133 gboolean dialog_response;
2134 gchar *message = NULL;
2135 gchar *filename = NULL;
2137 if (tny_list_get_length (att_list) == 1) {
2139 iter = tny_list_create_iterator (att_list);
2140 part = (TnyMimePart *) tny_iterator_get_current (iter);
2141 g_object_unref (iter);
2142 if (TNY_IS_MSG (part)) {
2143 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2145 filename = g_strdup (tny_header_get_subject (header));
2146 g_object_unref (header);
2148 if (filename == NULL) {
2149 filename = g_strdup (_("mail_va_no_subject"));
2152 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2154 g_object_unref (part);
2156 filename = g_strdup ("");
2158 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2159 (tny_list_get_length (att_list) == 1)), filename);
2161 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2163 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2164 gtk_widget_destroy (confirmation_dialog);
2165 if (!dialog_response) {
2166 g_object_unref (att_list);
2169 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2171 for (iter = tny_list_create_iterator (att_list);
2172 !tny_iterator_is_done (iter);
2173 tny_iterator_next (iter)) {
2174 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2175 const gchar *att_id;
2176 tny_list_remove (priv->attachments, (GObject *) mime_part);
2178 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2180 if (tny_list_get_length (priv->attachments) == 0)
2181 gtk_widget_hide (priv->attachments_caption);
2182 att_id = tny_mime_part_get_content_id (mime_part);
2184 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2186 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2187 g_object_unref (mime_part);
2191 g_object_unref (att_list);
2193 /* if the last attachment has been removed, focus the Subject: field */
2194 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2195 gtk_widget_grab_focus (priv->subject_field);
2199 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2202 ModestMsgEditWindowPrivate *priv;
2203 GdkColor *new_color;
2204 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2206 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2207 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2210 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2212 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2214 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2216 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2221 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2224 ModestMsgEditWindowPrivate *priv;
2225 gint new_size_index;
2226 ModestMsgEditWindow *window;
2229 window = MODEST_MSG_EDIT_WINDOW (userdata);
2230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2231 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2233 if (gtk_check_menu_item_get_active (menu_item)) {
2235 WPTextBufferFormat format;
2237 memset (&format, 0, sizeof (format));
2238 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2240 label = gtk_bin_get_child (GTK_BIN (menu_item));
2242 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2243 format.cs.font_size = TRUE;
2244 format.cs.text_position = TRUE;
2245 format.cs.font = TRUE;
2246 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2247 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2249 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2250 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2251 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2253 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2254 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2255 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2261 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2264 ModestMsgEditWindowPrivate *priv;
2265 gint new_font_index;
2266 ModestMsgEditWindow *window;
2269 window = MODEST_MSG_EDIT_WINDOW (userdata);
2270 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2271 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2273 if (gtk_check_menu_item_get_active (menu_item)) {
2276 label = gtk_bin_get_child (GTK_BIN (menu_item));
2278 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2280 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2281 GINT_TO_POINTER(new_font_index)))
2282 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2284 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2285 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2286 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2292 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2294 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2295 ModestWindowPrivate *parent_priv;
2296 ModestWindowMgr *mgr;
2297 gboolean is_fullscreen;
2298 GtkAction *fs_toggle_action;
2301 mgr = modest_runtime_get_window_mgr ();
2302 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2304 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2306 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2307 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2308 if (is_fullscreen != active)
2309 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2317 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2320 ModestMsgEditWindowPrivate *priv = NULL;
2321 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2323 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2324 if (!priv->update_caption_visibility)
2327 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2329 gtk_widget_show (priv->cc_caption);
2331 gtk_widget_hide (priv->cc_caption);
2333 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2337 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2340 ModestMsgEditWindowPrivate *priv = NULL;
2341 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2343 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2344 if (!priv->update_caption_visibility)
2347 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2349 gtk_widget_show (priv->bcc_caption);
2351 gtk_widget_hide (priv->bcc_caption);
2353 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2357 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2358 ModestRecptEditor *editor)
2360 ModestMsgEditWindowPrivate *priv;
2362 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2363 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2364 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2366 if (editor == NULL) {
2367 GtkWidget *view_focus;
2368 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2370 /* This code should be kept in sync with ModestRecptEditor. The
2371 textview inside the recpt editor is the one that really gets the
2372 focus. As it's inside a scrolled window, and this one inside the
2373 hbox recpt editor inherits from, we'll need to go up in the
2374 hierarchy to know if the text view is part of the recpt editor
2375 or if it's a different text entry */
2377 if (gtk_widget_get_parent (view_focus)) {
2378 GtkWidget *first_parent;
2380 first_parent = gtk_widget_get_parent (view_focus);
2381 if (gtk_widget_get_parent (first_parent) &&
2382 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2383 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2388 editor = MODEST_RECPT_EDITOR (priv->to_field);
2392 modest_address_book_select_addresses (editor);
2397 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2399 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2401 modest_msg_edit_window_open_addressbook (window, NULL);
2405 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2406 gboolean show_toolbar)
2408 ModestWindowPrivate *parent_priv;
2409 const gchar *action_name;
2412 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2413 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2415 /* We can not just use the code of
2416 modest_msg_edit_window_setup_toolbar because it has a
2417 mixture of both initialization and creation code. */
2419 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2421 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2423 /* Update also the actions (to update the toggles in the
2424 menus), we have to do it manually because some other window
2425 of the same time could have changed it (remember that the
2426 toolbar fullscreen mode is shared by all the windows of the
2428 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2429 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2431 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2433 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2434 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2440 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2441 TnyHeaderFlags priority_flags)
2443 ModestMsgEditWindowPrivate *priv;
2444 ModestWindowPrivate *parent_priv;
2446 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2448 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2449 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2451 if (priv->priority_flags != priority_flags) {
2452 GtkAction *priority_action = NULL;
2454 priv->priority_flags = priority_flags;
2456 switch (priority_flags) {
2457 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2458 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2459 gtk_widget_show (priv->priority_icon);
2460 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2461 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2463 case TNY_HEADER_FLAG_LOW_PRIORITY:
2464 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2465 gtk_widget_show (priv->priority_icon);
2466 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2467 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2470 gtk_widget_hide (priv->priority_icon);
2471 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2472 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2475 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2476 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2481 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2484 ModestMsgEditWindowPrivate *priv;
2485 ModestWindowPrivate *parent_priv;
2486 gint current_format;
2488 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2490 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2491 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2493 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2494 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2496 if (current_format != file_format) {
2497 switch (file_format) {
2498 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2499 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2500 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2502 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2506 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2507 response = gtk_dialog_run (GTK_DIALOG (dialog));
2508 gtk_widget_destroy (dialog);
2509 if (response == GTK_RESPONSE_OK) {
2510 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2512 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2513 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2518 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2523 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2526 ModestMsgEditWindowPrivate *priv;
2527 WPTextBufferFormat oldfmt, fmt;
2528 gint old_position = 0;
2532 GdkColor *color = NULL;
2533 gboolean bold, bold_set, italic, italic_set;
2534 gboolean underline, underline_set;
2535 gboolean strikethrough, strikethrough_set;
2536 gboolean position_set;
2537 gboolean font_size_set, font_set, color_set;
2540 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2541 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2543 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2545 /* First we get the currently selected font information */
2546 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2548 switch (oldfmt.text_position) {
2549 case TEXT_POSITION_NORMAL:
2552 case TEXT_POSITION_SUPERSCRIPT:
2560 g_object_set (G_OBJECT (dialog),
2561 "bold", oldfmt.bold != FALSE,
2562 "bold-set", !oldfmt.cs.bold,
2563 "underline", oldfmt.underline != FALSE,
2564 "underline-set", !oldfmt.cs.underline,
2565 "italic", oldfmt.italic != FALSE,
2566 "italic-set", !oldfmt.cs.italic,
2567 "strikethrough", oldfmt.strikethrough != FALSE,
2568 "strikethrough-set", !oldfmt.cs.strikethrough,
2569 "color", &oldfmt.color,
2570 "color-set", !oldfmt.cs.color,
2571 "size", wp_font_size[oldfmt.font_size],
2572 "size-set", !oldfmt.cs.font_size,
2573 "position", old_position,
2574 "position-set", !oldfmt.cs.text_position,
2575 "family", wp_get_font_name (oldfmt.font),
2576 "family-set", !oldfmt.cs.font,
2579 gtk_widget_show_all (dialog);
2580 response = gtk_dialog_run (GTK_DIALOG (dialog));
2581 if (response == GTK_RESPONSE_OK) {
2583 g_object_get( dialog,
2585 "bold-set", &bold_set,
2586 "underline", &underline,
2587 "underline-set", &underline_set,
2589 "italic-set", &italic_set,
2590 "strikethrough", &strikethrough,
2591 "strikethrough-set", &strikethrough_set,
2593 "color-set", &color_set,
2595 "size-set", &font_size_set,
2596 "family", &font_name,
2597 "family-set", &font_set,
2598 "position", &position,
2599 "position-set", &position_set,
2604 if (response == GTK_RESPONSE_OK) {
2605 memset(&fmt, 0, sizeof(fmt));
2611 fmt.italic = italic;
2612 fmt.cs.italic = TRUE;
2614 if (underline_set) {
2615 fmt.underline = underline;
2616 fmt.cs.underline = TRUE;
2618 if (strikethrough_set) {
2619 fmt.strikethrough = strikethrough;
2620 fmt.cs.strikethrough = TRUE;
2625 ? TEXT_POSITION_NORMAL
2626 : ( ( position == 1 )
2627 ? TEXT_POSITION_SUPERSCRIPT
2628 : TEXT_POSITION_SUBSCRIPT );
2629 fmt.cs.text_position = TRUE;
2630 fmt.font_size = oldfmt.font_size;
2634 fmt.cs.color = TRUE;
2637 fmt.font = wp_get_font_index(font_name,
2642 if (font_size_set) {
2643 fmt.cs.font_size = TRUE;
2644 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2646 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2647 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2649 gtk_widget_destroy (dialog);
2651 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2655 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2657 ModestMsgEditWindowPrivate *priv;
2659 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2660 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2662 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2664 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2665 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2670 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2672 ModestMsgEditWindowPrivate *priv;
2674 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2675 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2677 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2679 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2680 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2685 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2687 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2689 priv->can_undo = can_undo;
2693 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2695 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2697 priv->can_redo = can_redo;
2701 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2703 ModestMsgEditWindowPrivate *priv;
2704 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2705 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2707 return priv->can_undo;
2711 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2713 ModestMsgEditWindowPrivate *priv;
2714 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2715 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2717 return priv->can_redo;
2722 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2725 GtkTextIter match_start, match_end;
2727 if (image_id == NULL)
2730 gtk_text_buffer_get_start_iter (buffer, &iter);
2732 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2733 GSList *tags = gtk_text_iter_get_tags (&match_start);
2735 for (node = tags; node != NULL; node = g_slist_next (node)) {
2736 GtkTextTag *tag = (GtkTextTag *) node->data;
2737 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2738 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2739 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2741 offset = gtk_text_iter_get_offset (&match_start);
2742 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2743 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2747 gtk_text_iter_forward_char (&iter);
2752 message_is_empty (ModestMsgEditWindow *window)
2754 ModestMsgEditWindowPrivate *priv = NULL;
2756 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2757 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2759 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2760 * so we can ignore markup.
2762 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2765 count = gtk_text_buffer_get_char_count (buf);
2771 msg_body_focus (GtkWidget *focus,
2772 GdkEventFocus *event,
2776 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2777 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
2778 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
2783 recpt_field_changed (GtkTextBuffer *buffer,
2784 ModestMsgEditWindow *editor)
2786 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2787 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
2791 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2793 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2794 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
2798 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2800 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2801 GtkTextBuffer *buffer;
2803 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2804 gtk_text_buffer_set_modified (buffer, FALSE);
2805 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2806 gtk_text_buffer_set_modified (buffer, FALSE);
2807 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2808 gtk_text_buffer_set_modified (buffer, FALSE);
2809 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2813 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2815 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2816 GtkTextBuffer *buffer;
2818 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2819 if (gtk_text_buffer_get_modified (buffer))
2821 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2822 if (gtk_text_buffer_get_modified (buffer))
2824 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2825 if (gtk_text_buffer_get_modified (buffer))
2827 if (gtk_text_buffer_get_modified (priv->text_buffer))
2837 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2839 ModestMsgEditWindowPrivate *priv = NULL;
2841 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2842 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2844 /* check if there's no recipient added */
2845 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2846 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2847 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2848 /* no recipient contents, then select contacts */
2849 modest_msg_edit_window_open_addressbook (window, NULL);
2853 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2854 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2857 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2858 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2861 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2862 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2866 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2867 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2868 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2875 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2876 ModestMsgEditWindow *window)
2878 modest_msg_edit_window_offer_attach_file (window);
2882 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2884 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2886 return priv->clipboard_text;
2890 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2892 ModestMsgEditWindow *window)
2894 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2895 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2897 if (!GTK_WIDGET_VISIBLE (window))
2900 text = gtk_clipboard_wait_for_text (selection_clipboard);
2902 if (priv->clipboard_text != NULL) {
2903 g_free (priv->clipboard_text);
2905 priv->clipboard_text = text;
2907 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2910 subject_field_move_cursor (GtkEntry *entry,
2911 GtkMovementStep step,
2916 if (!GTK_WIDGET_VISIBLE (window))
2919 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2923 update_window_title (ModestMsgEditWindow *window)
2925 ModestMsgEditWindowPrivate *priv = NULL;
2926 const gchar *subject;
2928 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2929 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2930 if (subject == NULL || subject[0] == '\0')
2931 subject = _("mail_va_new_email");
2933 gtk_window_set_title (GTK_WINDOW (window), subject);
2938 subject_field_changed (GtkEditable *editable,
2939 ModestMsgEditWindow *window)
2941 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2942 update_window_title (window);
2943 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2944 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2945 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2949 subject_field_insert_text (GtkEditable *editable,
2951 gint new_text_length,
2953 ModestMsgEditWindow *window)
2955 GString *result = g_string_new ("");
2957 gint result_len = 0;
2958 const gchar *entry_text = NULL;
2961 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2962 old_length = g_utf8_strlen (entry_text, -1);
2964 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2965 gunichar c = g_utf8_get_char_validated (current, 8);
2966 /* Invalid unichar, stop */
2972 result = g_string_append_unichar (result, c);
2976 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2977 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2980 /* Prevent endless recursion */
2981 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2982 g_signal_emit_by_name (editable, "insert-text",
2983 (gpointer) result->str, (gpointer) result->len,
2984 (gpointer) position, (gpointer) window);
2985 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2989 if (result_len + old_length > 1000) {
2990 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2991 dgettext("hildon-common-strings",
2992 "ckdg_ib_maximum_characters_reached"));
2995 g_string_free (result, TRUE);
2999 text_buffer_insert_text (GtkTextBuffer *buffer,
3002 gint new_text_length,
3003 ModestMsgEditWindow *window)
3005 GString *result = g_string_new ("");
3007 gint result_len = 0;
3008 gboolean changed = FALSE;
3010 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3011 gunichar c = g_utf8_get_char_validated (current, 8);
3012 /* Invalid unichar, stop */
3018 result = g_string_append_c (result, ' ');
3022 result = g_string_append_unichar (result, c);
3028 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3029 g_signal_handlers_block_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3030 g_signal_emit_by_name (buffer, "insert-text",
3032 (gpointer) result->str, (gpointer) result->len,
3034 g_signal_handlers_unblock_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3037 g_string_free (result, TRUE);
3041 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3044 ModestMsgEditWindowPrivate *priv = NULL;
3046 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3047 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3049 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3052 gtk_widget_show_all (priv->find_toolbar);
3053 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3055 gtk_widget_hide_all (priv->find_toolbar);
3056 gtk_widget_grab_focus (priv->msg_body);
3062 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3064 GtkTextIter *match_start,
3065 GtkTextIter *match_end)
3067 GtkTextIter end_iter;
3068 gchar *str_casefold;
3071 gchar *range_casefold;
3074 gboolean result = FALSE;
3081 gtk_text_iter_forward_to_end (&end_iter);
3083 str_casefold = g_utf8_casefold (str, -1);
3084 str_chars_n = strlen (str);
3086 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3087 range_casefold = g_utf8_casefold (range_text, -1);
3088 range_chars_n = strlen (range_casefold);
3090 if (range_chars_n < str_chars_n) {
3091 g_free (str_casefold);
3092 g_free (range_text);
3093 g_free (range_casefold);
3097 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3098 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3099 if (!g_utf8_collate (range_subtext, str_casefold)) {
3100 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3102 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3103 match_start, match_end, NULL);
3104 g_free (found_text);
3106 g_free (range_subtext);
3110 g_free (str_casefold);
3111 g_free (range_text);
3112 g_free (range_casefold);
3119 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3120 ModestMsgEditWindow *window)
3122 gchar *current_search = NULL;
3123 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3125 GtkTextIter selection_start, selection_end;
3126 GtkTextIter match_start, match_end;
3127 gboolean continue_search = FALSE;
3129 if (message_is_empty (window)) {
3130 g_free (priv->last_search);
3131 priv->last_search = NULL;
3132 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3136 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3137 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3138 g_free (current_search);
3139 g_free (priv->last_search);
3140 priv->last_search = NULL;
3141 /* Information banner about empty search */
3142 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3146 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3147 continue_search = TRUE;
3149 g_free (priv->last_search);
3150 priv->last_search = g_strdup (current_search);
3153 if (continue_search) {
3154 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3155 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3156 &match_start, &match_end);
3158 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3160 GtkTextIter buffer_start;
3161 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3162 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3163 &match_start, &match_end);
3165 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3168 /* Mark as selected the string found in search */
3170 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3171 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3173 g_free (priv->last_search);
3174 priv->last_search = NULL;
3176 g_free (current_search);
3180 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3181 ModestMsgEditWindow *window)
3183 GtkToggleAction *toggle;
3184 ModestWindowPrivate *parent_priv;
3185 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3187 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3188 gtk_toggle_action_set_active (toggle, FALSE);
3192 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3194 ModestMsgEditWindowPrivate *priv;
3196 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3201 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3204 ModestMsgEditWindowPrivate *priv;
3206 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3212 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3215 ModestMsgEditWindowPrivate *priv;
3216 TnyHeader *header = NULL;
3218 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3219 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3221 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3222 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3224 if (priv->draft_msg != NULL) {
3225 g_object_unref (priv->draft_msg);
3228 if (draft != NULL) {
3229 g_object_ref (draft);
3230 header = tny_msg_get_header (draft);
3231 if (priv->msg_uid) {
3232 g_free (priv->msg_uid);
3233 priv->msg_uid = NULL;
3235 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3236 if (GTK_WIDGET_REALIZED (window))
3237 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3240 priv->draft_msg = draft;
3244 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3245 GtkTextIter *start, GtkTextIter *end,
3248 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3249 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3252 if (tag == NULL+13) return;
3253 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3254 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3255 replace_with_images (window, priv->images);
3260 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3263 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3265 g_return_if_fail (TNY_IS_MIME_PART (part));
3266 tny_list_prepend (priv->attachments, (GObject *) part);
3267 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3268 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3269 gtk_widget_show_all (priv->attachments_caption);
3270 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3274 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3276 ModestMsgEditWindowPrivate *priv;
3278 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3279 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3281 return priv->msg_uid;
3285 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3286 ModestMsgEditWindowWidgetType widget_type)
3288 ModestMsgEditWindowPrivate *priv;
3290 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3291 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3293 switch (widget_type) {
3294 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3295 return priv->msg_body;
3297 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3298 return priv->to_field;
3300 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3301 return priv->cc_field;
3303 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3304 return priv->bcc_field;
3306 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3307 return priv->subject_field;
3309 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3310 return priv->attachments_view;
3318 remove_tags (WPTextBuffer *buffer)
3320 GtkTextIter start, end;
3322 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3323 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3325 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3329 on_account_removed (TnyAccountStore *account_store,
3330 TnyAccount *account,
3333 /* Do nothing if it's a store account, because we use the
3334 transport to send the messages */
3335 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3336 const gchar *parent_acc = NULL;
3337 const gchar *our_acc = NULL;
3339 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3340 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3341 /* Close this window if I'm showing a message of the removed account */
3342 if (strcmp (parent_acc, our_acc) == 0)
3343 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3348 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3350 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3352 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3358 set_zoom_do_nothing (ModestWindow *window,
3364 get_zoom_do_nothing (ModestWindow *window)