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->from);
1502 g_free (data->subject);
1503 g_free (data->plain_body);
1504 g_free (data->html_body);
1505 g_free (data->account_name);
1507 if (data->draft_msg != NULL) {
1508 g_object_unref (data->draft_msg);
1509 data->draft_msg = NULL;
1512 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1513 g_list_free (data->attachments);
1514 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1515 g_list_free (data->images);
1517 g_slice_free (MsgData, data);
1521 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1524 ModestMsgEditWindowPrivate *priv = NULL;
1525 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1527 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1529 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1531 return MODEST_MSG_EDIT_FORMAT_HTML;
1533 return MODEST_MSG_EDIT_FORMAT_TEXT;
1537 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1538 ModestMsgEditFormat format)
1540 ModestMsgEditWindowPrivate *priv;
1542 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1543 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1546 case MODEST_MSG_EDIT_FORMAT_HTML:
1547 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1549 case MODEST_MSG_EDIT_FORMAT_TEXT:
1550 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1553 g_return_if_reached ();
1557 ModestMsgEditFormatState *
1558 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1560 ModestMsgEditFormatState *format_state = NULL;
1561 ModestMsgEditWindowPrivate *priv;
1562 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1564 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1565 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1567 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1569 format_state = g_new0 (ModestMsgEditFormatState, 1);
1570 format_state->bold = buffer_format->bold&0x1;
1571 format_state->italics = buffer_format->italic&0x1;
1572 format_state->bullet = buffer_format->bullet&0x1;
1573 format_state->color = buffer_format->color;
1574 format_state->font_size = buffer_format->font_size;
1575 format_state->font_family = wp_get_font_name (buffer_format->font);
1576 format_state->justification = buffer_format->justification;
1577 g_free (buffer_format);
1579 return format_state;
1584 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1585 const ModestMsgEditFormatState *format_state)
1587 ModestMsgEditWindowPrivate *priv;
1588 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1589 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1590 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1591 g_return_if_fail (format_state != NULL);
1593 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1594 gtk_widget_grab_focus (priv->msg_body);
1595 buffer_format->bold = (format_state->bold != FALSE);
1596 buffer_format->italic = (format_state->italics != FALSE);
1597 buffer_format->color = format_state->color;
1598 buffer_format->font_size = format_state->font_size;
1599 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1600 buffer_format->justification = format_state->justification;
1601 buffer_format->bullet = format_state->bullet;
1603 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1605 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1606 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1607 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1608 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1609 buffer_format->cs.font = (buffer_format->font != current_format->font);
1610 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1611 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1613 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1614 if (buffer_format->cs.bold) {
1615 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1617 if (buffer_format->cs.italic) {
1618 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1620 if (buffer_format->cs.color) {
1621 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1623 if (buffer_format->cs.font_size) {
1624 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1626 if (buffer_format->cs.justification) {
1627 switch (buffer_format->justification) {
1628 case GTK_JUSTIFY_LEFT:
1629 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1631 case GTK_JUSTIFY_CENTER:
1632 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1634 case GTK_JUSTIFY_RIGHT:
1635 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1642 if (buffer_format->cs.font) {
1643 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1645 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1646 if (buffer_format->cs.bullet) {
1647 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1649 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1651 g_free (current_format);
1656 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1658 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1660 ModestWindowPrivate *parent_priv;
1661 ModestMsgEditWindowPrivate *priv;
1662 GtkWidget *new_size_menuitem;
1663 GtkWidget *new_font_menuitem;
1665 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1666 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1668 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1669 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1670 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1671 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1673 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1674 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1675 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1678 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1680 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1681 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1683 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1684 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1686 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1687 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1689 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1690 G_CALLBACK (modest_msg_edit_window_color_button_change),
1692 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1693 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1694 G_CALLBACK (modest_msg_edit_window_color_button_change),
1697 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1698 buffer_format->font_size))->data);
1699 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1703 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1704 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1705 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1707 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1708 G_CALLBACK (modest_msg_edit_window_size_change),
1710 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1711 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1712 G_CALLBACK (modest_msg_edit_window_size_change),
1716 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1717 buffer_format->font))->data);
1718 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1722 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1723 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1724 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1726 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1727 G_CALLBACK (modest_msg_edit_window_font_change),
1729 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1730 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1731 G_CALLBACK (modest_msg_edit_window_font_change),
1735 g_free (buffer_format);
1739 #ifdef MODEST_HILDON_VERSION_0
1741 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1744 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1745 ModestMsgEditWindowPrivate *priv;
1746 GtkWidget *dialog = NULL;
1748 GdkColor *new_color = NULL;
1750 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1751 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1753 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1754 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1755 g_free (buffer_format);
1757 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1758 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1759 if (new_color != NULL) {
1760 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1761 (gpointer) new_color);
1764 gtk_widget_destroy (dialog);
1769 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1772 ModestMsgEditWindowPrivate *priv;
1773 GtkWidget *dialog = NULL;
1775 GdkColor *old_color = NULL;
1776 const GdkColor *new_color = NULL;
1778 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1779 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1781 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1782 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1784 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1785 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1786 if (new_color != NULL)
1787 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1789 gtk_widget_destroy (dialog);
1795 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1798 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1799 ModestMsgEditWindowPrivate *priv;
1800 GtkWidget *dialog = NULL;
1802 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1803 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1805 dialog = hildon_color_chooser_new ();
1806 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1807 g_free (buffer_format);
1809 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1811 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1812 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1815 gtk_widget_destroy (dialog);
1820 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1823 ModestMsgEditWindowPrivate *priv;
1824 GtkWidget *dialog = NULL;
1825 GdkColor *old_color = NULL;
1827 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1828 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1830 dialog = hildon_color_chooser_new ();
1831 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1833 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1835 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1836 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1838 gtk_widget_destroy (dialog);
1841 #endif /*!MODEST_HILDON_VERSION_0*/
1845 static TnyStream* create_stream_for_uri (const gchar* uri)
1850 TnyStream *result = NULL;
1852 GnomeVFSHandle *handle = NULL;
1853 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1854 if (test == GNOME_VFS_OK) {
1855 /* Create the tinymail stream: */
1856 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1857 result = TNY_STREAM (tny_vfs_stream_new (handle));
1864 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1867 ModestMsgEditWindowPrivate *priv;
1868 GtkWidget *dialog = NULL;
1870 GSList *uris = NULL;
1871 GSList *uri_node = NULL;
1873 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1875 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1876 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1877 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1879 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1881 response = gtk_dialog_run (GTK_DIALOG (dialog));
1883 case GTK_RESPONSE_OK:
1884 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1889 gtk_widget_destroy (dialog);
1891 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1893 GnomeVFSHandle *handle = NULL;
1894 GnomeVFSResult result;
1895 GtkTextIter position;
1896 GtkTextMark *insert_mark;
1898 uri = (const gchar *) uri_node->data;
1899 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1900 if (result == GNOME_VFS_OK) {
1902 GnomeVFSFileInfo info;
1903 gchar *filename, *basename, *escaped_filename;
1904 TnyMimePart *mime_part;
1906 const gchar *mime_type = NULL;
1907 GnomeVFSURI *vfs_uri;
1909 vfs_uri = gnome_vfs_uri_new (uri);
1911 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1912 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1913 g_free (escaped_filename);
1914 gnome_vfs_uri_unref (vfs_uri);
1916 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1917 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1919 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1921 mime_part = tny_platform_factory_new_mime_part
1922 (modest_runtime_get_platform_factory ());
1924 TnyStream *stream = create_stream_for_uri (uri);
1925 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1927 content_id = g_strdup_printf ("%d", priv->last_cid);
1928 tny_mime_part_set_content_id (mime_part, content_id);
1929 g_free (content_id);
1932 basename = g_path_get_basename (filename);
1933 tny_mime_part_set_filename (mime_part, basename);
1936 pixbuf = pixbuf_from_stream (stream, mime_type);
1938 if (pixbuf != NULL) {
1939 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1940 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1941 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1944 priv->images = g_list_prepend (priv->images, mime_part);
1945 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1955 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1958 ModestMsgEditWindowPrivate *priv;
1959 GtkWidget *dialog = NULL;
1961 GSList *uris = NULL;
1964 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1966 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1967 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1968 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1970 response = gtk_dialog_run (GTK_DIALOG (dialog));
1972 case GTK_RESPONSE_OK:
1973 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1978 gtk_widget_destroy (dialog);
1980 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1981 const gchar *uri = (const gchar *) uri_node->data;
1982 modest_msg_edit_window_attach_file_one (window, uri);
1984 g_slist_foreach (uris, (GFunc) g_free, NULL);
1985 g_slist_free (uris);
1989 modest_msg_edit_window_attach_file_one (
1990 ModestMsgEditWindow *window,
1993 g_return_if_fail (window);
1994 g_return_if_fail (uri);
1996 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1999 GnomeVFSHandle *handle = NULL;
2000 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2001 if (result == GNOME_VFS_OK) {
2002 TnyMimePart *mime_part;
2004 const gchar *mime_type = NULL;
2006 gchar *escaped_filename;
2009 GnomeVFSFileInfo info;
2010 GnomeVFSURI *vfs_uri;
2012 vfs_uri = gnome_vfs_uri_new (uri);
2015 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2016 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2017 g_free (escaped_filename);
2018 gnome_vfs_uri_unref (vfs_uri);
2020 if (gnome_vfs_get_file_info (uri,
2022 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2023 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2025 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2026 mime_part = tny_platform_factory_new_mime_part
2027 (modest_runtime_get_platform_factory ());
2028 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2030 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2032 content_id = g_strdup_printf ("%d", priv->last_cid);
2033 tny_mime_part_set_content_id (mime_part, content_id);
2034 g_free (content_id);
2037 basename = g_path_get_basename (filename);
2038 tny_mime_part_set_filename (mime_part, basename);
2041 priv->attachments = g_list_prepend (priv->attachments, mime_part);
2042 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2044 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2045 gtk_widget_show_all (priv->attachments_caption);
2046 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2052 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2055 ModestMsgEditWindowPrivate *priv;
2056 gboolean clean_list = FALSE;
2058 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2059 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2061 if (att_list == NULL) {
2062 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2066 if (att_list == NULL) {
2067 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2069 GtkWidget *confirmation_dialog = NULL;
2070 gboolean dialog_response;
2072 gchar *message = NULL;
2073 gchar *filename = NULL;
2075 if (att_list->next == NULL) {
2076 if (TNY_IS_MSG (att_list->data)) {
2077 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2079 filename = g_strdup (tny_header_get_subject (header));
2080 g_object_unref (header);
2082 if (filename == NULL) {
2083 filename = g_strdup (_("mail_va_no_subject"));
2086 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2089 filename = g_strdup ("");
2091 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2092 att_list->next == NULL), filename);
2094 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2096 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2097 gtk_widget_destroy (confirmation_dialog);
2098 if (!dialog_response) {
2100 g_list_free (att_list);
2103 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2105 for (node = att_list; node != NULL; node = g_list_next (node)) {
2106 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2107 const gchar *att_id;
2108 priv->attachments = g_list_remove (priv->attachments, mime_part);
2110 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2112 if (priv->attachments == NULL)
2113 gtk_widget_hide (priv->attachments_caption);
2114 att_id = tny_mime_part_get_content_id (mime_part);
2116 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2118 g_object_unref (mime_part);
2119 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2124 g_list_free (att_list);
2128 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2131 ModestMsgEditWindowPrivate *priv;
2132 GdkColor *new_color;
2133 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2135 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2136 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2139 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2141 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2143 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2145 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2150 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2153 ModestMsgEditWindowPrivate *priv;
2154 gint new_size_index;
2155 ModestMsgEditWindow *window;
2158 window = MODEST_MSG_EDIT_WINDOW (userdata);
2159 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2160 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2162 if (gtk_check_menu_item_get_active (menu_item)) {
2164 WPTextBufferFormat format;
2166 memset (&format, 0, sizeof (format));
2167 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2169 label = gtk_bin_get_child (GTK_BIN (menu_item));
2171 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2172 format.cs.font_size = TRUE;
2173 format.cs.text_position = TRUE;
2174 format.cs.font = TRUE;
2175 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2176 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2178 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2179 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2180 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2182 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2183 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2184 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2190 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2193 ModestMsgEditWindowPrivate *priv;
2194 gint new_font_index;
2195 ModestMsgEditWindow *window;
2198 window = MODEST_MSG_EDIT_WINDOW (userdata);
2199 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2200 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2202 if (gtk_check_menu_item_get_active (menu_item)) {
2205 label = gtk_bin_get_child (GTK_BIN (menu_item));
2207 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2209 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2210 (gpointer) new_font_index))
2211 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2213 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2214 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2215 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2221 modest_msg_edit_window_set_zoom (ModestWindow *window,
2224 ModestMsgEditWindowPrivate *priv;
2225 ModestWindowPrivate *parent_priv;
2226 GtkRadioAction *zoom_radio_action;
2228 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2231 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2232 priv->zoom_level = zoom;
2233 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2235 /* Zoom level menu options should be updated with the current zoom level */
2236 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2237 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2238 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2239 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2240 /* FIXME: Not availible before Gtk 2.10 */
2242 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2247 modest_msg_edit_window_get_zoom (ModestWindow *window)
2249 ModestMsgEditWindowPrivate *priv;
2251 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2253 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2254 return priv->zoom_level;
2258 zoom_allowed (ModestMsgEditWindow *window)
2262 focus = gtk_window_get_focus (GTK_WINDOW (window));
2263 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2267 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2269 ModestWindowPrivate *parent_priv;
2270 GtkRadioAction *zoom_radio_action;
2271 GSList *group, *node;
2273 /* First we check if the text view is focused. If not, zooming is not allowed */
2274 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2275 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2279 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2280 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2281 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2283 group = gtk_radio_action_get_group (zoom_radio_action);
2285 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2286 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2290 for (node = group; node != NULL; node = g_slist_next (node)) {
2291 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2292 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2300 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2302 ModestWindowPrivate *parent_priv;
2303 GtkRadioAction *zoom_radio_action;
2304 GSList *group, *node;
2306 /* First we check if the text view is focused. If not, zooming is not allowed */
2307 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2308 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2312 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2313 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2314 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2316 group = gtk_radio_action_get_group (zoom_radio_action);
2318 for (node = group; node != NULL; node = g_slist_next (node)) {
2319 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2320 if (node->next != NULL) {
2321 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2324 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2332 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2334 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2335 ModestWindowPrivate *parent_priv;
2336 ModestWindowMgr *mgr;
2337 gboolean is_fullscreen;
2338 GtkAction *fs_toggle_action;
2341 mgr = modest_runtime_get_window_mgr ();
2342 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2344 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2346 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2347 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2348 if (is_fullscreen != active)
2349 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2357 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2360 ModestMsgEditWindowPrivate *priv = NULL;
2361 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2363 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2364 if (!priv->update_caption_visibility)
2367 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2369 gtk_widget_show (priv->cc_caption);
2371 gtk_widget_hide (priv->cc_caption);
2373 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2377 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2380 ModestMsgEditWindowPrivate *priv = NULL;
2381 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2383 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2384 if (!priv->update_caption_visibility)
2387 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2389 gtk_widget_show (priv->bcc_caption);
2391 gtk_widget_hide (priv->bcc_caption);
2393 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2397 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2398 ModestRecptEditor *editor)
2400 ModestMsgEditWindowPrivate *priv;
2402 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2403 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2404 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2406 if (editor == NULL) {
2407 GtkWidget *view_focus;
2408 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2410 /* This code should be kept in sync with ModestRecptEditor. The
2411 textview inside the recpt editor is the one that really gets the
2412 focus. As it's inside a scrolled window, and this one inside the
2413 hbox recpt editor inherits from, we'll need to go up in the
2414 hierarchy to know if the text view is part of the recpt editor
2415 or if it's a different text entry */
2417 if (gtk_widget_get_parent (view_focus)) {
2418 GtkWidget *first_parent;
2420 first_parent = gtk_widget_get_parent (view_focus);
2421 if (gtk_widget_get_parent (first_parent) &&
2422 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2423 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2428 editor = MODEST_RECPT_EDITOR (priv->to_field);
2432 modest_address_book_select_addresses (editor);
2437 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2439 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2441 modest_msg_edit_window_open_addressbook (window, NULL);
2445 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2446 gboolean show_toolbar)
2448 ModestWindowPrivate *parent_priv;
2449 const gchar *action_name;
2452 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2453 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2455 /* We can not just use the code of
2456 modest_msg_edit_window_setup_toolbar because it has a
2457 mixture of both initialization and creation code. */
2459 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2461 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2463 /* Update also the actions (to update the toggles in the
2464 menus), we have to do it manually because some other window
2465 of the same time could have changed it (remember that the
2466 toolbar fullscreen mode is shared by all the windows of the
2468 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2469 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2471 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2473 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2474 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2480 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2481 TnyHeaderFlags priority_flags)
2483 ModestMsgEditWindowPrivate *priv;
2484 ModestWindowPrivate *parent_priv;
2486 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2488 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2489 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2491 if (priv->priority_flags != priority_flags) {
2492 GtkAction *priority_action = NULL;
2494 priv->priority_flags = priority_flags;
2496 switch (priority_flags) {
2497 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2498 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2499 gtk_widget_show (priv->priority_icon);
2500 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2501 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2503 case TNY_HEADER_FLAG_LOW_PRIORITY:
2504 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2505 gtk_widget_show (priv->priority_icon);
2506 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2507 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2510 gtk_widget_hide (priv->priority_icon);
2511 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2512 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2515 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2516 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2521 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2524 ModestMsgEditWindowPrivate *priv;
2525 ModestWindowPrivate *parent_priv;
2526 gint current_format;
2528 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2530 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2531 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2533 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2534 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2536 if (current_format != file_format) {
2537 switch (file_format) {
2538 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2539 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2540 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2542 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2546 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2547 response = gtk_dialog_run (GTK_DIALOG (dialog));
2548 gtk_widget_destroy (dialog);
2549 if (response == GTK_RESPONSE_OK) {
2550 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2552 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2553 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2558 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2563 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2566 ModestMsgEditWindowPrivate *priv;
2567 WPTextBufferFormat oldfmt, fmt;
2568 gint old_position = 0;
2572 GdkColor *color = NULL;
2573 gboolean bold, bold_set, italic, italic_set;
2574 gboolean underline, underline_set;
2575 gboolean strikethrough, strikethrough_set;
2576 gboolean position_set;
2577 gboolean font_size_set, font_set, color_set;
2580 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2581 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2583 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2585 /* First we get the currently selected font information */
2586 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2587 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2589 switch (oldfmt.text_position) {
2590 case TEXT_POSITION_NORMAL:
2593 case TEXT_POSITION_SUPERSCRIPT:
2601 g_object_set (G_OBJECT (dialog),
2602 "bold", oldfmt.bold != FALSE,
2603 "bold-set", !oldfmt.cs.bold,
2604 "underline", oldfmt.underline != FALSE,
2605 "underline-set", !oldfmt.cs.underline,
2606 "italic", oldfmt.italic != FALSE,
2607 "italic-set", !oldfmt.cs.italic,
2608 "strikethrough", oldfmt.strikethrough != FALSE,
2609 "strikethrough-set", !oldfmt.cs.strikethrough,
2610 "color", &oldfmt.color,
2611 "color-set", !oldfmt.cs.color,
2612 "size", wp_font_size[oldfmt.font_size],
2613 "size-set", !oldfmt.cs.font_size,
2614 "position", old_position,
2615 "position-set", !oldfmt.cs.text_position,
2616 "family", wp_get_font_name (oldfmt.font),
2617 "family-set", !oldfmt.cs.font,
2620 gtk_widget_show_all (dialog);
2621 response = gtk_dialog_run (GTK_DIALOG (dialog));
2622 if (response == GTK_RESPONSE_OK) {
2624 g_object_get( dialog,
2626 "bold-set", &bold_set,
2627 "underline", &underline,
2628 "underline-set", &underline_set,
2630 "italic-set", &italic_set,
2631 "strikethrough", &strikethrough,
2632 "strikethrough-set", &strikethrough_set,
2634 "color-set", &color_set,
2636 "size-set", &font_size_set,
2637 "family", &font_name,
2638 "family-set", &font_set,
2639 "position", &position,
2640 "position-set", &position_set,
2645 if (response == GTK_RESPONSE_OK) {
2646 memset(&fmt, 0, sizeof(fmt));
2652 fmt.italic = italic;
2653 fmt.cs.italic = TRUE;
2655 if (underline_set) {
2656 fmt.underline = underline;
2657 fmt.cs.underline = TRUE;
2659 if (strikethrough_set) {
2660 fmt.strikethrough = strikethrough;
2661 fmt.cs.strikethrough = TRUE;
2666 ? TEXT_POSITION_NORMAL
2667 : ( ( position == 1 )
2668 ? TEXT_POSITION_SUPERSCRIPT
2669 : TEXT_POSITION_SUBSCRIPT );
2670 fmt.cs.text_position = TRUE;
2674 fmt.cs.color = TRUE;
2677 fmt.font = wp_get_font_index(font_name,
2682 if (font_size_set) {
2683 fmt.font_size = wp_get_font_size_index(
2684 font_size, DEFAULT_FONT_SIZE);
2685 fmt.cs.font_size = TRUE;
2687 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2688 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2690 gtk_widget_destroy (dialog);
2692 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2696 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2698 ModestMsgEditWindowPrivate *priv;
2700 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2701 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2703 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2705 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2710 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2712 ModestMsgEditWindowPrivate *priv;
2714 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2715 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2717 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2719 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2724 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2726 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2728 priv->can_undo = can_undo;
2732 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2734 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2736 priv->can_redo = can_redo;
2740 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2742 ModestMsgEditWindowPrivate *priv;
2743 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2744 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2746 return priv->can_undo;
2750 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2752 ModestMsgEditWindowPrivate *priv;
2753 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2754 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2756 return priv->can_redo;
2761 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2764 GtkTextIter match_start, match_end;
2766 if (image_id == NULL)
2769 gtk_text_buffer_get_start_iter (buffer, &iter);
2771 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2772 GSList *tags = gtk_text_iter_get_tags (&match_start);
2774 for (node = tags; node != NULL; node = g_slist_next (node)) {
2775 GtkTextTag *tag = (GtkTextTag *) node->data;
2776 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2777 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2778 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2780 offset = gtk_text_iter_get_offset (&match_start);
2781 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2782 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2786 gtk_text_iter_forward_char (&iter);
2791 message_is_empty (ModestMsgEditWindow *window)
2793 ModestMsgEditWindowPrivate *priv = NULL;
2795 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2796 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2798 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2799 * so we can ignore markup.
2801 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2804 count = gtk_text_buffer_get_char_count (buf);
2810 msg_body_focus (GtkWidget *focus,
2811 GdkEventFocus *event,
2815 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2820 recpt_field_changed (GtkTextBuffer *buffer,
2821 ModestMsgEditWindow *editor)
2823 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2827 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2829 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2833 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2835 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2836 GtkTextBuffer *buffer;
2838 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2839 gtk_text_buffer_set_modified (buffer, FALSE);
2840 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2841 gtk_text_buffer_set_modified (buffer, FALSE);
2842 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2843 gtk_text_buffer_set_modified (buffer, FALSE);
2844 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2848 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2850 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2851 GtkTextBuffer *buffer;
2853 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2854 if (gtk_text_buffer_get_modified (buffer))
2856 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2857 if (gtk_text_buffer_get_modified (buffer))
2859 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2860 if (gtk_text_buffer_get_modified (buffer))
2862 if (gtk_text_buffer_get_modified (priv->text_buffer))
2872 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2874 ModestMsgEditWindowPrivate *priv = NULL;
2876 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2877 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2879 /* check if there's no recipient added */
2880 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2881 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2882 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2883 /* no recipient contents, then select contacts */
2884 modest_msg_edit_window_open_addressbook (window, NULL);
2888 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2889 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2892 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2893 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2896 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2897 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2901 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2902 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2903 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2910 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2911 ModestMsgEditWindow *window)
2913 modest_msg_edit_window_offer_attach_file (window);
2917 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2919 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2921 return priv->clipboard_text;
2925 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2927 ModestMsgEditWindow *window)
2929 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2930 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2932 if (!GTK_WIDGET_VISIBLE (window))
2935 text = gtk_clipboard_wait_for_text (selection_clipboard);
2937 if (priv->clipboard_text != NULL) {
2938 g_free (priv->clipboard_text);
2940 priv->clipboard_text = text;
2942 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2945 subject_field_move_cursor (GtkEntry *entry,
2946 GtkMovementStep step,
2951 if (!GTK_WIDGET_VISIBLE (window))
2954 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2958 update_window_title (ModestMsgEditWindow *window)
2960 ModestMsgEditWindowPrivate *priv = NULL;
2961 const gchar *subject;
2963 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2964 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2965 if (subject == NULL || subject[0] == '\0')
2966 subject = _("mail_va_new_email");
2968 gtk_window_set_title (GTK_WINDOW (window), subject);
2973 subject_field_changed (GtkEditable *editable,
2974 ModestMsgEditWindow *window)
2976 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2977 update_window_title (window);
2978 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2979 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2983 subject_field_insert_text (GtkEditable *editable,
2985 gint new_text_length,
2987 ModestMsgEditWindow *window)
2989 GString *result = g_string_new ("");
2991 gint result_len = 0;
2992 const gchar *entry_text = NULL;
2995 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2996 old_length = g_utf8_strlen (entry_text, -1);
2998 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2999 gunichar c = g_utf8_get_char_validated (current, 8);
3000 /* Invalid unichar, stop */
3006 result = g_string_append_unichar (result, c);
3010 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3011 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3014 /* Prevent endless recursion */
3015 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3016 g_signal_emit_by_name (editable, "insert-text",
3017 (gpointer) result->str, (gpointer) result->len,
3018 (gpointer) position, (gpointer) window);
3019 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3023 if (result_len + old_length > 1000) {
3024 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3025 dgettext("hildon-common-strings",
3026 "ckdg_ib_maximum_characters_reached"));
3029 g_string_free (result, TRUE);
3033 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3036 ModestMsgEditWindowPrivate *priv = NULL;
3038 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3039 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3041 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3044 gtk_widget_show_all (priv->find_toolbar);
3045 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3047 gtk_widget_hide_all (priv->find_toolbar);
3048 gtk_widget_grab_focus (priv->msg_body);
3054 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3056 GtkTextIter *match_start,
3057 GtkTextIter *match_end)
3059 GtkTextIter end_iter;
3060 gchar *str_casefold;
3063 gchar *range_casefold;
3066 gboolean result = FALSE;
3073 gtk_text_iter_forward_to_end (&end_iter);
3075 str_casefold = g_utf8_casefold (str, -1);
3076 str_chars_n = strlen (str);
3078 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3079 range_casefold = g_utf8_casefold (range_text, -1);
3080 range_chars_n = strlen (range_casefold);
3082 if (range_chars_n < str_chars_n) {
3083 g_free (str_casefold);
3084 g_free (range_text);
3085 g_free (range_casefold);
3089 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3090 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3091 if (!g_utf8_collate (range_subtext, str_casefold)) {
3092 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3094 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3095 match_start, match_end, NULL);
3096 g_free (found_text);
3098 g_free (range_subtext);
3102 g_free (str_casefold);
3103 g_free (range_text);
3104 g_free (range_casefold);
3111 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3112 ModestMsgEditWindow *window)
3114 gchar *current_search = NULL;
3115 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3117 GtkTextIter selection_start, selection_end;
3118 GtkTextIter match_start, match_end;
3119 gboolean continue_search = FALSE;
3121 if (message_is_empty (window)) {
3122 g_free (priv->last_search);
3123 priv->last_search = NULL;
3124 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3128 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3129 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3130 g_free (current_search);
3131 g_free (priv->last_search);
3132 priv->last_search = NULL;
3133 /* Information banner about empty search */
3134 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3138 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3139 continue_search = TRUE;
3141 g_free (priv->last_search);
3142 priv->last_search = g_strdup (current_search);
3145 if (continue_search) {
3146 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3147 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3148 &match_start, &match_end);
3150 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3152 GtkTextIter buffer_start;
3153 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3154 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3155 &match_start, &match_end);
3157 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3160 /* Mark as selected the string found in search */
3162 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3163 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3165 g_free (priv->last_search);
3166 priv->last_search = NULL;
3168 g_free (current_search);
3172 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3173 ModestMsgEditWindow *window)
3175 GtkToggleAction *toggle;
3176 ModestWindowPrivate *parent_priv;
3177 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3179 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3180 gtk_toggle_action_set_active (toggle, FALSE);
3184 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3186 ModestMsgEditWindowPrivate *priv;
3188 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3193 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3196 ModestMsgEditWindowPrivate *priv;
3198 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3204 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3207 ModestMsgEditWindowPrivate *priv;
3208 TnyHeader *header = NULL;
3210 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3211 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3213 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3214 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3216 if (priv->draft_msg != NULL) {
3217 g_object_unref (priv->draft_msg);
3220 if (draft != NULL) {
3221 g_object_ref (draft);
3222 header = tny_msg_get_header (draft);
3223 if (priv->msg_uid) {
3224 g_free (priv->msg_uid);
3225 priv->msg_uid = NULL;
3227 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3228 if (GTK_WIDGET_REALIZED (window))
3229 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3232 priv->draft_msg = draft;
3236 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3237 GtkTextIter *start, GtkTextIter *end,
3240 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3241 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3244 if (tag == NULL+13) return;
3245 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3246 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3247 replace_with_images (window, priv->images);
3252 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3255 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3257 g_return_if_fail (TNY_IS_MIME_PART (part));
3258 priv->attachments = g_list_prepend (priv->attachments, part);
3259 g_object_ref (part);
3260 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3261 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3262 gtk_widget_show_all (priv->attachments_caption);
3263 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3267 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3269 ModestMsgEditWindowPrivate *priv;
3271 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3272 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3274 return priv->msg_uid;
3278 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3279 ModestMsgEditWindowWidgetType widget_type)
3281 ModestMsgEditWindowPrivate *priv;
3283 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3284 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3286 switch (widget_type) {
3287 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3288 return priv->msg_body;
3290 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3291 return priv->to_field;
3293 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3294 return priv->cc_field;
3296 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3297 return priv->bcc_field;
3299 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3300 return priv->subject_field;
3302 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3303 return priv->attachments_view;
3311 remove_tags (WPTextBuffer *buffer)
3313 GtkTextIter start, end;
3315 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3316 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3318 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3322 on_account_removed (TnyAccountStore *account_store,
3323 TnyAccount *account,
3326 /* Do nothing if it's a store account, because we use the
3327 transport to send the messages */
3328 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3329 const gchar *parent_acc = NULL;
3330 const gchar *our_acc = NULL;
3332 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3333 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3334 /* Close this window if I'm showing a message of the removed account */
3335 if (strcmp (parent_acc, our_acc) == 0)
3336 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));