1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include "modest-maemo-utils.h"
81 #define DEFAULT_FONT_SIZE 3
82 #define DEFAULT_FONT 2
83 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
84 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
85 #define DEFAULT_MAIN_VBOX_SPACING 6
86 #define SUBJECT_MAX_LENGTH 1000
87 #define IMAGE_MAX_WIDTH 560
88 #define DEFAULT_FONT_SCALE 1.5
90 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
91 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
92 static void modest_msg_edit_window_finalize (GObject *obj);
94 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
95 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
96 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
98 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
99 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
100 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
101 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
102 GtkTextIter *start, GtkTextIter *end,
104 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
105 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
106 static void subject_field_insert_text (GtkEditable *editable,
108 gint new_text_length,
110 ModestMsgEditWindow *window);
111 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
113 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
115 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
117 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
118 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
119 GdkEventWindowState *event,
121 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
122 ModestRecptEditor *editor);
123 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
124 ModestMsgEditWindow *window);
126 /* ModestWindow methods implementation */
127 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
128 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
129 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
130 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
131 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
132 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
133 gboolean show_toolbar);
134 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
136 ModestMsgEditWindow *window);
137 static void subject_field_move_cursor (GtkEntry *entry,
138 GtkMovementStep step,
142 static void update_window_title (ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
148 ModestMsgEditWindow *window);
149 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
151 GtkTextIter *match_start,
152 GtkTextIter *match_end);
154 static void remove_tags (WPTextBuffer *buffer);
156 static void on_account_removed (TnyAccountStore *account_store,
161 static void DEBUG_BUFFER (WPTextBuffer *buffer)
166 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
167 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
168 while (!gtk_text_iter_is_end (&iter)) {
169 GString *output = g_string_new ("");
170 GSList *toggled_tags;
173 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
174 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
175 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
176 GtkTextTag *tag = (GtkTextTag *) node->data;
178 g_object_get (G_OBJECT (tag), "name", &name, NULL);
179 output = g_string_append (output, name);
180 g_string_append (output, " ");
182 output = g_string_append (output, "] OPENED [ ");
183 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
184 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
185 GtkTextTag *tag = (GtkTextTag *) node->data;
187 g_object_get (G_OBJECT (tag), "name", &name, NULL);
188 output = g_string_append (output, name);
189 g_string_append (output, " ");
191 output = g_string_append (output, "]\n");
192 g_message ("%s", output->str);
193 g_string_free (output, TRUE);
194 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
196 g_message ("END BUFFER");
201 /* static gboolean */
202 /* on_key_pressed (GtkWidget *self, */
203 /* GdkEventKey *event, */
204 /* gpointer user_data); */
206 /* list my signals */
213 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
214 struct _ModestMsgEditWindowPrivate {
216 GtkWidget *header_box;
218 ModestPairList *from_field_protos;
219 GtkWidget *from_field;
223 GtkWidget *bcc_field;
224 GtkWidget *subject_field;
225 GtkWidget *attachments_view;
226 GtkWidget *priority_icon;
227 GtkWidget *add_attachment_button;
229 GtkWidget *cc_caption;
230 GtkWidget *bcc_caption;
231 gboolean update_caption_visibility;
232 GtkWidget *attachments_caption;
234 GtkTextBuffer *text_buffer;
236 GtkWidget *font_size_toolitem;
237 GtkWidget *font_face_toolitem;
238 GtkWidget *font_color_button;
239 GSList *font_items_group;
240 GtkWidget *font_tool_button_label;
241 GSList *size_items_group;
242 GtkWidget *size_tool_button_label;
244 GtkWidget *find_toolbar;
248 GtkWidget *scroll_area;
249 gint last_vadj_upper;
255 TnyHeaderFlags priority_flags;
259 gboolean can_undo, can_redo;
260 gulong clipboard_change_handler_id;
261 gulong default_clipboard_change_handler_id;
262 gulong account_removed_handler_id;
263 gchar *clipboard_text;
272 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
273 MODEST_TYPE_MSG_EDIT_WINDOW, \
274 ModestMsgEditWindowPrivate))
276 static GtkWindowClass *parent_class = NULL;
278 /* uncomment the following if you have defined any signals */
279 /* static guint signals[LAST_SIGNAL] = {0}; */
282 modest_msg_edit_window_get_type (void)
284 static GType my_type = 0;
286 static const GTypeInfo my_info = {
287 sizeof(ModestMsgEditWindowClass),
288 NULL, /* base init */
289 NULL, /* base finalize */
290 (GClassInitFunc) modest_msg_edit_window_class_init,
291 NULL, /* class finalize */
292 NULL, /* class data */
293 sizeof(ModestMsgEditWindow),
295 (GInstanceInitFunc) modest_msg_edit_window_init,
298 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
299 "ModestMsgEditWindow",
302 wp_text_buffer_library_init ();
308 save_state (ModestWindow *self)
310 modest_widget_memory_save (modest_runtime_get_conf(),
311 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
316 restore_settings (ModestMsgEditWindow *self)
318 modest_widget_memory_restore (modest_runtime_get_conf(),
319 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
324 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
326 GObjectClass *gobject_class;
327 ModestWindowClass *modest_window_class;
328 gobject_class = (GObjectClass*) klass;
329 modest_window_class = (ModestWindowClass*) klass;
331 parent_class = g_type_class_peek_parent (klass);
332 gobject_class->finalize = modest_msg_edit_window_finalize;
334 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
335 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
336 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
337 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
338 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
339 modest_window_class->save_state_func = save_state;
340 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
342 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
346 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
348 ModestMsgEditWindowPrivate *priv;
349 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
351 priv->msg_body = NULL;
352 priv->from_field = NULL;
353 priv->to_field = NULL;
354 priv->cc_field = NULL;
355 priv->bcc_field = NULL;
356 priv->subject_field = NULL;
357 priv->attachments = NULL;
360 priv->zoom_level = 1.0;
362 priv->cc_caption = NULL;
363 priv->bcc_caption = NULL;
364 priv->update_caption_visibility = FALSE;
366 priv->priority_flags = 0;
368 priv->find_toolbar = NULL;
369 priv->last_search = NULL;
371 priv->draft_msg = NULL;
372 priv->outbox_msg = NULL;
373 priv->msg_uid = NULL;
375 priv->can_undo = FALSE;
376 priv->can_redo = FALSE;
377 priv->clipboard_change_handler_id = 0;
378 priv->default_clipboard_change_handler_id = 0;
379 priv->account_removed_handler_id = 0;
380 priv->clipboard_text = NULL;
383 priv->last_vadj_upper = 0;
385 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
386 GTK_WINDOW(obj),"applications_email_editor");
390 /* FIXME: this is a dup from the one in gtk/ */
393 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
395 static ModestPairList*
396 get_transports (void)
398 GSList *transports = NULL;
400 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
401 GSList *accounts = modest_account_mgr_account_names (account_mgr,
402 TRUE /* only enabled accounts. */);
404 GSList *cursor = accounts;
406 gchar *account_name = cursor->data;
407 gchar *from_string = NULL;
409 from_string = modest_account_mgr_get_from_string (account_mgr,
413 if (from_string && account_name) {
414 gchar *name = account_name;
415 ModestPair *pair = modest_pair_new ((gpointer) name,
416 (gpointer) from_string , TRUE);
417 transports = g_slist_prepend (transports, pair);
420 cursor = cursor->next;
422 g_slist_free (accounts); /* only free the accounts, not the elements,
423 * because they are used in the pairlist */
427 void vadj_changed (GtkAdjustment *adj,
428 ModestMsgEditWindow *window)
430 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
432 GdkRectangle rectangle, cursor_rectangle;
433 GtkTextIter position;
437 /* We detect if cursor is visible using the full height, not only the center. This
439 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
440 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
442 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
443 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
445 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
446 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
448 if (gtk_widget_is_focus (priv->msg_body) &&
450 if (priv->last_vadj_upper != adj->upper) {
453 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
454 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
455 insert, 0.1, FALSE, 0.0, 0.0);
458 priv->last_vadj_upper = adj->upper;
463 init_window (ModestMsgEditWindow *obj)
465 GtkWidget *from_caption, *to_caption, *subject_caption;
466 GtkWidget *main_vbox;
467 ModestMsgEditWindowPrivate *priv;
469 GtkSizeGroup *size_group;
471 GtkWidget *subject_box;
472 GtkWidget *attachment_icon;
473 GtkWidget *window_box;
474 #if (GTK_MINOR_VERSION >= 10)
475 GdkAtom deserialize_type;
477 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
479 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
481 /* Note: This ModestPairList* must exist for as long as the combo
482 * that uses it, because the ModestComboBox uses the ID opaquely,
483 * so it can't know how to manage its memory. */
484 priv->from_field_protos = get_transports ();
486 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
488 priv->to_field = modest_recpt_editor_new ();
489 priv->cc_field = modest_recpt_editor_new ();
490 priv->bcc_field = modest_recpt_editor_new ();
491 subject_box = gtk_hbox_new (FALSE, 0);
492 priv->priority_icon = gtk_image_new ();
493 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
494 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
495 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
496 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
497 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
498 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
499 priv->add_attachment_button = gtk_button_new ();
500 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
501 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
502 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
503 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
504 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
505 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
506 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
507 priv->attachments_view = modest_attachments_view_new (NULL);
509 priv->header_box = gtk_vbox_new (FALSE, 0);
511 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
512 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
513 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
514 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
515 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
516 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
517 g_object_unref (size_group);
519 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
520 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
521 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
522 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
523 gtk_size_group_add_widget (size_group, priv->subject_field);
524 gtk_size_group_add_widget (size_group, priv->attachments_view);
525 g_object_unref (size_group);
527 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
528 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
529 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
530 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
531 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
532 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
533 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
536 priv->msg_body = wp_text_view_new ();
537 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
538 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
539 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
540 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
541 #if (GTK_MINOR_VERSION >= 10)
542 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
543 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
545 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
546 deserialize_type, TRUE);
548 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
550 priv->find_toolbar = hildon_find_toolbar_new (NULL);
551 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
553 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
555 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
556 G_CALLBACK (text_buffer_refresh_attributes), obj);
557 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
558 G_CALLBACK (text_buffer_can_undo), obj);
559 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
560 G_CALLBACK (text_buffer_can_redo), obj);
561 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
562 G_CALLBACK (body_changed), obj);
563 g_signal_connect (G_OBJECT (obj), "window-state-event",
564 G_CALLBACK (modest_msg_edit_window_window_state_event),
566 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
567 G_CALLBACK (text_buffer_apply_tag), obj);
568 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
569 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
570 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
571 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
572 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
573 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
575 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
576 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
578 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
579 G_CALLBACK (msg_body_focus), obj);
580 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
581 G_CALLBACK (msg_body_focus), obj);
582 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
583 "changed", G_CALLBACK (recpt_field_changed), obj);
584 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
585 "changed", G_CALLBACK (recpt_field_changed), obj);
586 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
587 "changed", G_CALLBACK (recpt_field_changed), obj);
588 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
589 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
590 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
592 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
593 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
595 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
596 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
597 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
598 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
600 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
602 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
603 frame = gtk_frame_new (NULL);
604 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
606 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
607 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
608 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
610 G_CALLBACK (vadj_changed),
612 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
614 window_box = gtk_vbox_new (FALSE, 0);
615 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
616 gtk_container_add (GTK_CONTAINER(obj), window_box);
617 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
618 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
620 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
621 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
622 priv->default_clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
623 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
628 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
630 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
632 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
633 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
634 priv->clipboard_change_handler_id))
635 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
636 priv->clipboard_change_handler_id);
637 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
638 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
639 priv->default_clipboard_change_handler_id))
640 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
641 priv->default_clipboard_change_handler_id);
643 if (priv->account_removed_handler_id &&
644 g_signal_handler_is_connected (modest_runtime_get_account_store (),
645 priv->account_removed_handler_id))
646 g_signal_handler_disconnect(modest_runtime_get_account_store (),
647 priv->account_removed_handler_id);
651 modest_msg_edit_window_finalize (GObject *obj)
653 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
655 /* Sanity check: shouldn't be needed, the window mgr should
656 call this function before */
657 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
659 if (priv->clipboard_text != NULL) {
660 g_free (priv->clipboard_text);
661 priv->clipboard_text = NULL;
664 if (priv->draft_msg != NULL) {
665 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
666 if (TNY_IS_HEADER (header)) {
667 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
668 modest_window_mgr_unregister_header (mgr, header);
670 g_object_unref (priv->draft_msg);
671 priv->draft_msg = NULL;
673 if (priv->outbox_msg != NULL) {
674 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
675 if (TNY_IS_HEADER (header)) {
676 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
677 modest_window_mgr_unregister_header (mgr, header);
679 g_object_unref (priv->outbox_msg);
680 priv->outbox_msg = NULL;
682 if (priv->msg_uid != NULL) {
683 g_free (priv->msg_uid);
684 priv->msg_uid = NULL;
687 /* This had to stay alive for as long as the combobox that used it: */
688 modest_pair_list_free (priv->from_field_protos);
690 G_OBJECT_CLASS(parent_class)->finalize (obj);
694 menubar_to_menu (GtkUIManager *ui_manager)
696 GtkWidget *main_menu;
700 /* Create new main menu */
701 main_menu = gtk_menu_new();
703 /* Get the menubar from the UI manager */
704 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
706 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
710 menu = GTK_WIDGET (iter->data);
711 gtk_widget_reparent(menu, main_menu);
713 iter = g_list_next (iter);
719 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
721 GdkPixbufLoader *loader;
724 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
729 tny_stream_reset (TNY_STREAM (stream));
730 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
731 unsigned char read_buffer[128];
733 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
734 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
738 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
739 g_object_ref (pixbuf);
740 gdk_pixbuf_loader_close (loader, NULL);
741 g_object_unref (loader);
743 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
744 GdkPixbuf *new_pixbuf;
746 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
747 gdk_pixbuf_get_width (pixbuf);
748 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
749 g_object_unref (pixbuf);
757 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
759 ModestMsgEditWindowPrivate *priv;
762 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
764 for (node = attachments; node != NULL; node = g_list_next (node)) {
765 TnyMimePart *part = (TnyMimePart *) node->data;
766 const gchar *cid = tny_mime_part_get_content_id (part);
767 const gchar *mime_type = tny_mime_part_get_content_type (part);
768 if ((cid != NULL)&&(mime_type != NULL)) {
769 TnyStream *stream = tny_mime_part_get_stream (part);
770 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
771 g_object_unref (stream);
773 if (pixbuf != NULL) {
774 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
775 g_object_unref (pixbuf);
782 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
784 TnyMimePart *parent = NULL;
785 const gchar *content_type = NULL;
786 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
788 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
790 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
791 parent = g_object_ref (msg);
792 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
793 TnyList *parts = TNY_LIST (tny_simple_list_new ());
796 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
797 iter = tny_list_create_iterator (parts);
798 while (!tny_iterator_is_done (iter)) {
800 part = TNY_MIME_PART (tny_iterator_get_current (iter));
801 content_type = tny_mime_part_get_content_type (part);
802 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
806 g_object_unref (part);
808 tny_iterator_next (iter);
810 g_object_unref (iter);
811 g_object_unref (parts);
814 if (parent != NULL) {
815 TnyList *parts = TNY_LIST (tny_simple_list_new ());
818 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
819 iter = tny_list_create_iterator (parts);
820 while (!tny_iterator_is_done (iter)) {
822 part = TNY_MIME_PART (tny_iterator_get_current (iter));
823 content_type = tny_mime_part_get_content_type (part);
824 if (content_type && g_str_has_prefix (content_type, "image/")) {
825 priv->images = g_list_prepend (priv->images, part);
827 g_object_unref (part);
829 tny_iterator_next (iter);
831 g_object_unref (iter);
832 g_object_unref (parts);
833 g_object_unref (parent);
838 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
841 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
843 for (node = attachments; node != NULL; node = g_list_next (node)) {
844 TnyMimePart *part = (TnyMimePart *) node->data;
845 const gchar *cid = tny_mime_part_get_content_id (part);
847 char *invalid = NULL;
848 gint int_cid = strtol (cid, &invalid, 10);
849 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
850 priv->last_cid = int_cid;
858 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
861 const gchar *to, *cc, *bcc, *subject;
863 ModestMsgEditWindowPrivate *priv;
865 TnyHeaderFlags priority_flags;
866 TnyFolder *msg_folder;
867 gboolean is_html = FALSE;
869 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
870 g_return_if_fail (TNY_IS_MSG (msg));
872 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
874 header = tny_msg_get_header (msg);
875 to = tny_header_get_to (header);
876 cc = tny_header_get_cc (header);
877 bcc = tny_header_get_bcc (header);
878 subject = tny_header_get_subject (header);
879 priority_flags = tny_header_get_priority (header);
882 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
884 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
885 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
886 gtk_widget_show (priv->cc_caption);
887 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
888 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
889 gtk_widget_hide (priv->cc_caption);
892 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
893 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
894 gtk_widget_show (priv->bcc_caption);
895 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
896 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
897 gtk_widget_hide (priv->bcc_caption);
900 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
901 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
904 update_window_title (self);
906 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
907 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
909 if ((body == NULL)||(body[0] == '\0')) {
911 body = modest_text_utils_convert_to_html ("");
914 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
915 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
918 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
921 /* Add attachments to the view */
922 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
923 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
924 if (priv->attachments == NULL) {
925 gtk_widget_hide (priv->attachments_caption);
927 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
928 gtk_widget_show_all (priv->attachments_caption);
930 get_related_images (self, msg);
931 update_last_cid (self, priv->attachments);
932 update_last_cid (self, priv->images);
933 replace_with_images (self, priv->images);
935 if (preserve_is_rich && !is_html) {
936 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
937 /* Get the default format required from configuration */
938 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
939 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
942 /* Set the default focus depending on having already a To: field or not */
943 if ((!to)||(*to == '\0')) {
944 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
946 gtk_widget_grab_focus (priv->msg_body);
949 /* TODO: lower priority, select in the From: combo to the
950 value that comes from msg <- not sure, should it be
953 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
955 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
956 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
958 modest_msg_edit_window_reset_modified (self);
960 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
961 text_buffer_can_undo (priv->text_buffer, FALSE, self);
962 text_buffer_can_redo (priv->text_buffer, FALSE, self);
965 g_free (priv->msg_uid);
966 priv->msg_uid = NULL;
969 /* we should set a reference to the incoming message if it is a draft */
970 msg_folder = tny_msg_get_folder (msg);
972 if (modest_tny_folder_is_local_folder (msg_folder)) {
973 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
974 if (type == TNY_FOLDER_TYPE_INVALID)
975 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
977 if (type == TNY_FOLDER_TYPE_DRAFTS)
978 priv->draft_msg = g_object_ref(msg);
979 if (type == TNY_FOLDER_TYPE_OUTBOX)
980 priv->outbox_msg = g_object_ref(msg);
981 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
983 g_object_unref (msg_folder);
988 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
991 GList *item_children, *node;
992 GtkWidget *bin_child;
994 bin_child = gtk_bin_get_child (GTK_BIN(item));
996 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
998 for (node = item_children; node != NULL; node = g_list_next (node)) {
999 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1000 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1003 g_list_free (item_children);
1007 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1010 GList *item_children, *node;
1012 box = gtk_bin_get_child (GTK_BIN (item));
1013 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1014 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1016 for (node = item_children; node != NULL; node = g_list_next (node)) {
1017 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1018 if (GTK_IS_TOGGLE_BUTTON (node->data))
1019 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1020 else if (GTK_IS_BUTTON (node->data))
1021 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1023 g_list_free (item_children);
1028 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1030 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1031 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1032 GtkWidget *placeholder;
1033 GtkWidget *tool_item;
1038 GtkWidget *sizes_menu;
1039 GtkWidget *fonts_menu;
1040 GSList *radio_group = NULL;
1041 GSList *node = NULL;
1045 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1046 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1048 /* Font color placeholder */
1049 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1050 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1053 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1054 priv->font_color_button = hildon_color_button_new ();
1055 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1056 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1057 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1058 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1059 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1060 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1061 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1063 G_CALLBACK (modest_msg_edit_window_color_button_change),
1066 /* Font size and face placeholder */
1067 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1068 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1070 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1071 priv->size_tool_button_label = gtk_label_new (NULL);
1072 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1073 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1074 size_text,"</span>", NULL);
1075 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1077 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1078 sizes_menu = gtk_menu_new ();
1079 priv->size_items_group = NULL;
1081 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1082 GtkWidget *size_menu_item;
1084 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1085 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1086 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1087 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1088 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1089 gtk_widget_show (size_menu_item);
1091 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1095 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1096 GtkWidget *item = (GtkWidget *) node->data;
1097 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1101 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1102 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1103 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1104 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1105 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1106 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1107 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1108 priv->font_size_toolitem = tool_item;
1111 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1112 priv->font_tool_button_label = gtk_label_new (NULL);
1113 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1114 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1116 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1117 fonts_menu = gtk_menu_new ();
1118 priv->font_items_group = NULL;
1120 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1121 GtkWidget *font_menu_item;
1122 GtkWidget *child_label;
1124 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1125 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1126 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1127 wp_get_font_name (font_index), "</span>", NULL);
1128 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1131 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1132 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1133 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1134 gtk_widget_show (font_menu_item);
1136 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1139 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1140 GtkWidget *item = (GtkWidget *) node->data;
1141 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1144 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1145 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1146 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1147 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1148 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1149 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1150 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1151 priv->font_face_toolitem = tool_item;
1153 /* Set expand and homogeneous for remaining items */
1154 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1155 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1156 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1157 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1158 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1159 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1160 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1161 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1162 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1164 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1165 will not show the tool items added to the placeholders) */
1166 gtk_widget_show_all (parent_priv->toolbar);
1168 /* Set the no show all *after* showing all items. We do not
1169 want the toolbar to be shown with a show all because it
1170 could go agains the gconf setting regarding showing or not
1171 the toolbar of the editor window */
1172 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1178 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1181 ModestWindowPrivate *parent_priv;
1182 ModestMsgEditWindowPrivate *priv;
1183 GtkActionGroup *action_group;
1184 GError *error = NULL;
1185 GdkPixbuf *window_icon = NULL;
1188 ModestPair *account_pair = NULL;
1189 ModestDimmingRulesGroup *menu_rules_group = NULL;
1190 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1191 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1193 g_return_val_if_fail (msg, NULL);
1194 g_return_val_if_fail (account_name, NULL);
1196 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1198 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1199 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1201 parent_priv->ui_manager = gtk_ui_manager_new();
1202 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1203 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1205 /* Add common actions */
1206 gtk_action_group_add_actions (action_group,
1207 modest_msg_edit_action_entries,
1208 G_N_ELEMENTS (modest_msg_edit_action_entries),
1210 gtk_action_group_add_toggle_actions (action_group,
1211 modest_msg_edit_toggle_action_entries,
1212 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1214 gtk_action_group_add_radio_actions (action_group,
1215 modest_msg_edit_alignment_radio_action_entries,
1216 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1218 G_CALLBACK (modest_ui_actions_on_change_justify),
1220 gtk_action_group_add_radio_actions (action_group,
1221 modest_msg_edit_zoom_action_entries,
1222 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1224 G_CALLBACK (modest_ui_actions_on_change_zoom),
1226 gtk_action_group_add_radio_actions (action_group,
1227 modest_msg_edit_priority_action_entries,
1228 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1230 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1232 gtk_action_group_add_radio_actions (action_group,
1233 modest_msg_edit_file_format_action_entries,
1234 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1235 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1236 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1238 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1239 g_object_unref (action_group);
1241 /* Load the UI definition */
1242 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1244 if (error != NULL) {
1245 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1246 g_clear_error (&error);
1249 /* Add accelerators */
1250 gtk_window_add_accel_group (GTK_WINDOW (obj),
1251 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1253 /* Menubar. Update the state of some toggles */
1254 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1255 conf = modest_runtime_get_conf ();
1256 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1257 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1258 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1259 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1260 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1261 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1262 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1263 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1265 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1268 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1270 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1272 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1274 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1275 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1277 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1278 if (account_pair != NULL)
1279 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1281 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1282 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1283 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1284 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1285 /* Add common dimming rules */
1286 modest_dimming_rules_group_add_rules (menu_rules_group,
1287 modest_msg_edit_window_menu_dimming_entries,
1288 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1289 MODEST_WINDOW (obj));
1290 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1291 modest_msg_edit_window_toolbar_dimming_entries,
1292 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1293 MODEST_WINDOW (obj));
1294 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1295 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1296 MODEST_WINDOW (obj));
1297 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1298 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1299 MODEST_WINDOW (obj));
1300 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1301 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1302 MODEST_WINDOW (obj));
1303 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1304 modest_msg_edit_window_clipboard_dimming_entries,
1305 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1306 MODEST_WINDOW (obj));
1307 /* Insert dimming rules group for this window */
1308 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1309 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1310 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1311 /* Checks the dimming rules */
1312 g_object_unref (menu_rules_group);
1313 g_object_unref (toolbar_rules_group);
1314 g_object_unref (clipboard_rules_group);
1316 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1318 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1320 /* Set window icon */
1321 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1323 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1324 g_object_unref (window_icon);
1327 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1328 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1330 /* Dim at start clipboard actions */
1331 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1332 gtk_action_set_sensitive (action, FALSE);
1333 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1334 gtk_action_set_sensitive (action, FALSE);
1335 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1336 gtk_action_set_sensitive (action, FALSE);
1338 /* set initial state of cc and bcc */
1339 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1340 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1341 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1342 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1343 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1344 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1346 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1347 priv->update_caption_visibility = TRUE;
1349 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1351 /* Track account-removed signal, this window should be closed
1352 in the case we're creating a mail associated to the account
1354 priv->account_removed_handler_id =
1355 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1357 G_CALLBACK(on_account_removed),
1360 return (ModestWindow*) obj;
1364 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1366 GString **string_buffer = (GString **) user_data;
1368 *string_buffer = g_string_append (*string_buffer, buffer);
1374 * @result: A new string which should be freed with g_free().
1377 get_formatted_data (ModestMsgEditWindow *edit_window)
1379 ModestMsgEditWindowPrivate *priv;
1380 GString *string_buffer = g_string_new ("");
1382 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1384 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1386 return g_string_free (string_buffer, FALSE);
1391 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1394 const gchar *account_name;
1395 ModestMsgEditWindowPrivate *priv;
1397 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1399 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1401 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1402 g_return_val_if_fail (account_name, NULL);
1405 /* don't free these (except from) */
1406 data = g_slice_new0 (MsgData);
1407 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1409 data->account_name = g_strdup (account_name);
1410 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1411 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1412 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1413 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1414 if (priv->draft_msg) {
1415 data->draft_msg = g_object_ref (priv->draft_msg);
1416 } else if (priv->outbox_msg) {
1417 data->draft_msg = g_object_ref (priv->outbox_msg);
1419 data->draft_msg = NULL;
1422 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1424 gtk_text_buffer_get_bounds (buf, &b, &e);
1425 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1427 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1428 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1430 data->html_body = NULL;
1432 /* deep-copy the data */
1433 GList *cursor = priv->attachments;
1434 data->attachments = NULL;
1436 if (!(TNY_IS_MIME_PART(cursor->data))) {
1437 g_warning ("strange data in attachment list");
1438 cursor = g_list_next (cursor);
1441 data->attachments = g_list_append (data->attachments,
1442 g_object_ref (cursor->data));
1443 cursor = g_list_next (cursor);
1446 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1447 cursor = priv->images;
1448 data->images = NULL;
1451 if (!(TNY_IS_MIME_PART(cursor->data))) {
1452 g_warning ("strange data in attachment list");
1453 cursor = g_list_next (cursor);
1456 cid = tny_mime_part_get_content_id (cursor->data);
1458 gchar *image_tag_id;
1459 GtkTextTag *image_tag;
1461 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1462 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1463 g_free (image_tag_id);
1465 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1467 ((gtk_text_iter_has_tag (&iter, image_tag))||
1468 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1469 data->images = g_list_append (data->images,
1470 g_object_ref (cursor->data));
1472 cursor = g_list_next (cursor);
1475 data->priority_flags = priv->priority_flags;
1482 unref_gobject (GObject *obj, gpointer data)
1484 if (!G_IS_OBJECT(obj))
1486 g_object_unref (obj);
1490 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1493 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1501 g_free (data->subject);
1502 g_free (data->plain_body);
1503 g_free (data->html_body);
1504 g_free (data->account_name);
1506 if (data->draft_msg != NULL) {
1507 g_object_unref (data->draft_msg);
1508 data->draft_msg = NULL;
1511 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1512 g_list_free (data->attachments);
1513 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1514 g_list_free (data->images);
1516 g_slice_free (MsgData, data);
1520 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1523 ModestMsgEditWindowPrivate *priv = NULL;
1524 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1526 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1528 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1530 return MODEST_MSG_EDIT_FORMAT_HTML;
1532 return MODEST_MSG_EDIT_FORMAT_TEXT;
1536 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1537 ModestMsgEditFormat format)
1539 ModestMsgEditWindowPrivate *priv;
1541 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1542 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1545 case MODEST_MSG_EDIT_FORMAT_HTML:
1546 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1548 case MODEST_MSG_EDIT_FORMAT_TEXT:
1549 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1552 g_return_if_reached ();
1556 ModestMsgEditFormatState *
1557 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1559 ModestMsgEditFormatState *format_state = NULL;
1560 ModestMsgEditWindowPrivate *priv;
1561 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1563 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1564 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1566 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1568 format_state = g_new0 (ModestMsgEditFormatState, 1);
1569 format_state->bold = buffer_format->bold&0x1;
1570 format_state->italics = buffer_format->italic&0x1;
1571 format_state->bullet = buffer_format->bullet&0x1;
1572 format_state->color = buffer_format->color;
1573 format_state->font_size = buffer_format->font_size;
1574 format_state->font_family = wp_get_font_name (buffer_format->font);
1575 format_state->justification = buffer_format->justification;
1576 g_free (buffer_format);
1578 return format_state;
1583 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1584 const ModestMsgEditFormatState *format_state)
1586 ModestMsgEditWindowPrivate *priv;
1587 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1588 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1589 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1590 g_return_if_fail (format_state != NULL);
1592 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1593 gtk_widget_grab_focus (priv->msg_body);
1594 buffer_format->bold = (format_state->bold != FALSE);
1595 buffer_format->italic = (format_state->italics != FALSE);
1596 buffer_format->color = format_state->color;
1597 buffer_format->font_size = format_state->font_size;
1598 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1599 buffer_format->justification = format_state->justification;
1600 buffer_format->bullet = format_state->bullet;
1602 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1604 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1605 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1606 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1607 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1608 buffer_format->cs.font = (buffer_format->font != current_format->font);
1609 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1610 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1612 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1613 if (buffer_format->cs.bold) {
1614 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1616 if (buffer_format->cs.italic) {
1617 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1619 if (buffer_format->cs.color) {
1620 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1622 if (buffer_format->cs.font_size) {
1623 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1625 if (buffer_format->cs.justification) {
1626 switch (buffer_format->justification) {
1627 case GTK_JUSTIFY_LEFT:
1628 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1630 case GTK_JUSTIFY_CENTER:
1631 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1633 case GTK_JUSTIFY_RIGHT:
1634 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1641 if (buffer_format->cs.font) {
1642 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1644 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1645 if (buffer_format->cs.bullet) {
1646 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1648 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1650 g_free (current_format);
1655 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1657 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1659 ModestWindowPrivate *parent_priv;
1660 ModestMsgEditWindowPrivate *priv;
1661 GtkWidget *new_size_menuitem;
1662 GtkWidget *new_font_menuitem;
1664 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1665 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1667 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1668 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1669 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1670 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1672 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1673 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1674 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1677 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1679 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1680 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1682 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1683 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1685 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1686 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1688 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1689 G_CALLBACK (modest_msg_edit_window_color_button_change),
1691 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1692 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1693 G_CALLBACK (modest_msg_edit_window_color_button_change),
1696 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1697 buffer_format->font_size))->data);
1698 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1702 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1703 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1704 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1706 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1707 G_CALLBACK (modest_msg_edit_window_size_change),
1709 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1710 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1711 G_CALLBACK (modest_msg_edit_window_size_change),
1715 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1716 buffer_format->font))->data);
1717 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1721 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1722 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1723 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1725 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1726 G_CALLBACK (modest_msg_edit_window_font_change),
1728 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1729 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1730 G_CALLBACK (modest_msg_edit_window_font_change),
1734 g_free (buffer_format);
1738 #ifdef MODEST_HILDON_VERSION_0
1740 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1743 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1744 ModestMsgEditWindowPrivate *priv;
1745 GtkWidget *dialog = NULL;
1747 GdkColor *new_color = NULL;
1749 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1750 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1752 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1753 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1754 g_free (buffer_format);
1756 response = gtk_dialog_run (GTK_DIALOG (dialog));
1758 case GTK_RESPONSE_OK: {
1759 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1765 gtk_widget_destroy (dialog);
1767 if (new_color != NULL) {
1768 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1769 /* FIXME: free new_color here? */
1774 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1777 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1778 ModestMsgEditWindowPrivate *priv;
1779 GtkWidget *dialog = NULL;
1781 const GdkColor *new_color = NULL;
1784 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1785 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1787 dialog = hildon_color_chooser_new ();
1788 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1789 g_free (buffer_format);
1791 response = gtk_dialog_run (GTK_DIALOG (dialog));
1793 case GTK_RESPONSE_OK: {
1794 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1802 gtk_widget_destroy (dialog);
1803 if (new_color != NULL)
1804 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1805 (gpointer) new_color);
1808 #endif /*!MODEST_HILDON_VERSION_0*/
1811 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1814 ModestMsgEditWindowPrivate *priv;
1815 GtkWidget *dialog = NULL;
1817 GdkColor *old_color = NULL;
1818 const GdkColor *new_color = NULL;
1820 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1821 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1823 #ifdef MODEST_HILDON_VERSION_0
1824 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1825 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1827 dialog = hildon_color_chooser_new ();
1828 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1829 #endif /*MODEST_HILDON_VERSION_9*/
1831 response = gtk_dialog_run (GTK_DIALOG (dialog));
1833 case GTK_RESPONSE_OK: {
1834 #ifdef MODEST_HILDON_VERSION_0
1835 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1838 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1840 #endif /*MODEST_HILDON_VERSION_0*/
1846 gtk_widget_destroy (dialog);
1848 if (new_color != NULL)
1849 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1853 static TnyStream* create_stream_for_uri (const gchar* uri)
1858 TnyStream *result = NULL;
1860 GnomeVFSHandle *handle = NULL;
1861 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1862 if (test == GNOME_VFS_OK) {
1863 /* Create the tinymail stream: */
1864 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1865 result = TNY_STREAM (tny_vfs_stream_new (handle));
1872 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1875 ModestMsgEditWindowPrivate *priv;
1876 GtkWidget *dialog = NULL;
1878 GSList *uris = NULL;
1879 GSList *uri_node = NULL;
1881 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1883 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1884 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1885 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1887 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1889 response = gtk_dialog_run (GTK_DIALOG (dialog));
1891 case GTK_RESPONSE_OK:
1892 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1897 gtk_widget_destroy (dialog);
1899 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1901 GnomeVFSHandle *handle = NULL;
1902 GnomeVFSResult result;
1903 GtkTextIter position;
1904 GtkTextMark *insert_mark;
1906 uri = (const gchar *) uri_node->data;
1907 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1908 if (result == GNOME_VFS_OK) {
1910 GnomeVFSFileInfo info;
1911 gchar *filename, *basename, *escaped_filename;
1912 TnyMimePart *mime_part;
1914 const gchar *mime_type = NULL;
1915 GnomeVFSURI *vfs_uri;
1917 vfs_uri = gnome_vfs_uri_new (uri);
1919 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1920 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1921 g_free (escaped_filename);
1922 gnome_vfs_uri_unref (vfs_uri);
1924 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1925 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1927 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1929 mime_part = tny_platform_factory_new_mime_part
1930 (modest_runtime_get_platform_factory ());
1932 TnyStream *stream = create_stream_for_uri (uri);
1933 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1935 content_id = g_strdup_printf ("%d", priv->last_cid);
1936 tny_mime_part_set_content_id (mime_part, content_id);
1937 g_free (content_id);
1940 basename = g_path_get_basename (filename);
1941 tny_mime_part_set_filename (mime_part, basename);
1944 pixbuf = pixbuf_from_stream (stream, mime_type);
1946 if (pixbuf != NULL) {
1947 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1948 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1949 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1952 priv->images = g_list_prepend (priv->images, mime_part);
1953 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1963 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1966 ModestMsgEditWindowPrivate *priv;
1967 GtkWidget *dialog = NULL;
1969 GSList *uris = NULL;
1972 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1974 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1975 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1976 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1978 response = gtk_dialog_run (GTK_DIALOG (dialog));
1980 case GTK_RESPONSE_OK:
1981 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1986 gtk_widget_destroy (dialog);
1988 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1989 const gchar *uri = (const gchar *) uri_node->data;
1990 modest_msg_edit_window_attach_file_one (window, uri);
1992 g_slist_foreach (uris, (GFunc) g_free, NULL);
1993 g_slist_free (uris);
1997 modest_msg_edit_window_attach_file_one (
1998 ModestMsgEditWindow *window,
2001 g_return_if_fail (window);
2002 g_return_if_fail (uri);
2004 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2007 GnomeVFSHandle *handle = NULL;
2008 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2009 if (result == GNOME_VFS_OK) {
2010 TnyMimePart *mime_part;
2012 const gchar *mime_type = NULL;
2014 gchar *escaped_filename;
2017 GnomeVFSFileInfo info;
2018 GnomeVFSURI *vfs_uri;
2020 vfs_uri = gnome_vfs_uri_new (uri);
2023 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2024 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2025 g_free (escaped_filename);
2026 gnome_vfs_uri_unref (vfs_uri);
2028 if (gnome_vfs_get_file_info (uri,
2030 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2031 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2033 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2034 mime_part = tny_platform_factory_new_mime_part
2035 (modest_runtime_get_platform_factory ());
2036 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2038 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2040 content_id = g_strdup_printf ("%d", priv->last_cid);
2041 tny_mime_part_set_content_id (mime_part, content_id);
2042 g_free (content_id);
2045 basename = g_path_get_basename (filename);
2046 tny_mime_part_set_filename (mime_part, basename);
2049 priv->attachments = g_list_prepend (priv->attachments, mime_part);
2050 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2052 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2053 gtk_widget_show_all (priv->attachments_caption);
2054 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2060 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2063 ModestMsgEditWindowPrivate *priv;
2064 gboolean clean_list = FALSE;
2066 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2067 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2069 if (att_list == NULL) {
2070 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2074 if (att_list == NULL) {
2075 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2077 GtkWidget *confirmation_dialog = NULL;
2078 gboolean dialog_response;
2080 gchar *message = NULL;
2081 gchar *filename = NULL;
2083 if (att_list->next == NULL) {
2084 if (TNY_IS_MSG (att_list->data)) {
2085 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2087 filename = g_strdup (tny_header_get_subject (header));
2088 g_object_unref (header);
2090 if (filename == NULL) {
2091 filename = g_strdup (_("mail_va_no_subject"));
2094 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2097 filename = g_strdup ("");
2099 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2100 att_list->next == NULL), filename);
2102 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2104 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2105 gtk_widget_destroy (confirmation_dialog);
2106 if (!dialog_response) {
2108 g_list_free (att_list);
2111 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2113 for (node = att_list; node != NULL; node = g_list_next (node)) {
2114 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2115 const gchar *att_id;
2116 priv->attachments = g_list_remove (priv->attachments, mime_part);
2118 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2120 if (priv->attachments == NULL)
2121 gtk_widget_hide (priv->attachments_caption);
2122 att_id = tny_mime_part_get_content_id (mime_part);
2124 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2126 g_object_unref (mime_part);
2127 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2132 g_list_free (att_list);
2136 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2139 ModestMsgEditWindowPrivate *priv;
2140 GdkColor *new_color;
2141 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2143 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2144 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2147 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2149 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2151 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2153 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2158 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2161 ModestMsgEditWindowPrivate *priv;
2162 gint new_size_index;
2163 ModestMsgEditWindow *window;
2166 window = MODEST_MSG_EDIT_WINDOW (userdata);
2167 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2168 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2170 if (gtk_check_menu_item_get_active (menu_item)) {
2172 WPTextBufferFormat format;
2174 memset (&format, 0, sizeof (format));
2175 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2177 label = gtk_bin_get_child (GTK_BIN (menu_item));
2179 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2180 format.cs.font_size = TRUE;
2181 format.cs.text_position = TRUE;
2182 format.cs.font = TRUE;
2183 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2184 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2186 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2187 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2188 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2190 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2191 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2192 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2198 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2201 ModestMsgEditWindowPrivate *priv;
2202 gint new_font_index;
2203 ModestMsgEditWindow *window;
2206 window = MODEST_MSG_EDIT_WINDOW (userdata);
2207 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2208 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2210 if (gtk_check_menu_item_get_active (menu_item)) {
2213 label = gtk_bin_get_child (GTK_BIN (menu_item));
2215 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2217 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2218 (gpointer) new_font_index))
2219 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2221 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2222 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2223 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2229 modest_msg_edit_window_set_zoom (ModestWindow *window,
2232 ModestMsgEditWindowPrivate *priv;
2233 ModestWindowPrivate *parent_priv;
2234 GtkRadioAction *zoom_radio_action;
2236 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2238 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2239 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2240 priv->zoom_level = zoom;
2241 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2243 /* Zoom level menu options should be updated with the current zoom level */
2244 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2245 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2246 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2247 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2248 /* FIXME: Not availible before Gtk 2.10 */
2250 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2255 modest_msg_edit_window_get_zoom (ModestWindow *window)
2257 ModestMsgEditWindowPrivate *priv;
2259 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2261 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2262 return priv->zoom_level;
2266 zoom_allowed (ModestMsgEditWindow *window)
2270 focus = gtk_window_get_focus (GTK_WINDOW (window));
2271 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2275 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2277 ModestWindowPrivate *parent_priv;
2278 GtkRadioAction *zoom_radio_action;
2279 GSList *group, *node;
2281 /* First we check if the text view is focused. If not, zooming is not allowed */
2282 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2283 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2287 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2288 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2289 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2291 group = gtk_radio_action_get_group (zoom_radio_action);
2293 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2294 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2298 for (node = group; node != NULL; node = g_slist_next (node)) {
2299 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2300 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2308 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2310 ModestWindowPrivate *parent_priv;
2311 GtkRadioAction *zoom_radio_action;
2312 GSList *group, *node;
2314 /* First we check if the text view is focused. If not, zooming is not allowed */
2315 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2316 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2320 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2321 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2322 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2324 group = gtk_radio_action_get_group (zoom_radio_action);
2326 for (node = group; node != NULL; node = g_slist_next (node)) {
2327 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2328 if (node->next != NULL) {
2329 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2332 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2340 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2342 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2343 ModestWindowPrivate *parent_priv;
2344 ModestWindowMgr *mgr;
2345 gboolean is_fullscreen;
2346 GtkAction *fs_toggle_action;
2349 mgr = modest_runtime_get_window_mgr ();
2350 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2352 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2354 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2355 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2356 if (is_fullscreen != active)
2357 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2365 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2368 ModestMsgEditWindowPrivate *priv = NULL;
2369 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2371 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2372 if (!priv->update_caption_visibility)
2375 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2377 gtk_widget_show (priv->cc_caption);
2379 gtk_widget_hide (priv->cc_caption);
2381 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2385 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2388 ModestMsgEditWindowPrivate *priv = NULL;
2389 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2391 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2392 if (!priv->update_caption_visibility)
2395 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2397 gtk_widget_show (priv->bcc_caption);
2399 gtk_widget_hide (priv->bcc_caption);
2401 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2405 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2406 ModestRecptEditor *editor)
2408 ModestMsgEditWindowPrivate *priv;
2410 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2411 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2412 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2414 if (editor == NULL) {
2415 GtkWidget *view_focus;
2416 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2418 /* This code should be kept in sync with ModestRecptEditor. The
2419 textview inside the recpt editor is the one that really gets the
2420 focus. As it's inside a scrolled window, and this one inside the
2421 hbox recpt editor inherits from, we'll need to go up in the
2422 hierarchy to know if the text view is part of the recpt editor
2423 or if it's a different text entry */
2425 if (gtk_widget_get_parent (view_focus)) {
2426 GtkWidget *first_parent;
2428 first_parent = gtk_widget_get_parent (view_focus);
2429 if (gtk_widget_get_parent (first_parent) &&
2430 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2431 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2436 editor = MODEST_RECPT_EDITOR (priv->to_field);
2440 modest_address_book_select_addresses (editor);
2445 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2447 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2449 modest_msg_edit_window_open_addressbook (window, NULL);
2453 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2454 gboolean show_toolbar)
2456 ModestWindowPrivate *parent_priv;
2457 const gchar *action_name;
2460 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2461 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2463 /* We can not just use the code of
2464 modest_msg_edit_window_setup_toolbar because it has a
2465 mixture of both initialization and creation code. */
2467 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2469 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2471 /* Update also the actions (to update the toggles in the
2472 menus), we have to do it manually because some other window
2473 of the same time could have changed it (remember that the
2474 toolbar fullscreen mode is shared by all the windows of the
2476 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2477 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2479 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2481 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2482 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2488 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2489 TnyHeaderFlags priority_flags)
2491 ModestMsgEditWindowPrivate *priv;
2492 ModestWindowPrivate *parent_priv;
2494 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2496 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2497 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2499 if (priv->priority_flags != priority_flags) {
2500 GtkAction *priority_action = NULL;
2502 priv->priority_flags = priority_flags;
2504 switch (priority_flags) {
2505 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2506 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2507 gtk_widget_show (priv->priority_icon);
2508 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2509 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2511 case TNY_HEADER_FLAG_LOW_PRIORITY:
2512 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2513 gtk_widget_show (priv->priority_icon);
2514 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2515 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2518 gtk_widget_hide (priv->priority_icon);
2519 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2520 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2523 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2524 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2529 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2532 ModestMsgEditWindowPrivate *priv;
2533 ModestWindowPrivate *parent_priv;
2534 gint current_format;
2536 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2538 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2539 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2541 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2542 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2544 if (current_format != file_format) {
2545 switch (file_format) {
2546 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2547 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2548 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2550 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2554 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2555 response = gtk_dialog_run (GTK_DIALOG (dialog));
2556 gtk_widget_destroy (dialog);
2557 if (response == GTK_RESPONSE_OK) {
2558 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2560 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2561 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2566 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2571 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2574 ModestMsgEditWindowPrivate *priv;
2575 WPTextBufferFormat oldfmt, fmt;
2576 gint old_position = 0;
2580 GdkColor *color = NULL;
2581 gboolean bold, bold_set, italic, italic_set;
2582 gboolean underline, underline_set;
2583 gboolean strikethrough, strikethrough_set;
2584 gboolean position_set;
2585 gboolean font_size_set, font_set, color_set;
2588 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2589 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2591 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2593 /* First we get the currently selected font information */
2594 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2595 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2597 switch (oldfmt.text_position) {
2598 case TEXT_POSITION_NORMAL:
2601 case TEXT_POSITION_SUPERSCRIPT:
2609 g_object_set (G_OBJECT (dialog),
2610 "bold", oldfmt.bold != FALSE,
2611 "bold-set", !oldfmt.cs.bold,
2612 "underline", oldfmt.underline != FALSE,
2613 "underline-set", !oldfmt.cs.underline,
2614 "italic", oldfmt.italic != FALSE,
2615 "italic-set", !oldfmt.cs.italic,
2616 "strikethrough", oldfmt.strikethrough != FALSE,
2617 "strikethrough-set", !oldfmt.cs.strikethrough,
2618 "color", &oldfmt.color,
2619 "color-set", !oldfmt.cs.color,
2620 "size", wp_font_size[oldfmt.font_size],
2621 "size-set", !oldfmt.cs.font_size,
2622 "position", old_position,
2623 "position-set", !oldfmt.cs.text_position,
2624 "family", wp_get_font_name (oldfmt.font),
2625 "family-set", !oldfmt.cs.font,
2628 gtk_widget_show_all (dialog);
2629 response = gtk_dialog_run (GTK_DIALOG (dialog));
2630 if (response == GTK_RESPONSE_OK) {
2632 g_object_get( dialog,
2634 "bold-set", &bold_set,
2635 "underline", &underline,
2636 "underline-set", &underline_set,
2638 "italic-set", &italic_set,
2639 "strikethrough", &strikethrough,
2640 "strikethrough-set", &strikethrough_set,
2642 "color-set", &color_set,
2644 "size-set", &font_size_set,
2645 "family", &font_name,
2646 "family-set", &font_set,
2647 "position", &position,
2648 "position-set", &position_set,
2653 if (response == GTK_RESPONSE_OK) {
2654 memset(&fmt, 0, sizeof(fmt));
2660 fmt.italic = italic;
2661 fmt.cs.italic = TRUE;
2663 if (underline_set) {
2664 fmt.underline = underline;
2665 fmt.cs.underline = TRUE;
2667 if (strikethrough_set) {
2668 fmt.strikethrough = strikethrough;
2669 fmt.cs.strikethrough = TRUE;
2674 ? TEXT_POSITION_NORMAL
2675 : ( ( position == 1 )
2676 ? TEXT_POSITION_SUPERSCRIPT
2677 : TEXT_POSITION_SUBSCRIPT );
2678 fmt.cs.text_position = TRUE;
2682 fmt.cs.color = TRUE;
2685 fmt.font = wp_get_font_index(font_name,
2690 if (font_size_set) {
2691 fmt.font_size = wp_get_font_size_index(
2692 font_size, DEFAULT_FONT_SIZE);
2693 fmt.cs.font_size = TRUE;
2695 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2696 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2698 gtk_widget_destroy (dialog);
2700 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2704 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2706 ModestMsgEditWindowPrivate *priv;
2708 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2709 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2711 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2713 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2718 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2720 ModestMsgEditWindowPrivate *priv;
2722 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2723 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2725 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2727 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2732 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2734 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2736 priv->can_undo = can_undo;
2740 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2742 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2744 priv->can_redo = can_redo;
2748 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2750 ModestMsgEditWindowPrivate *priv;
2751 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2752 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2754 return priv->can_undo;
2758 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2760 ModestMsgEditWindowPrivate *priv;
2761 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2762 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2764 return priv->can_redo;
2769 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2772 GtkTextIter match_start, match_end;
2774 if (image_id == NULL)
2777 gtk_text_buffer_get_start_iter (buffer, &iter);
2779 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2780 GSList *tags = gtk_text_iter_get_tags (&match_start);
2782 for (node = tags; node != NULL; node = g_slist_next (node)) {
2783 GtkTextTag *tag = (GtkTextTag *) node->data;
2784 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2785 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2786 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2788 offset = gtk_text_iter_get_offset (&match_start);
2789 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2790 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2794 gtk_text_iter_forward_char (&iter);
2799 message_is_empty (ModestMsgEditWindow *window)
2801 ModestMsgEditWindowPrivate *priv = NULL;
2803 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2804 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2806 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2807 * so we can ignore markup.
2809 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2812 count = gtk_text_buffer_get_char_count (buf);
2818 msg_body_focus (GtkWidget *focus,
2819 GdkEventFocus *event,
2823 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2828 recpt_field_changed (GtkTextBuffer *buffer,
2829 ModestMsgEditWindow *editor)
2831 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2835 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2837 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2841 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2843 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2844 GtkTextBuffer *buffer;
2846 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2847 gtk_text_buffer_set_modified (buffer, FALSE);
2848 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2849 gtk_text_buffer_set_modified (buffer, FALSE);
2850 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2851 gtk_text_buffer_set_modified (buffer, FALSE);
2852 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2856 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2858 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2859 GtkTextBuffer *buffer;
2861 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2862 if (gtk_text_buffer_get_modified (buffer))
2864 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2865 if (gtk_text_buffer_get_modified (buffer))
2867 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2868 if (gtk_text_buffer_get_modified (buffer))
2870 if (gtk_text_buffer_get_modified (priv->text_buffer))
2880 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2882 ModestMsgEditWindowPrivate *priv = NULL;
2884 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2885 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2887 /* check if there's no recipient added */
2888 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2889 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2890 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2891 /* no recipient contents, then select contacts */
2892 modest_msg_edit_window_open_addressbook (window, NULL);
2896 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2897 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2900 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2901 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2904 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2905 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2909 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2910 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2911 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2918 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2919 ModestMsgEditWindow *window)
2921 modest_msg_edit_window_offer_attach_file (window);
2925 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2927 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2929 return priv->clipboard_text;
2933 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2935 ModestMsgEditWindow *window)
2937 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2938 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2940 if (!GTK_WIDGET_VISIBLE (window))
2943 text = gtk_clipboard_wait_for_text (selection_clipboard);
2945 if (priv->clipboard_text != NULL) {
2946 g_free (priv->clipboard_text);
2948 priv->clipboard_text = text;
2950 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2953 subject_field_move_cursor (GtkEntry *entry,
2954 GtkMovementStep step,
2959 if (!GTK_WIDGET_VISIBLE (window))
2962 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2966 update_window_title (ModestMsgEditWindow *window)
2968 ModestMsgEditWindowPrivate *priv = NULL;
2969 const gchar *subject;
2971 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2972 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2973 if (subject == NULL || subject[0] == '\0')
2974 subject = _("mail_va_new_email");
2976 gtk_window_set_title (GTK_WINDOW (window), subject);
2981 subject_field_changed (GtkEditable *editable,
2982 ModestMsgEditWindow *window)
2984 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2985 update_window_title (window);
2986 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2987 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2991 subject_field_insert_text (GtkEditable *editable,
2993 gint new_text_length,
2995 ModestMsgEditWindow *window)
2997 GString *result = g_string_new ("");
2999 gint result_len = 0;
3000 const gchar *entry_text = NULL;
3003 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3004 old_length = g_utf8_strlen (entry_text, -1);
3006 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3007 gunichar c = g_utf8_get_char_validated (current, 8);
3008 /* Invalid unichar, stop */
3014 result = g_string_append_unichar (result, c);
3018 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3019 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3022 /* Prevent endless recursion */
3023 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3024 g_signal_emit_by_name (editable, "insert-text",
3025 (gpointer) result->str, (gpointer) result->len,
3026 (gpointer) position, (gpointer) window);
3027 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3031 if (result_len + old_length > 1000) {
3032 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3033 dgettext("hildon-common-strings",
3034 "ckdg_ib_maximum_characters_reached"));
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 modest_window_mgr_unregister_window (mgr, MODEST_WINDOW (window));
3226 g_object_unref (priv->draft_msg);
3229 if (draft != NULL) {
3230 g_object_ref (draft);
3231 header = tny_msg_get_header (draft);
3232 if (priv->msg_uid) {
3233 g_free (priv->msg_uid);
3234 priv->msg_uid = NULL;
3236 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3237 if (GTK_WIDGET_REALIZED (window))
3238 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3241 priv->draft_msg = draft;
3245 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3246 GtkTextIter *start, GtkTextIter *end,
3249 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3250 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3253 if (tag == NULL+13) return;
3254 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3255 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3256 replace_with_images (window, priv->images);
3261 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3264 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3266 g_return_if_fail (TNY_IS_MIME_PART (part));
3267 priv->attachments = g_list_prepend (priv->attachments, part);
3268 g_object_ref (part);
3269 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3270 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3271 gtk_widget_show_all (priv->attachments_caption);
3272 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3276 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3278 ModestMsgEditWindowPrivate *priv;
3280 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3281 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3283 return priv->msg_uid;
3287 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3288 ModestMsgEditWindowWidgetType widget_type)
3290 ModestMsgEditWindowPrivate *priv;
3292 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3293 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3295 switch (widget_type) {
3296 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3297 return priv->msg_body;
3299 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3300 return priv->to_field;
3302 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3303 return priv->cc_field;
3305 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3306 return priv->bcc_field;
3308 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3309 return priv->subject_field;
3311 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3312 return priv->attachments_view;
3320 remove_tags (WPTextBuffer *buffer)
3322 GtkTextIter start, end;
3324 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3325 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3327 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3331 on_account_removed (TnyAccountStore *account_store,
3332 TnyAccount *account,
3335 /* Do nothing if it's a store account, because we use the
3336 transport to send the messages */
3337 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3338 const gchar *parent_acc = NULL;
3339 const gchar *our_acc = NULL;
3341 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3342 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3343 /* Close this window if I'm showing a message of the removed account */
3344 if (strcmp (parent_acc, our_acc) == 0)
3345 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));