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 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1757 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1758 if (new_color != NULL) {
1759 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1760 (gpointer) new_color);
1763 gtk_widget_destroy (dialog);
1768 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1771 ModestMsgEditWindowPrivate *priv;
1772 GtkWidget *dialog = NULL;
1774 GdkColor *old_color = NULL;
1775 const GdkColor *new_color = NULL;
1777 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1778 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1780 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1781 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1783 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1784 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1785 if (new_color != NULL)
1786 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1788 gtk_widget_destroy (dialog);
1794 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1797 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1798 ModestMsgEditWindowPrivate *priv;
1799 GtkWidget *dialog = NULL;
1801 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1802 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1804 dialog = hildon_color_chooser_new ();
1805 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1806 g_free (buffer_format);
1808 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1810 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1811 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1814 gtk_widget_destroy (dialog);
1819 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1822 ModestMsgEditWindowPrivate *priv;
1823 GtkWidget *dialog = NULL;
1824 GdkColor *old_color = NULL;
1826 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1827 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1829 dialog = hildon_color_chooser_new ();
1830 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1832 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1834 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1835 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1837 gtk_widget_destroy (dialog);
1840 #endif /*!MODEST_HILDON_VERSION_0*/
1844 static TnyStream* create_stream_for_uri (const gchar* uri)
1849 TnyStream *result = NULL;
1851 GnomeVFSHandle *handle = NULL;
1852 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1853 if (test == GNOME_VFS_OK) {
1854 /* Create the tinymail stream: */
1855 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1856 result = TNY_STREAM (tny_vfs_stream_new (handle));
1863 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1866 ModestMsgEditWindowPrivate *priv;
1867 GtkWidget *dialog = NULL;
1869 GSList *uris = NULL;
1870 GSList *uri_node = NULL;
1872 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1874 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1875 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1876 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1878 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1880 response = gtk_dialog_run (GTK_DIALOG (dialog));
1882 case GTK_RESPONSE_OK:
1883 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1888 gtk_widget_destroy (dialog);
1890 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1892 GnomeVFSHandle *handle = NULL;
1893 GnomeVFSResult result;
1894 GtkTextIter position;
1895 GtkTextMark *insert_mark;
1897 uri = (const gchar *) uri_node->data;
1898 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1899 if (result == GNOME_VFS_OK) {
1901 GnomeVFSFileInfo info;
1902 gchar *filename, *basename, *escaped_filename;
1903 TnyMimePart *mime_part;
1905 const gchar *mime_type = NULL;
1906 GnomeVFSURI *vfs_uri;
1908 vfs_uri = gnome_vfs_uri_new (uri);
1910 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1911 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1912 g_free (escaped_filename);
1913 gnome_vfs_uri_unref (vfs_uri);
1915 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1916 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1918 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1920 mime_part = tny_platform_factory_new_mime_part
1921 (modest_runtime_get_platform_factory ());
1923 TnyStream *stream = create_stream_for_uri (uri);
1924 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1926 content_id = g_strdup_printf ("%d", priv->last_cid);
1927 tny_mime_part_set_content_id (mime_part, content_id);
1928 g_free (content_id);
1931 basename = g_path_get_basename (filename);
1932 tny_mime_part_set_filename (mime_part, basename);
1935 pixbuf = pixbuf_from_stream (stream, mime_type);
1937 if (pixbuf != NULL) {
1938 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1939 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1940 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1943 priv->images = g_list_prepend (priv->images, mime_part);
1944 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1954 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1957 ModestMsgEditWindowPrivate *priv;
1958 GtkWidget *dialog = NULL;
1960 GSList *uris = NULL;
1963 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1965 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1966 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1967 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1969 response = gtk_dialog_run (GTK_DIALOG (dialog));
1971 case GTK_RESPONSE_OK:
1972 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1977 gtk_widget_destroy (dialog);
1979 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1980 const gchar *uri = (const gchar *) uri_node->data;
1981 modest_msg_edit_window_attach_file_one (window, uri);
1983 g_slist_foreach (uris, (GFunc) g_free, NULL);
1984 g_slist_free (uris);
1988 modest_msg_edit_window_attach_file_one (
1989 ModestMsgEditWindow *window,
1992 g_return_if_fail (window);
1993 g_return_if_fail (uri);
1995 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1998 GnomeVFSHandle *handle = NULL;
1999 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2000 if (result == GNOME_VFS_OK) {
2001 TnyMimePart *mime_part;
2003 const gchar *mime_type = NULL;
2005 gchar *escaped_filename;
2008 GnomeVFSFileInfo info;
2009 GnomeVFSURI *vfs_uri;
2011 vfs_uri = gnome_vfs_uri_new (uri);
2014 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2015 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2016 g_free (escaped_filename);
2017 gnome_vfs_uri_unref (vfs_uri);
2019 if (gnome_vfs_get_file_info (uri,
2021 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2022 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2024 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2025 mime_part = tny_platform_factory_new_mime_part
2026 (modest_runtime_get_platform_factory ());
2027 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2029 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2031 content_id = g_strdup_printf ("%d", priv->last_cid);
2032 tny_mime_part_set_content_id (mime_part, content_id);
2033 g_free (content_id);
2036 basename = g_path_get_basename (filename);
2037 tny_mime_part_set_filename (mime_part, basename);
2040 priv->attachments = g_list_prepend (priv->attachments, mime_part);
2041 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2043 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2044 gtk_widget_show_all (priv->attachments_caption);
2045 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2051 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2054 ModestMsgEditWindowPrivate *priv;
2055 gboolean clean_list = FALSE;
2057 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2058 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2060 if (att_list == NULL) {
2061 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2065 if (att_list == NULL) {
2066 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2068 GtkWidget *confirmation_dialog = NULL;
2069 gboolean dialog_response;
2071 gchar *message = NULL;
2072 gchar *filename = NULL;
2074 if (att_list->next == NULL) {
2075 if (TNY_IS_MSG (att_list->data)) {
2076 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2078 filename = g_strdup (tny_header_get_subject (header));
2079 g_object_unref (header);
2081 if (filename == NULL) {
2082 filename = g_strdup (_("mail_va_no_subject"));
2085 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2088 filename = g_strdup ("");
2090 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2091 att_list->next == NULL), filename);
2093 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2095 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2096 gtk_widget_destroy (confirmation_dialog);
2097 if (!dialog_response) {
2099 g_list_free (att_list);
2102 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2104 for (node = att_list; node != NULL; node = g_list_next (node)) {
2105 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2106 const gchar *att_id;
2107 priv->attachments = g_list_remove (priv->attachments, mime_part);
2109 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2111 if (priv->attachments == NULL)
2112 gtk_widget_hide (priv->attachments_caption);
2113 att_id = tny_mime_part_get_content_id (mime_part);
2115 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2117 g_object_unref (mime_part);
2118 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2123 g_list_free (att_list);
2127 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2130 ModestMsgEditWindowPrivate *priv;
2131 GdkColor *new_color;
2132 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2134 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2135 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2138 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2140 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2142 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2144 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2149 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2152 ModestMsgEditWindowPrivate *priv;
2153 gint new_size_index;
2154 ModestMsgEditWindow *window;
2157 window = MODEST_MSG_EDIT_WINDOW (userdata);
2158 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2159 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2161 if (gtk_check_menu_item_get_active (menu_item)) {
2163 WPTextBufferFormat format;
2165 memset (&format, 0, sizeof (format));
2166 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2168 label = gtk_bin_get_child (GTK_BIN (menu_item));
2170 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2171 format.cs.font_size = TRUE;
2172 format.cs.text_position = TRUE;
2173 format.cs.font = TRUE;
2174 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2175 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2177 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2178 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2179 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2181 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2182 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2183 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2189 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2192 ModestMsgEditWindowPrivate *priv;
2193 gint new_font_index;
2194 ModestMsgEditWindow *window;
2197 window = MODEST_MSG_EDIT_WINDOW (userdata);
2198 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2199 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2201 if (gtk_check_menu_item_get_active (menu_item)) {
2204 label = gtk_bin_get_child (GTK_BIN (menu_item));
2206 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2208 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2209 (gpointer) new_font_index))
2210 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2212 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2213 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2214 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2220 modest_msg_edit_window_set_zoom (ModestWindow *window,
2223 ModestMsgEditWindowPrivate *priv;
2224 ModestWindowPrivate *parent_priv;
2225 GtkRadioAction *zoom_radio_action;
2227 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2229 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2230 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2231 priv->zoom_level = zoom;
2232 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2234 /* Zoom level menu options should be updated with the current zoom level */
2235 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2236 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2237 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2238 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2239 /* FIXME: Not availible before Gtk 2.10 */
2241 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2246 modest_msg_edit_window_get_zoom (ModestWindow *window)
2248 ModestMsgEditWindowPrivate *priv;
2250 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2252 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2253 return priv->zoom_level;
2257 zoom_allowed (ModestMsgEditWindow *window)
2261 focus = gtk_window_get_focus (GTK_WINDOW (window));
2262 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2266 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2268 ModestWindowPrivate *parent_priv;
2269 GtkRadioAction *zoom_radio_action;
2270 GSList *group, *node;
2272 /* First we check if the text view is focused. If not, zooming is not allowed */
2273 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2274 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2278 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2279 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2280 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2282 group = gtk_radio_action_get_group (zoom_radio_action);
2284 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2285 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2289 for (node = group; node != NULL; node = g_slist_next (node)) {
2290 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2291 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2299 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2301 ModestWindowPrivate *parent_priv;
2302 GtkRadioAction *zoom_radio_action;
2303 GSList *group, *node;
2305 /* First we check if the text view is focused. If not, zooming is not allowed */
2306 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2307 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2311 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2312 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2313 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2315 group = gtk_radio_action_get_group (zoom_radio_action);
2317 for (node = group; node != NULL; node = g_slist_next (node)) {
2318 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2319 if (node->next != NULL) {
2320 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2323 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2331 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2333 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2334 ModestWindowPrivate *parent_priv;
2335 ModestWindowMgr *mgr;
2336 gboolean is_fullscreen;
2337 GtkAction *fs_toggle_action;
2340 mgr = modest_runtime_get_window_mgr ();
2341 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2343 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2345 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2346 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2347 if (is_fullscreen != active)
2348 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2356 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2359 ModestMsgEditWindowPrivate *priv = NULL;
2360 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2362 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2363 if (!priv->update_caption_visibility)
2366 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2368 gtk_widget_show (priv->cc_caption);
2370 gtk_widget_hide (priv->cc_caption);
2372 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2376 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2379 ModestMsgEditWindowPrivate *priv = NULL;
2380 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2382 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2383 if (!priv->update_caption_visibility)
2386 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2388 gtk_widget_show (priv->bcc_caption);
2390 gtk_widget_hide (priv->bcc_caption);
2392 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2396 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2397 ModestRecptEditor *editor)
2399 ModestMsgEditWindowPrivate *priv;
2401 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2402 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2403 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2405 if (editor == NULL) {
2406 GtkWidget *view_focus;
2407 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2409 /* This code should be kept in sync with ModestRecptEditor. The
2410 textview inside the recpt editor is the one that really gets the
2411 focus. As it's inside a scrolled window, and this one inside the
2412 hbox recpt editor inherits from, we'll need to go up in the
2413 hierarchy to know if the text view is part of the recpt editor
2414 or if it's a different text entry */
2416 if (gtk_widget_get_parent (view_focus)) {
2417 GtkWidget *first_parent;
2419 first_parent = gtk_widget_get_parent (view_focus);
2420 if (gtk_widget_get_parent (first_parent) &&
2421 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2422 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2427 editor = MODEST_RECPT_EDITOR (priv->to_field);
2431 modest_address_book_select_addresses (editor);
2436 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2438 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2440 modest_msg_edit_window_open_addressbook (window, NULL);
2444 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2445 gboolean show_toolbar)
2447 ModestWindowPrivate *parent_priv;
2448 const gchar *action_name;
2451 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2452 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2454 /* We can not just use the code of
2455 modest_msg_edit_window_setup_toolbar because it has a
2456 mixture of both initialization and creation code. */
2458 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2460 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2462 /* Update also the actions (to update the toggles in the
2463 menus), we have to do it manually because some other window
2464 of the same time could have changed it (remember that the
2465 toolbar fullscreen mode is shared by all the windows of the
2467 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2468 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2470 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2472 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2473 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2479 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2480 TnyHeaderFlags priority_flags)
2482 ModestMsgEditWindowPrivate *priv;
2483 ModestWindowPrivate *parent_priv;
2485 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2487 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2488 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2490 if (priv->priority_flags != priority_flags) {
2491 GtkAction *priority_action = NULL;
2493 priv->priority_flags = priority_flags;
2495 switch (priority_flags) {
2496 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2497 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2498 gtk_widget_show (priv->priority_icon);
2499 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2500 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2502 case TNY_HEADER_FLAG_LOW_PRIORITY:
2503 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2504 gtk_widget_show (priv->priority_icon);
2505 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2506 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2509 gtk_widget_hide (priv->priority_icon);
2510 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2511 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2514 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2515 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2520 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2523 ModestMsgEditWindowPrivate *priv;
2524 ModestWindowPrivate *parent_priv;
2525 gint current_format;
2527 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2529 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2530 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2532 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2533 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2535 if (current_format != file_format) {
2536 switch (file_format) {
2537 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2538 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2539 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2541 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2545 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2546 response = gtk_dialog_run (GTK_DIALOG (dialog));
2547 gtk_widget_destroy (dialog);
2548 if (response == GTK_RESPONSE_OK) {
2549 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2551 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2552 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2557 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2562 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2565 ModestMsgEditWindowPrivate *priv;
2566 WPTextBufferFormat oldfmt, fmt;
2567 gint old_position = 0;
2571 GdkColor *color = NULL;
2572 gboolean bold, bold_set, italic, italic_set;
2573 gboolean underline, underline_set;
2574 gboolean strikethrough, strikethrough_set;
2575 gboolean position_set;
2576 gboolean font_size_set, font_set, color_set;
2579 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2580 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2582 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2584 /* First we get the currently selected font information */
2585 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2586 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2588 switch (oldfmt.text_position) {
2589 case TEXT_POSITION_NORMAL:
2592 case TEXT_POSITION_SUPERSCRIPT:
2600 g_object_set (G_OBJECT (dialog),
2601 "bold", oldfmt.bold != FALSE,
2602 "bold-set", !oldfmt.cs.bold,
2603 "underline", oldfmt.underline != FALSE,
2604 "underline-set", !oldfmt.cs.underline,
2605 "italic", oldfmt.italic != FALSE,
2606 "italic-set", !oldfmt.cs.italic,
2607 "strikethrough", oldfmt.strikethrough != FALSE,
2608 "strikethrough-set", !oldfmt.cs.strikethrough,
2609 "color", &oldfmt.color,
2610 "color-set", !oldfmt.cs.color,
2611 "size", wp_font_size[oldfmt.font_size],
2612 "size-set", !oldfmt.cs.font_size,
2613 "position", old_position,
2614 "position-set", !oldfmt.cs.text_position,
2615 "family", wp_get_font_name (oldfmt.font),
2616 "family-set", !oldfmt.cs.font,
2619 gtk_widget_show_all (dialog);
2620 response = gtk_dialog_run (GTK_DIALOG (dialog));
2621 if (response == GTK_RESPONSE_OK) {
2623 g_object_get( dialog,
2625 "bold-set", &bold_set,
2626 "underline", &underline,
2627 "underline-set", &underline_set,
2629 "italic-set", &italic_set,
2630 "strikethrough", &strikethrough,
2631 "strikethrough-set", &strikethrough_set,
2633 "color-set", &color_set,
2635 "size-set", &font_size_set,
2636 "family", &font_name,
2637 "family-set", &font_set,
2638 "position", &position,
2639 "position-set", &position_set,
2644 if (response == GTK_RESPONSE_OK) {
2645 memset(&fmt, 0, sizeof(fmt));
2651 fmt.italic = italic;
2652 fmt.cs.italic = TRUE;
2654 if (underline_set) {
2655 fmt.underline = underline;
2656 fmt.cs.underline = TRUE;
2658 if (strikethrough_set) {
2659 fmt.strikethrough = strikethrough;
2660 fmt.cs.strikethrough = TRUE;
2665 ? TEXT_POSITION_NORMAL
2666 : ( ( position == 1 )
2667 ? TEXT_POSITION_SUPERSCRIPT
2668 : TEXT_POSITION_SUBSCRIPT );
2669 fmt.cs.text_position = TRUE;
2673 fmt.cs.color = TRUE;
2676 fmt.font = wp_get_font_index(font_name,
2681 if (font_size_set) {
2682 fmt.font_size = wp_get_font_size_index(
2683 font_size, DEFAULT_FONT_SIZE);
2684 fmt.cs.font_size = TRUE;
2686 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2687 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2689 gtk_widget_destroy (dialog);
2691 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2695 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2697 ModestMsgEditWindowPrivate *priv;
2699 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2700 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2702 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2704 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2709 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2711 ModestMsgEditWindowPrivate *priv;
2713 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2714 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2716 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2718 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2723 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2725 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2727 priv->can_undo = can_undo;
2731 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2733 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2735 priv->can_redo = can_redo;
2739 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2741 ModestMsgEditWindowPrivate *priv;
2742 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2743 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2745 return priv->can_undo;
2749 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2751 ModestMsgEditWindowPrivate *priv;
2752 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2753 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2755 return priv->can_redo;
2760 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2763 GtkTextIter match_start, match_end;
2765 if (image_id == NULL)
2768 gtk_text_buffer_get_start_iter (buffer, &iter);
2770 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2771 GSList *tags = gtk_text_iter_get_tags (&match_start);
2773 for (node = tags; node != NULL; node = g_slist_next (node)) {
2774 GtkTextTag *tag = (GtkTextTag *) node->data;
2775 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2776 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2777 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2779 offset = gtk_text_iter_get_offset (&match_start);
2780 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2781 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2785 gtk_text_iter_forward_char (&iter);
2790 message_is_empty (ModestMsgEditWindow *window)
2792 ModestMsgEditWindowPrivate *priv = NULL;
2794 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2795 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2797 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2798 * so we can ignore markup.
2800 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2803 count = gtk_text_buffer_get_char_count (buf);
2809 msg_body_focus (GtkWidget *focus,
2810 GdkEventFocus *event,
2814 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2819 recpt_field_changed (GtkTextBuffer *buffer,
2820 ModestMsgEditWindow *editor)
2822 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2826 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2828 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2832 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2834 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2835 GtkTextBuffer *buffer;
2837 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2838 gtk_text_buffer_set_modified (buffer, FALSE);
2839 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2840 gtk_text_buffer_set_modified (buffer, FALSE);
2841 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2842 gtk_text_buffer_set_modified (buffer, FALSE);
2843 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2847 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2849 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2850 GtkTextBuffer *buffer;
2852 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2853 if (gtk_text_buffer_get_modified (buffer))
2855 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2856 if (gtk_text_buffer_get_modified (buffer))
2858 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2859 if (gtk_text_buffer_get_modified (buffer))
2861 if (gtk_text_buffer_get_modified (priv->text_buffer))
2871 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2873 ModestMsgEditWindowPrivate *priv = NULL;
2875 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2876 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2878 /* check if there's no recipient added */
2879 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2880 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2881 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2882 /* no recipient contents, then select contacts */
2883 modest_msg_edit_window_open_addressbook (window, NULL);
2887 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2888 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2891 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2892 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2895 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2896 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2900 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2901 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2902 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2909 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2910 ModestMsgEditWindow *window)
2912 modest_msg_edit_window_offer_attach_file (window);
2916 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2918 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2920 return priv->clipboard_text;
2924 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2926 ModestMsgEditWindow *window)
2928 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2929 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2931 if (!GTK_WIDGET_VISIBLE (window))
2934 text = gtk_clipboard_wait_for_text (selection_clipboard);
2936 if (priv->clipboard_text != NULL) {
2937 g_free (priv->clipboard_text);
2939 priv->clipboard_text = text;
2941 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2944 subject_field_move_cursor (GtkEntry *entry,
2945 GtkMovementStep step,
2950 if (!GTK_WIDGET_VISIBLE (window))
2953 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2957 update_window_title (ModestMsgEditWindow *window)
2959 ModestMsgEditWindowPrivate *priv = NULL;
2960 const gchar *subject;
2962 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2963 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2964 if (subject == NULL || subject[0] == '\0')
2965 subject = _("mail_va_new_email");
2967 gtk_window_set_title (GTK_WINDOW (window), subject);
2972 subject_field_changed (GtkEditable *editable,
2973 ModestMsgEditWindow *window)
2975 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2976 update_window_title (window);
2977 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2978 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2982 subject_field_insert_text (GtkEditable *editable,
2984 gint new_text_length,
2986 ModestMsgEditWindow *window)
2988 GString *result = g_string_new ("");
2990 gint result_len = 0;
2991 const gchar *entry_text = NULL;
2994 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2995 old_length = g_utf8_strlen (entry_text, -1);
2997 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2998 gunichar c = g_utf8_get_char_validated (current, 8);
2999 /* Invalid unichar, stop */
3005 result = g_string_append_unichar (result, c);
3009 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3010 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3013 /* Prevent endless recursion */
3014 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3015 g_signal_emit_by_name (editable, "insert-text",
3016 (gpointer) result->str, (gpointer) result->len,
3017 (gpointer) position, (gpointer) window);
3018 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3022 if (result_len + old_length > 1000) {
3023 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3024 dgettext("hildon-common-strings",
3025 "ckdg_ib_maximum_characters_reached"));
3028 g_string_free (result, TRUE);
3032 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3035 ModestMsgEditWindowPrivate *priv = NULL;
3037 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3038 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3040 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3043 gtk_widget_show_all (priv->find_toolbar);
3044 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3046 gtk_widget_hide_all (priv->find_toolbar);
3047 gtk_widget_grab_focus (priv->msg_body);
3053 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3055 GtkTextIter *match_start,
3056 GtkTextIter *match_end)
3058 GtkTextIter end_iter;
3059 gchar *str_casefold;
3062 gchar *range_casefold;
3065 gboolean result = FALSE;
3072 gtk_text_iter_forward_to_end (&end_iter);
3074 str_casefold = g_utf8_casefold (str, -1);
3075 str_chars_n = strlen (str);
3077 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3078 range_casefold = g_utf8_casefold (range_text, -1);
3079 range_chars_n = strlen (range_casefold);
3081 if (range_chars_n < str_chars_n) {
3082 g_free (str_casefold);
3083 g_free (range_text);
3084 g_free (range_casefold);
3088 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3089 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3090 if (!g_utf8_collate (range_subtext, str_casefold)) {
3091 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3093 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3094 match_start, match_end, NULL);
3095 g_free (found_text);
3097 g_free (range_subtext);
3101 g_free (str_casefold);
3102 g_free (range_text);
3103 g_free (range_casefold);
3110 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3111 ModestMsgEditWindow *window)
3113 gchar *current_search = NULL;
3114 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3116 GtkTextIter selection_start, selection_end;
3117 GtkTextIter match_start, match_end;
3118 gboolean continue_search = FALSE;
3120 if (message_is_empty (window)) {
3121 g_free (priv->last_search);
3122 priv->last_search = NULL;
3123 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3127 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3128 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3129 g_free (current_search);
3130 g_free (priv->last_search);
3131 priv->last_search = NULL;
3132 /* Information banner about empty search */
3133 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3137 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3138 continue_search = TRUE;
3140 g_free (priv->last_search);
3141 priv->last_search = g_strdup (current_search);
3144 if (continue_search) {
3145 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3146 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3147 &match_start, &match_end);
3149 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3151 GtkTextIter buffer_start;
3152 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3153 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3154 &match_start, &match_end);
3156 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3159 /* Mark as selected the string found in search */
3161 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3162 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3164 g_free (priv->last_search);
3165 priv->last_search = NULL;
3167 g_free (current_search);
3171 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3172 ModestMsgEditWindow *window)
3174 GtkToggleAction *toggle;
3175 ModestWindowPrivate *parent_priv;
3176 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3178 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3179 gtk_toggle_action_set_active (toggle, FALSE);
3183 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3185 ModestMsgEditWindowPrivate *priv;
3187 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3192 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3195 ModestMsgEditWindowPrivate *priv;
3197 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3203 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3206 ModestMsgEditWindowPrivate *priv;
3207 TnyHeader *header = NULL;
3209 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3210 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3212 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3213 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3215 if (priv->draft_msg != NULL) {
3216 g_object_unref (priv->draft_msg);
3219 if (draft != NULL) {
3220 g_object_ref (draft);
3221 header = tny_msg_get_header (draft);
3222 if (priv->msg_uid) {
3223 g_free (priv->msg_uid);
3224 priv->msg_uid = NULL;
3226 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3227 if (GTK_WIDGET_REALIZED (window))
3228 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3231 priv->draft_msg = draft;
3235 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3236 GtkTextIter *start, GtkTextIter *end,
3239 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3240 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3243 if (tag == NULL+13) return;
3244 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3245 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3246 replace_with_images (window, priv->images);
3251 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3254 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3256 g_return_if_fail (TNY_IS_MIME_PART (part));
3257 priv->attachments = g_list_prepend (priv->attachments, part);
3258 g_object_ref (part);
3259 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3260 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3261 gtk_widget_show_all (priv->attachments_caption);
3262 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3266 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3268 ModestMsgEditWindowPrivate *priv;
3270 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3271 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3273 return priv->msg_uid;
3277 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3278 ModestMsgEditWindowWidgetType widget_type)
3280 ModestMsgEditWindowPrivate *priv;
3282 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3283 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3285 switch (widget_type) {
3286 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3287 return priv->msg_body;
3289 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3290 return priv->to_field;
3292 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3293 return priv->cc_field;
3295 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3296 return priv->bcc_field;
3298 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3299 return priv->subject_field;
3301 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3302 return priv->attachments_view;
3310 remove_tags (WPTextBuffer *buffer)
3312 GtkTextIter start, end;
3314 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3315 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3317 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3321 on_account_removed (TnyAccountStore *account_store,
3322 TnyAccount *account,
3325 /* Do nothing if it's a store account, because we use the
3326 transport to send the messages */
3327 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3328 const gchar *parent_acc = NULL;
3329 const gchar *our_acc = NULL;
3331 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3332 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3333 /* Close this window if I'm showing a message of the removed account */
3334 if (strcmp (parent_acc, our_acc) == 0)
3335 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));