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-address-book.h"
60 #include "modest-text-utils.h"
61 #include <tny-simple-list.h>
62 #include <wptextview.h>
63 #include <wptextbuffer.h>
64 #include "modest-scroll-area.h"
65 #include "modest-msg-edit-window-ui-dimming.h"
67 #include "modest-hildon-includes.h"
68 #ifdef MODEST_HAVE_HILDON0_WIDGETS
69 #include <hildon-widgets/hildon-color-chooser.h>
71 #include "widgets/modest-msg-edit-window-ui.h"
72 #ifdef MODEST_HAVE_HILDON0_WIDGETS
73 #include <libgnomevfs/gnome-vfs-mime-utils.h>
75 #include <libgnomevfs/gnome-vfs-mime.h>
77 #include "modest-maemo-utils.h"
80 #define DEFAULT_FONT_SIZE 3
81 #define DEFAULT_FONT 2
82 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
83 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
84 #define DEFAULT_MAIN_VBOX_SPACING 6
85 #define SUBJECT_MAX_LENGTH 1000
86 #define IMAGE_MAX_WIDTH 560
87 #define DEFAULT_FONT_SCALE 1.5
89 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
90 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
91 static void modest_msg_edit_window_finalize (GObject *obj);
93 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
94 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
95 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
97 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
98 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
99 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
100 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
101 GtkTextIter *start, GtkTextIter *end,
103 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
104 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
105 static void subject_field_insert_text (GtkEditable *editable,
107 gint new_text_length,
109 ModestMsgEditWindow *window);
110 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
112 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
114 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
116 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
117 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
118 GdkEventWindowState *event,
120 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
121 ModestRecptEditor *editor);
122 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
123 ModestMsgEditWindow *window);
125 /* ModestWindow methods implementation */
126 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
127 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
128 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
129 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
130 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
131 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
132 gboolean show_toolbar);
133 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
135 ModestMsgEditWindow *window);
136 static void subject_field_move_cursor (GtkEntry *entry,
137 GtkMovementStep step,
141 static void update_window_title (ModestMsgEditWindow *window);
144 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
145 ModestMsgEditWindow *window);
146 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
147 ModestMsgEditWindow *window);
148 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
150 GtkTextIter *match_start,
151 GtkTextIter *match_end);
153 static void remove_tags (WPTextBuffer *buffer);
155 static void DEBUG_BUFFER (WPTextBuffer *buffer)
160 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
161 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
162 while (!gtk_text_iter_is_end (&iter)) {
163 GString *output = g_string_new ("");
164 GSList *toggled_tags;
167 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
168 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
169 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
170 GtkTextTag *tag = (GtkTextTag *) node->data;
172 g_object_get (G_OBJECT (tag), "name", &name, NULL);
173 output = g_string_append (output, name);
174 g_string_append (output, " ");
176 output = g_string_append (output, "] OPENED [ ");
177 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
178 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
179 GtkTextTag *tag = (GtkTextTag *) node->data;
181 g_object_get (G_OBJECT (tag), "name", &name, NULL);
182 output = g_string_append (output, name);
183 g_string_append (output, " ");
185 output = g_string_append (output, "]\n");
186 g_message ("%s", output->str);
187 g_string_free (output, TRUE);
188 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
190 g_message ("END BUFFER");
195 /* static gboolean */
196 /* on_key_pressed (GtkWidget *self, */
197 /* GdkEventKey *event, */
198 /* gpointer user_data); */
200 /* list my signals */
207 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
208 struct _ModestMsgEditWindowPrivate {
210 GtkWidget *header_box;
212 ModestPairList *from_field_protos;
213 GtkWidget *from_field;
217 GtkWidget *bcc_field;
218 GtkWidget *subject_field;
219 GtkWidget *attachments_view;
220 GtkWidget *priority_icon;
221 GtkWidget *add_attachment_button;
223 GtkWidget *cc_caption;
224 GtkWidget *bcc_caption;
225 gboolean update_caption_visibility;
226 GtkWidget *attachments_caption;
228 GtkTextBuffer *text_buffer;
230 GtkWidget *font_size_toolitem;
231 GtkWidget *font_face_toolitem;
232 GtkWidget *font_color_button;
233 GSList *font_items_group;
234 GtkWidget *font_tool_button_label;
235 GSList *size_items_group;
236 GtkWidget *size_tool_button_label;
238 GtkWidget *find_toolbar;
242 GtkWidget *scroll_area;
243 gint last_vadj_upper;
249 TnyHeaderFlags priority_flags;
253 gboolean can_undo, can_redo;
254 gulong clipboard_change_handler_id;
255 gulong default_clipboard_change_handler_id;
256 gchar *clipboard_text;
265 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
266 MODEST_TYPE_MSG_EDIT_WINDOW, \
267 ModestMsgEditWindowPrivate))
269 static GtkWindowClass *parent_class = NULL;
271 /* uncomment the following if you have defined any signals */
272 /* static guint signals[LAST_SIGNAL] = {0}; */
275 modest_msg_edit_window_get_type (void)
277 static GType my_type = 0;
279 static const GTypeInfo my_info = {
280 sizeof(ModestMsgEditWindowClass),
281 NULL, /* base init */
282 NULL, /* base finalize */
283 (GClassInitFunc) modest_msg_edit_window_class_init,
284 NULL, /* class finalize */
285 NULL, /* class data */
286 sizeof(ModestMsgEditWindow),
288 (GInstanceInitFunc) modest_msg_edit_window_init,
291 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
292 "ModestMsgEditWindow",
295 wp_text_buffer_library_init ();
301 save_state (ModestWindow *self)
303 modest_widget_memory_save (modest_runtime_get_conf(),
304 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
309 restore_settings (ModestMsgEditWindow *self)
311 modest_widget_memory_restore (modest_runtime_get_conf(),
312 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
317 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
319 GObjectClass *gobject_class;
320 ModestWindowClass *modest_window_class;
321 gobject_class = (GObjectClass*) klass;
322 modest_window_class = (ModestWindowClass*) klass;
324 parent_class = g_type_class_peek_parent (klass);
325 gobject_class->finalize = modest_msg_edit_window_finalize;
327 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
328 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
329 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
330 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
331 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
332 modest_window_class->save_state_func = save_state;
333 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
335 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
339 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
341 ModestMsgEditWindowPrivate *priv;
342 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
344 priv->msg_body = NULL;
345 priv->from_field = NULL;
346 priv->to_field = NULL;
347 priv->cc_field = NULL;
348 priv->bcc_field = NULL;
349 priv->subject_field = NULL;
350 priv->attachments = NULL;
353 priv->zoom_level = 1.0;
355 priv->cc_caption = NULL;
356 priv->bcc_caption = NULL;
357 priv->update_caption_visibility = FALSE;
359 priv->priority_flags = 0;
361 priv->find_toolbar = NULL;
362 priv->last_search = NULL;
364 priv->draft_msg = NULL;
365 priv->outbox_msg = NULL;
366 priv->msg_uid = NULL;
368 priv->can_undo = FALSE;
369 priv->can_redo = FALSE;
370 priv->clipboard_change_handler_id = 0;
371 priv->default_clipboard_change_handler_id = 0;
372 priv->clipboard_text = NULL;
375 priv->last_vadj_upper = 0;
379 /* FIXME: this is a dup from the one in gtk/ */
382 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
384 static ModestPairList*
385 get_transports (void)
387 GSList *transports = NULL;
389 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
390 GSList *accounts = modest_account_mgr_account_names (account_mgr,
391 TRUE /* only enabled accounts. */);
393 GSList *cursor = accounts;
395 gchar *account_name = cursor->data;
396 gchar *from_string = NULL;
398 from_string = modest_account_mgr_get_from_string (account_mgr,
402 if (from_string && account_name) {
403 gchar *name = account_name;
404 ModestPair *pair = modest_pair_new ((gpointer) name,
405 (gpointer) from_string , TRUE);
406 transports = g_slist_prepend (transports, pair);
409 cursor = cursor->next;
411 g_slist_free (accounts); /* only free the accounts, not the elements,
412 * because they are used in the pairlist */
416 void vadj_changed (GtkAdjustment *adj,
417 ModestMsgEditWindow *window)
419 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
421 GdkRectangle rectangle, cursor_rectangle;
422 GtkTextIter position;
426 /* We detect if cursor is visible using the full height, not only the center. This
428 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
429 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
431 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
432 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
434 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
435 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
437 if (gtk_widget_is_focus (priv->msg_body) &&
439 if (priv->last_vadj_upper != adj->upper) {
442 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
443 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
444 insert, 0.1, FALSE, 0.0, 0.0);
447 priv->last_vadj_upper = adj->upper;
452 init_window (ModestMsgEditWindow *obj)
454 GtkWidget *from_caption, *to_caption, *subject_caption;
455 GtkWidget *main_vbox;
456 ModestMsgEditWindowPrivate *priv;
458 GtkSizeGroup *size_group;
460 GtkWidget *subject_box;
461 GtkWidget *attachment_icon;
462 GtkWidget *window_box;
463 #if (GTK_MINOR_VERSION >= 10)
464 GdkAtom deserialize_type;
466 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
468 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
470 /* Note: This ModestPairList* must exist for as long as the combo
471 * that uses it, because the ModestComboBox uses the ID opaquely,
472 * so it can't know how to manage its memory. */
473 priv->from_field_protos = get_transports ();
475 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
477 priv->to_field = modest_recpt_editor_new ();
478 priv->cc_field = modest_recpt_editor_new ();
479 priv->bcc_field = modest_recpt_editor_new ();
480 subject_box = gtk_hbox_new (FALSE, 0);
481 priv->priority_icon = gtk_image_new ();
482 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
483 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
484 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
485 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
486 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
487 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
488 priv->add_attachment_button = gtk_button_new ();
489 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
490 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
491 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
492 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
493 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
494 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
495 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
496 priv->attachments_view = modest_attachments_view_new (NULL);
498 priv->header_box = gtk_vbox_new (FALSE, 0);
500 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
501 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
502 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
503 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
504 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
505 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
506 g_object_unref (size_group);
508 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
509 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
510 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
511 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
512 gtk_size_group_add_widget (size_group, priv->subject_field);
513 gtk_size_group_add_widget (size_group, priv->attachments_view);
514 g_object_unref (size_group);
516 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
517 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
518 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
519 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
520 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
521 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
522 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
525 priv->msg_body = wp_text_view_new ();
526 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
527 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
528 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
529 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
530 #if (GTK_MINOR_VERSION >= 10)
531 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
532 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
534 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
535 deserialize_type, TRUE);
537 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
539 priv->find_toolbar = hildon_find_toolbar_new (NULL);
540 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
542 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
544 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
545 G_CALLBACK (text_buffer_refresh_attributes), obj);
546 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
547 G_CALLBACK (text_buffer_can_undo), obj);
548 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
549 G_CALLBACK (text_buffer_can_redo), obj);
550 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
551 G_CALLBACK (body_changed), obj);
552 g_signal_connect (G_OBJECT (obj), "window-state-event",
553 G_CALLBACK (modest_msg_edit_window_window_state_event),
555 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
556 G_CALLBACK (text_buffer_apply_tag), obj);
557 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
558 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
559 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
560 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
561 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
562 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
564 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
565 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
567 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
568 G_CALLBACK (msg_body_focus), obj);
569 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
570 G_CALLBACK (msg_body_focus), obj);
571 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
572 "changed", G_CALLBACK (recpt_field_changed), obj);
573 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
574 "changed", G_CALLBACK (recpt_field_changed), obj);
575 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
576 "changed", G_CALLBACK (recpt_field_changed), obj);
577 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
578 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
579 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
581 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
582 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
584 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
585 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
586 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
587 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
589 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
591 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
592 frame = gtk_frame_new (NULL);
593 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
595 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
596 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
597 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
599 G_CALLBACK (vadj_changed),
601 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
603 window_box = gtk_vbox_new (FALSE, 0);
604 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
605 gtk_container_add (GTK_CONTAINER(obj), window_box);
606 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
607 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
609 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
610 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
611 priv->default_clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
612 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
617 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
619 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
621 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
622 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
623 priv->clipboard_change_handler_id))
624 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
625 priv->clipboard_change_handler_id);
626 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
627 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
628 priv->default_clipboard_change_handler_id))
629 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
630 priv->default_clipboard_change_handler_id);
634 modest_msg_edit_window_finalize (GObject *obj)
636 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
638 /* Sanity check: shouldn't be needed, the window mgr should
639 call this function before */
640 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
642 if (priv->clipboard_text != NULL) {
643 g_free (priv->clipboard_text);
644 priv->clipboard_text = NULL;
647 if (priv->draft_msg != NULL) {
648 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
649 if (TNY_IS_HEADER (header)) {
650 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
651 modest_window_mgr_unregister_header (mgr, header);
653 g_object_unref (priv->draft_msg);
654 priv->draft_msg = NULL;
656 if (priv->outbox_msg != NULL) {
657 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
658 if (TNY_IS_HEADER (header)) {
659 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
660 modest_window_mgr_unregister_header (mgr, header);
662 g_object_unref (priv->outbox_msg);
663 priv->outbox_msg = NULL;
665 if (priv->msg_uid != NULL) {
666 g_free (priv->msg_uid);
667 priv->msg_uid = NULL;
670 /* This had to stay alive for as long as the combobox that used it: */
671 modest_pair_list_free (priv->from_field_protos);
673 G_OBJECT_CLASS(parent_class)->finalize (obj);
677 menubar_to_menu (GtkUIManager *ui_manager)
679 GtkWidget *main_menu;
683 /* Create new main menu */
684 main_menu = gtk_menu_new();
686 /* Get the menubar from the UI manager */
687 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
689 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
693 menu = GTK_WIDGET (iter->data);
694 gtk_widget_reparent(menu, main_menu);
696 iter = g_list_next (iter);
702 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
704 GdkPixbufLoader *loader;
707 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
712 tny_stream_reset (TNY_STREAM (stream));
713 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
714 unsigned char read_buffer[128];
716 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
717 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
721 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
722 g_object_ref (pixbuf);
723 gdk_pixbuf_loader_close (loader, NULL);
724 g_object_unref (loader);
726 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
727 GdkPixbuf *new_pixbuf;
729 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
730 gdk_pixbuf_get_width (pixbuf);
731 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
732 g_object_unref (pixbuf);
740 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
742 ModestMsgEditWindowPrivate *priv;
745 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
747 for (node = attachments; node != NULL; node = g_list_next (node)) {
748 TnyMimePart *part = (TnyMimePart *) node->data;
749 const gchar *cid = tny_mime_part_get_content_id (part);
750 const gchar *mime_type = tny_mime_part_get_content_type (part);
751 if ((cid != NULL)&&(mime_type != NULL)) {
752 TnyStream *stream = tny_mime_part_get_stream (part);
753 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
754 g_object_unref (stream);
756 if (pixbuf != NULL) {
757 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
758 g_object_unref (pixbuf);
765 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
767 TnyMimePart *parent = NULL;
768 const gchar *content_type = NULL;
769 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
771 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
773 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
774 parent = g_object_ref (msg);
775 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
776 TnyList *parts = TNY_LIST (tny_simple_list_new ());
779 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
780 iter = tny_list_create_iterator (parts);
781 while (!tny_iterator_is_done (iter)) {
783 part = TNY_MIME_PART (tny_iterator_get_current (iter));
784 content_type = tny_mime_part_get_content_type (part);
785 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
789 g_object_unref (part);
791 tny_iterator_next (iter);
793 g_object_unref (iter);
794 g_object_unref (parts);
797 if (parent != NULL) {
798 TnyList *parts = TNY_LIST (tny_simple_list_new ());
801 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
802 iter = tny_list_create_iterator (parts);
803 while (!tny_iterator_is_done (iter)) {
805 part = TNY_MIME_PART (tny_iterator_get_current (iter));
806 content_type = tny_mime_part_get_content_type (part);
807 if (content_type && g_str_has_prefix (content_type, "image/")) {
808 priv->images = g_list_prepend (priv->images, part);
810 g_object_unref (part);
812 tny_iterator_next (iter);
814 g_object_unref (iter);
815 g_object_unref (parts);
816 g_object_unref (parent);
821 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
824 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
826 for (node = attachments; node != NULL; node = g_list_next (node)) {
827 TnyMimePart *part = (TnyMimePart *) node->data;
828 const gchar *cid = tny_mime_part_get_content_id (part);
830 char *invalid = NULL;
831 gint int_cid = strtol (cid, &invalid, 10);
832 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
833 priv->last_cid = int_cid;
841 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
844 const gchar *to, *cc, *bcc, *subject;
846 ModestMsgEditWindowPrivate *priv;
848 TnyHeaderFlags priority_flags;
849 TnyFolder *msg_folder;
850 gboolean is_html = FALSE;
852 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
853 g_return_if_fail (TNY_IS_MSG (msg));
855 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
857 header = tny_msg_get_header (msg);
858 to = tny_header_get_to (header);
859 cc = tny_header_get_cc (header);
860 bcc = tny_header_get_bcc (header);
861 subject = tny_header_get_subject (header);
862 priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
865 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
867 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
868 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
869 gtk_widget_show (priv->cc_caption);
870 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
871 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
872 gtk_widget_hide (priv->cc_caption);
875 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
876 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
877 gtk_widget_show (priv->bcc_caption);
878 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
879 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
880 gtk_widget_hide (priv->bcc_caption);
883 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
884 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
887 update_window_title (self);
889 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
890 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
892 if ((body == NULL)||(body[0] == '\0')) {
894 body = modest_text_utils_convert_to_html ("");
897 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
898 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
901 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
904 /* Add attachments to the view */
905 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
906 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
907 if (priv->attachments == NULL) {
908 gtk_widget_hide (priv->attachments_caption);
910 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
911 gtk_widget_show_all (priv->attachments_caption);
913 get_related_images (self, msg);
914 update_last_cid (self, priv->attachments);
915 update_last_cid (self, priv->images);
916 replace_with_images (self, priv->images);
918 if (preserve_is_rich && !is_html) {
919 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
920 /* Get the default format required from configuration */
921 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
922 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
925 /* Set the default focus depending on having already a To: field or not */
926 if ((!to)||(*to == '\0')) {
927 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
929 gtk_widget_grab_focus (priv->msg_body);
932 /* TODO: lower priority, select in the From: combo to the
933 value that comes from msg <- not sure, should it be
936 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
938 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
939 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
941 modest_msg_edit_window_reset_modified (self);
943 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
944 text_buffer_can_undo (priv->text_buffer, FALSE, self);
945 text_buffer_can_redo (priv->text_buffer, FALSE, self);
948 g_free (priv->msg_uid);
949 priv->msg_uid = NULL;
952 /* we should set a reference to the incoming message if it is a draft */
953 msg_folder = tny_msg_get_folder (msg);
955 if (modest_tny_folder_is_local_folder (msg_folder)) {
956 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
957 if (type == TNY_FOLDER_TYPE_DRAFTS)
958 priv->draft_msg = g_object_ref(msg);
959 if (type == TNY_FOLDER_TYPE_OUTBOX)
960 priv->outbox_msg = g_object_ref(msg);
961 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
963 g_object_unref (msg_folder);
968 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
971 GList *item_children, *node;
972 GtkWidget *bin_child;
974 bin_child = gtk_bin_get_child (GTK_BIN(item));
976 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
978 for (node = item_children; node != NULL; node = g_list_next (node)) {
979 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
980 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
983 g_list_free (item_children);
987 menu_tool_button_dont_expand (GtkMenuToolButton *item)
990 GList *item_children, *node;
992 box = gtk_bin_get_child (GTK_BIN (item));
993 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
994 item_children = gtk_container_get_children (GTK_CONTAINER (box));
996 for (node = item_children; node != NULL; node = g_list_next (node)) {
997 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
998 if (GTK_IS_TOGGLE_BUTTON (node->data))
999 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1000 else if (GTK_IS_BUTTON (node->data))
1001 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1003 g_list_free (item_children);
1008 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1010 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1011 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1012 GtkWidget *placeholder;
1013 GtkWidget *tool_item;
1018 GtkWidget *sizes_menu;
1019 GtkWidget *fonts_menu;
1020 GSList *radio_group = NULL;
1021 GSList *node = NULL;
1025 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1026 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1028 /* Font color placeholder */
1029 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1030 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1033 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1034 priv->font_color_button = hildon_color_button_new ();
1035 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1036 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1037 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1038 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1039 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1040 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1041 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1043 G_CALLBACK (modest_msg_edit_window_color_button_change),
1046 /* Font size and face placeholder */
1047 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1048 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1050 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1051 priv->size_tool_button_label = gtk_label_new (NULL);
1052 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1053 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1054 size_text,"</span>", NULL);
1055 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1057 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1058 sizes_menu = gtk_menu_new ();
1059 priv->size_items_group = NULL;
1061 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1062 GtkWidget *size_menu_item;
1064 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1065 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1066 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1067 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1068 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1069 gtk_widget_show (size_menu_item);
1071 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1075 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1076 GtkWidget *item = (GtkWidget *) node->data;
1077 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1081 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1082 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1083 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1084 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1085 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1086 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1087 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1088 priv->font_size_toolitem = tool_item;
1091 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1092 priv->font_tool_button_label = gtk_label_new (NULL);
1093 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1094 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1096 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1097 fonts_menu = gtk_menu_new ();
1098 priv->font_items_group = NULL;
1100 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1101 GtkWidget *font_menu_item;
1102 GtkWidget *child_label;
1104 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1105 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1106 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1107 wp_get_font_name (font_index), "</span>", NULL);
1108 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1111 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1112 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1113 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1114 gtk_widget_show (font_menu_item);
1116 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1119 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1120 GtkWidget *item = (GtkWidget *) node->data;
1121 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1124 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1125 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1126 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1127 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1128 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1129 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1130 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1131 priv->font_face_toolitem = tool_item;
1133 /* Set expand and homogeneous for remaining items */
1134 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1135 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1136 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1137 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1138 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1139 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1140 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1141 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1142 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1144 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1145 will not show the tool items added to the placeholders) */
1146 gtk_widget_show_all (parent_priv->toolbar);
1148 /* Set the no show all *after* showing all items. We do not
1149 want the toolbar to be shown with a show all because it
1150 could go agains the gconf setting regarding showing or not
1151 the toolbar of the editor window */
1152 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1158 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1161 ModestWindowPrivate *parent_priv;
1162 ModestMsgEditWindowPrivate *priv;
1163 GtkActionGroup *action_group;
1164 GError *error = NULL;
1165 GdkPixbuf *window_icon = NULL;
1168 ModestPair *account_pair = NULL;
1169 ModestDimmingRulesGroup *menu_rules_group = NULL;
1170 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1171 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1173 g_return_val_if_fail (msg, NULL);
1174 g_return_val_if_fail (account_name, NULL);
1176 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1178 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1179 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1181 parent_priv->ui_manager = gtk_ui_manager_new();
1182 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1183 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1185 /* Add common actions */
1186 gtk_action_group_add_actions (action_group,
1187 modest_msg_edit_action_entries,
1188 G_N_ELEMENTS (modest_msg_edit_action_entries),
1190 gtk_action_group_add_toggle_actions (action_group,
1191 modest_msg_edit_toggle_action_entries,
1192 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1194 gtk_action_group_add_radio_actions (action_group,
1195 modest_msg_edit_alignment_radio_action_entries,
1196 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1198 G_CALLBACK (modest_ui_actions_on_change_justify),
1200 gtk_action_group_add_radio_actions (action_group,
1201 modest_msg_edit_zoom_action_entries,
1202 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1204 G_CALLBACK (modest_ui_actions_on_change_zoom),
1206 gtk_action_group_add_radio_actions (action_group,
1207 modest_msg_edit_priority_action_entries,
1208 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1210 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1212 gtk_action_group_add_radio_actions (action_group,
1213 modest_msg_edit_file_format_action_entries,
1214 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1215 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1216 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1218 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1219 g_object_unref (action_group);
1221 /* Load the UI definition */
1222 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1224 if (error != NULL) {
1225 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1226 g_clear_error (&error);
1229 /* Add accelerators */
1230 gtk_window_add_accel_group (GTK_WINDOW (obj),
1231 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1233 /* Menubar. Update the state of some toggles */
1234 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1235 conf = modest_runtime_get_conf ();
1236 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1237 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1238 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1239 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1240 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1241 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1242 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1243 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1245 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1248 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1250 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1252 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1254 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1255 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1257 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1258 if (account_pair != NULL)
1259 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1261 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1262 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1263 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1264 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1265 /* Add common dimming rules */
1266 modest_dimming_rules_group_add_rules (menu_rules_group,
1267 modest_msg_edit_window_menu_dimming_entries,
1268 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1269 MODEST_WINDOW (obj));
1270 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1271 modest_msg_edit_window_toolbar_dimming_entries,
1272 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1273 MODEST_WINDOW (obj));
1274 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1275 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1276 MODEST_WINDOW (obj));
1277 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1278 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1279 MODEST_WINDOW (obj));
1280 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1281 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1282 MODEST_WINDOW (obj));
1283 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1284 modest_msg_edit_window_clipboard_dimming_entries,
1285 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1286 MODEST_WINDOW (obj));
1287 /* Insert dimming rules group for this window */
1288 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1289 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1290 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1291 /* Checks the dimming rules */
1292 g_object_unref (menu_rules_group);
1293 g_object_unref (toolbar_rules_group);
1294 g_object_unref (clipboard_rules_group);
1296 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1298 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1300 /* Set window icon */
1301 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1303 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1304 g_object_unref (window_icon);
1307 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1308 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1310 /* Dim at start clipboard actions */
1311 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1312 gtk_action_set_sensitive (action, FALSE);
1313 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1314 gtk_action_set_sensitive (action, FALSE);
1315 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1316 gtk_action_set_sensitive (action, FALSE);
1318 /* set initial state of cc and bcc */
1319 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1320 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1321 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1322 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1323 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1324 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1326 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1327 priv->update_caption_visibility = TRUE;
1329 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1331 return (ModestWindow*) obj;
1335 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1337 GString **string_buffer = (GString **) user_data;
1339 *string_buffer = g_string_append (*string_buffer, buffer);
1345 * @result: A new string which should be freed with g_free().
1348 get_formatted_data (ModestMsgEditWindow *edit_window)
1350 ModestMsgEditWindowPrivate *priv;
1351 GString *string_buffer = g_string_new ("");
1353 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1355 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1357 return g_string_free (string_buffer, FALSE);
1362 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1365 const gchar *account_name;
1366 ModestMsgEditWindowPrivate *priv;
1368 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1370 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1372 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1373 g_return_val_if_fail (account_name, NULL);
1376 /* don't free these (except from) */
1377 data = g_slice_new0 (MsgData);
1378 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1380 data->account_name = g_strdup (account_name);
1381 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1382 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1383 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1384 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1385 if (priv->draft_msg) {
1386 data->draft_msg = g_object_ref (priv->draft_msg);
1387 } else if (priv->outbox_msg) {
1388 data->draft_msg = g_object_ref (priv->outbox_msg);
1390 data->draft_msg = NULL;
1393 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1395 gtk_text_buffer_get_bounds (buf, &b, &e);
1396 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1398 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1399 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1401 data->html_body = NULL;
1403 /* deep-copy the data */
1404 GList *cursor = priv->attachments;
1405 data->attachments = NULL;
1407 if (!(TNY_IS_MIME_PART(cursor->data))) {
1408 g_warning ("strange data in attachment list");
1409 cursor = g_list_next (cursor);
1412 data->attachments = g_list_append (data->attachments,
1413 g_object_ref (cursor->data));
1414 cursor = g_list_next (cursor);
1417 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1418 cursor = priv->images;
1419 data->images = NULL;
1422 if (!(TNY_IS_MIME_PART(cursor->data))) {
1423 g_warning ("strange data in attachment list");
1424 cursor = g_list_next (cursor);
1427 cid = tny_mime_part_get_content_id (cursor->data);
1429 gchar *image_tag_id;
1430 GtkTextTag *image_tag;
1432 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1433 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1434 g_free (image_tag_id);
1436 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1438 ((gtk_text_iter_has_tag (&iter, image_tag))||
1439 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1440 data->images = g_list_append (data->images,
1441 g_object_ref (cursor->data));
1443 cursor = g_list_next (cursor);
1446 data->priority_flags = priv->priority_flags;
1453 unref_gobject (GObject *obj, gpointer data)
1455 if (!G_IS_OBJECT(obj))
1457 g_object_unref (obj);
1461 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1464 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1472 g_free (data->subject);
1473 g_free (data->plain_body);
1474 g_free (data->html_body);
1475 g_free (data->account_name);
1477 if (data->draft_msg != NULL) {
1478 g_object_unref (data->draft_msg);
1479 data->draft_msg = NULL;
1482 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1483 g_list_free (data->attachments);
1484 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1485 g_list_free (data->images);
1487 g_slice_free (MsgData, data);
1491 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1494 ModestMsgEditWindowPrivate *priv = NULL;
1495 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1497 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1499 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1501 return MODEST_MSG_EDIT_FORMAT_HTML;
1503 return MODEST_MSG_EDIT_FORMAT_TEXT;
1507 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1508 ModestMsgEditFormat format)
1510 ModestMsgEditWindowPrivate *priv;
1512 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1513 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1516 case MODEST_MSG_EDIT_FORMAT_HTML:
1517 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1519 case MODEST_MSG_EDIT_FORMAT_TEXT:
1520 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1523 g_return_if_reached ();
1527 ModestMsgEditFormatState *
1528 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1530 ModestMsgEditFormatState *format_state = NULL;
1531 ModestMsgEditWindowPrivate *priv;
1532 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1534 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1535 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1537 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1539 format_state = g_new0 (ModestMsgEditFormatState, 1);
1540 format_state->bold = buffer_format->bold&0x1;
1541 format_state->italics = buffer_format->italic&0x1;
1542 format_state->bullet = buffer_format->bullet&0x1;
1543 format_state->color = buffer_format->color;
1544 format_state->font_size = buffer_format->font_size;
1545 format_state->font_family = wp_get_font_name (buffer_format->font);
1546 format_state->justification = buffer_format->justification;
1547 g_free (buffer_format);
1549 return format_state;
1554 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1555 const ModestMsgEditFormatState *format_state)
1557 ModestMsgEditWindowPrivate *priv;
1558 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1559 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1560 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1561 g_return_if_fail (format_state != NULL);
1563 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1564 gtk_widget_grab_focus (priv->msg_body);
1565 buffer_format->bold = (format_state->bold != FALSE);
1566 buffer_format->italic = (format_state->italics != FALSE);
1567 buffer_format->color = format_state->color;
1568 buffer_format->font_size = format_state->font_size;
1569 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1570 buffer_format->justification = format_state->justification;
1571 buffer_format->bullet = format_state->bullet;
1573 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1575 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1576 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1577 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1578 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1579 buffer_format->cs.font = (buffer_format->font != current_format->font);
1580 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1581 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1583 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1584 if (buffer_format->cs.bold) {
1585 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1587 if (buffer_format->cs.italic) {
1588 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1590 if (buffer_format->cs.color) {
1591 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1593 if (buffer_format->cs.font_size) {
1594 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1596 if (buffer_format->cs.justification) {
1597 switch (buffer_format->justification) {
1598 case GTK_JUSTIFY_LEFT:
1599 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1601 case GTK_JUSTIFY_CENTER:
1602 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1604 case GTK_JUSTIFY_RIGHT:
1605 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1612 if (buffer_format->cs.font) {
1613 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1615 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1616 if (buffer_format->cs.bullet) {
1617 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1619 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1621 g_free (current_format);
1626 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1628 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1630 ModestWindowPrivate *parent_priv;
1631 ModestMsgEditWindowPrivate *priv;
1632 GtkWidget *new_size_menuitem;
1633 GtkWidget *new_font_menuitem;
1635 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1636 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1638 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1639 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1640 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1641 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1643 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1644 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1645 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1648 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1650 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1651 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1653 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1654 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1656 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1657 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1659 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1660 G_CALLBACK (modest_msg_edit_window_color_button_change),
1662 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1663 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1664 G_CALLBACK (modest_msg_edit_window_color_button_change),
1667 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1668 buffer_format->font_size))->data);
1669 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1673 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1674 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1675 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1677 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1678 G_CALLBACK (modest_msg_edit_window_size_change),
1680 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1681 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1682 G_CALLBACK (modest_msg_edit_window_size_change),
1686 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1687 buffer_format->font))->data);
1688 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1692 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1693 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1694 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1696 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1697 G_CALLBACK (modest_msg_edit_window_font_change),
1699 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1700 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1701 G_CALLBACK (modest_msg_edit_window_font_change),
1705 g_free (buffer_format);
1711 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1714 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1715 ModestMsgEditWindowPrivate *priv;
1716 GtkWidget *dialog = NULL;
1718 const GdkColor *new_color = NULL;
1720 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1721 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1723 #ifdef MODEST_HILDON_VERSION_0
1724 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1725 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1727 dialog = hildon_color_chooser_new ();
1728 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1729 #endif /*MODEST_HILDON_VERSION_0*/
1730 g_free (buffer_format);
1732 response = gtk_dialog_run (GTK_DIALOG (dialog));
1734 case GTK_RESPONSE_OK: {
1735 #ifdef MODEST_HILDON_VERSION_0
1736 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1739 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1741 #endif /*MODEST_HILDON_VERSION_0*/
1748 gtk_widget_destroy (dialog);
1750 if (new_color != NULL)
1751 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1756 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1759 ModestMsgEditWindowPrivate *priv;
1760 GtkWidget *dialog = NULL;
1762 GdkColor *old_color = NULL;
1763 const GdkColor *new_color = NULL;
1765 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1766 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1768 #ifdef MODEST_HILDON_VERSION_0
1769 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1770 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1772 dialog = hildon_color_chooser_new ();
1773 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1774 #endif /*MODEST_HILDON_VERSION_9*/
1776 response = gtk_dialog_run (GTK_DIALOG (dialog));
1778 case GTK_RESPONSE_OK: {
1779 #ifdef MODEST_HILDON_VERSION_0
1780 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1783 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1785 #endif /*MODEST_HILDON_VERSION_0*/
1791 gtk_widget_destroy (dialog);
1793 if (new_color != NULL)
1794 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1798 static TnyStream* create_stream_for_uri (const gchar* uri)
1803 TnyStream *result = NULL;
1805 GnomeVFSHandle *handle = NULL;
1806 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1807 if (test == GNOME_VFS_OK) {
1808 /* Create the tinymail stream: */
1809 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1810 result = TNY_STREAM (tny_vfs_stream_new (handle));
1817 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1820 ModestMsgEditWindowPrivate *priv;
1821 GtkWidget *dialog = NULL;
1823 GSList *uris = NULL;
1824 GSList *uri_node = NULL;
1826 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1828 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1829 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1830 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1832 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1834 response = gtk_dialog_run (GTK_DIALOG (dialog));
1836 case GTK_RESPONSE_OK:
1837 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1842 gtk_widget_destroy (dialog);
1844 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1846 GnomeVFSHandle *handle = NULL;
1847 GnomeVFSResult result;
1848 GtkTextIter position;
1849 GtkTextMark *insert_mark;
1851 uri = (const gchar *) uri_node->data;
1852 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1853 if (result == GNOME_VFS_OK) {
1855 GnomeVFSFileInfo info;
1856 gchar *filename, *basename, *escaped_filename;
1857 TnyMimePart *mime_part;
1859 const gchar *mime_type = NULL;
1860 GnomeVFSURI *vfs_uri;
1862 vfs_uri = gnome_vfs_uri_new (uri);
1864 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1865 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1866 g_free (escaped_filename);
1867 gnome_vfs_uri_unref (vfs_uri);
1869 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1870 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1872 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1874 mime_part = tny_platform_factory_new_mime_part
1875 (modest_runtime_get_platform_factory ());
1877 TnyStream *stream = create_stream_for_uri (uri);
1878 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1880 content_id = g_strdup_printf ("%d", priv->last_cid);
1881 tny_mime_part_set_content_id (mime_part, content_id);
1882 g_free (content_id);
1885 basename = g_path_get_basename (filename);
1886 tny_mime_part_set_filename (mime_part, basename);
1889 pixbuf = pixbuf_from_stream (stream, mime_type);
1891 if (pixbuf != NULL) {
1892 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1893 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1894 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1897 priv->images = g_list_prepend (priv->images, mime_part);
1898 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1908 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1911 ModestMsgEditWindowPrivate *priv;
1912 GtkWidget *dialog = NULL;
1914 GSList *uris = NULL;
1917 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1919 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1920 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1921 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1923 response = gtk_dialog_run (GTK_DIALOG (dialog));
1925 case GTK_RESPONSE_OK:
1926 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1931 gtk_widget_destroy (dialog);
1933 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1934 const gchar *uri = (const gchar *) uri_node->data;
1935 modest_msg_edit_window_attach_file_one (window, uri);
1937 g_slist_foreach (uris, (GFunc) g_free, NULL);
1938 g_slist_free (uris);
1942 modest_msg_edit_window_attach_file_one (
1943 ModestMsgEditWindow *window,
1946 g_return_if_fail (window);
1947 g_return_if_fail (uri);
1949 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1952 GnomeVFSHandle *handle = NULL;
1953 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1954 if (result == GNOME_VFS_OK) {
1955 TnyMimePart *mime_part;
1957 const gchar *mime_type = NULL;
1959 gchar *escaped_filename;
1962 GnomeVFSFileInfo info;
1963 GnomeVFSURI *vfs_uri;
1965 vfs_uri = gnome_vfs_uri_new (uri);
1968 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1969 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1970 g_free (escaped_filename);
1971 gnome_vfs_uri_unref (vfs_uri);
1973 if (gnome_vfs_get_file_info (uri,
1975 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1976 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1978 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1979 mime_part = tny_platform_factory_new_mime_part
1980 (modest_runtime_get_platform_factory ());
1981 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1983 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1985 content_id = g_strdup_printf ("%d", priv->last_cid);
1986 tny_mime_part_set_content_id (mime_part, content_id);
1987 g_free (content_id);
1990 basename = g_path_get_basename (filename);
1991 tny_mime_part_set_filename (mime_part, basename);
1994 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1995 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1997 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1998 gtk_widget_show_all (priv->attachments_caption);
1999 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2005 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2008 ModestMsgEditWindowPrivate *priv;
2009 gboolean clean_list = FALSE;
2011 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2012 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2014 if (att_list == NULL) {
2015 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2019 if (att_list == NULL) {
2020 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2022 GtkWidget *confirmation_dialog = NULL;
2023 gboolean dialog_response;
2025 gchar *message = NULL;
2026 const gchar *filename = NULL;
2028 if (att_list->next == NULL) {
2029 filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
2033 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2034 att_list->next == NULL), filename);
2035 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2037 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2038 gtk_widget_destroy (confirmation_dialog);
2039 if (!dialog_response) {
2041 g_list_free (att_list);
2044 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2046 for (node = att_list; node != NULL; node = g_list_next (node)) {
2047 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2048 const gchar *att_id;
2049 priv->attachments = g_list_remove (priv->attachments, mime_part);
2051 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2053 if (priv->attachments == NULL)
2054 gtk_widget_hide (priv->attachments_caption);
2055 att_id = tny_mime_part_get_content_id (mime_part);
2057 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2059 g_object_unref (mime_part);
2060 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2065 g_list_free (att_list);
2069 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2072 ModestMsgEditWindowPrivate *priv;
2073 GdkColor *new_color;
2074 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2076 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2077 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2080 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2082 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2084 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2086 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2091 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2094 ModestMsgEditWindowPrivate *priv;
2095 gint new_size_index;
2096 ModestMsgEditWindow *window;
2099 window = MODEST_MSG_EDIT_WINDOW (userdata);
2100 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2101 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2103 if (gtk_check_menu_item_get_active (menu_item)) {
2105 WPTextBufferFormat format;
2107 memset (&format, 0, sizeof (format));
2108 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2110 label = gtk_bin_get_child (GTK_BIN (menu_item));
2112 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2113 format.cs.font_size = TRUE;
2114 format.cs.text_position = TRUE;
2115 format.cs.font = TRUE;
2116 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2117 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2119 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2120 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2121 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2123 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2124 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2125 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2131 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2134 ModestMsgEditWindowPrivate *priv;
2135 gint new_font_index;
2136 ModestMsgEditWindow *window;
2139 window = MODEST_MSG_EDIT_WINDOW (userdata);
2140 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2141 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2143 if (gtk_check_menu_item_get_active (menu_item)) {
2146 label = gtk_bin_get_child (GTK_BIN (menu_item));
2148 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2150 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2151 (gpointer) new_font_index))
2152 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2154 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2155 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2156 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2162 modest_msg_edit_window_set_zoom (ModestWindow *window,
2165 ModestMsgEditWindowPrivate *priv;
2166 ModestWindowPrivate *parent_priv;
2167 GtkRadioAction *zoom_radio_action;
2169 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2171 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2172 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2173 priv->zoom_level = zoom;
2174 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2176 /* Zoom level menu options should be updated with the current zoom level */
2177 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2178 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2179 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2180 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2181 /* FIXME: Not availible before Gtk 2.10 */
2183 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2188 modest_msg_edit_window_get_zoom (ModestWindow *window)
2190 ModestMsgEditWindowPrivate *priv;
2192 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2194 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2195 return priv->zoom_level;
2199 zoom_allowed (ModestMsgEditWindow *window)
2203 focus = gtk_window_get_focus (GTK_WINDOW (window));
2204 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2208 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2210 ModestWindowPrivate *parent_priv;
2211 GtkRadioAction *zoom_radio_action;
2212 GSList *group, *node;
2214 /* First we check if the text view is focused. If not, zooming is not allowed */
2215 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2216 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2220 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2221 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2222 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2224 group = gtk_radio_action_get_group (zoom_radio_action);
2226 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2227 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2231 for (node = group; node != NULL; node = g_slist_next (node)) {
2232 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2233 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2241 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2243 ModestWindowPrivate *parent_priv;
2244 GtkRadioAction *zoom_radio_action;
2245 GSList *group, *node;
2247 /* First we check if the text view is focused. If not, zooming is not allowed */
2248 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2249 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2253 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2254 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2255 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2257 group = gtk_radio_action_get_group (zoom_radio_action);
2259 for (node = group; node != NULL; node = g_slist_next (node)) {
2260 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2261 if (node->next != NULL) {
2262 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2265 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2273 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2275 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2276 ModestWindowPrivate *parent_priv;
2277 ModestWindowMgr *mgr;
2278 gboolean is_fullscreen;
2279 GtkAction *fs_toggle_action;
2282 mgr = modest_runtime_get_window_mgr ();
2283 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2285 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2287 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2288 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2289 if (is_fullscreen != active)
2290 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2298 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2301 ModestMsgEditWindowPrivate *priv = NULL;
2302 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2304 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2305 if (!priv->update_caption_visibility)
2308 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2310 gtk_widget_show (priv->cc_caption);
2312 gtk_widget_hide (priv->cc_caption);
2314 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2318 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2321 ModestMsgEditWindowPrivate *priv = NULL;
2322 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2324 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2325 if (!priv->update_caption_visibility)
2328 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2330 gtk_widget_show (priv->bcc_caption);
2332 gtk_widget_hide (priv->bcc_caption);
2334 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2338 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2339 ModestRecptEditor *editor)
2341 ModestMsgEditWindowPrivate *priv;
2343 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2344 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2345 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2347 if (editor == NULL) {
2348 GtkWidget *view_focus;
2349 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2351 /* This code should be kept in sync with ModestRecptEditor. The
2352 textview inside the recpt editor is the one that really gets the
2353 focus. As it's inside a scrolled window, and this one inside the
2354 hbox recpt editor inherits from, we'll need to go up in the
2355 hierarchy to know if the text view is part of the recpt editor
2356 or if it's a different text entry */
2358 if (gtk_widget_get_parent (view_focus)) {
2359 GtkWidget *first_parent;
2361 first_parent = gtk_widget_get_parent (view_focus);
2362 if (gtk_widget_get_parent (first_parent) &&
2363 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2364 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2369 editor = MODEST_RECPT_EDITOR (priv->to_field);
2373 modest_address_book_select_addresses (editor);
2378 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2380 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2382 modest_msg_edit_window_open_addressbook (window, NULL);
2386 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2387 gboolean show_toolbar)
2389 ModestWindowPrivate *parent_priv;
2390 const gchar *action_name;
2393 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2394 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2396 /* We can not just use the code of
2397 modest_msg_edit_window_setup_toolbar because it has a
2398 mixture of both initialization and creation code. */
2400 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2402 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2404 /* Update also the actions (to update the toggles in the
2405 menus), we have to do it manually because some other window
2406 of the same time could have changed it (remember that the
2407 toolbar fullscreen mode is shared by all the windows of the
2409 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2410 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2412 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2414 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2415 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2421 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2422 TnyHeaderFlags priority_flags)
2424 ModestMsgEditWindowPrivate *priv;
2425 ModestWindowPrivate *parent_priv;
2427 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2429 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2430 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2431 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2433 if (priv->priority_flags != priority_flags) {
2434 GtkAction *priority_action = NULL;
2436 priv->priority_flags = priority_flags;
2438 switch (priority_flags) {
2439 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2440 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2441 gtk_widget_show (priv->priority_icon);
2442 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2443 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2445 case TNY_HEADER_FLAG_LOW_PRIORITY:
2446 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2447 gtk_widget_show (priv->priority_icon);
2448 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2449 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2452 gtk_widget_hide (priv->priority_icon);
2453 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2454 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2457 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2458 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2463 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2466 ModestMsgEditWindowPrivate *priv;
2467 ModestWindowPrivate *parent_priv;
2468 gint current_format;
2470 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2472 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2473 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2475 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2476 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2478 if (current_format != file_format) {
2479 switch (file_format) {
2480 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2481 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2482 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2484 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2488 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2489 response = gtk_dialog_run (GTK_DIALOG (dialog));
2490 gtk_widget_destroy (dialog);
2491 if (response == GTK_RESPONSE_OK) {
2492 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2494 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2495 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2500 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2505 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2508 ModestMsgEditWindowPrivate *priv;
2509 WPTextBufferFormat oldfmt, fmt;
2510 gint old_position = 0;
2514 GdkColor *color = NULL;
2515 gboolean bold, bold_set, italic, italic_set;
2516 gboolean underline, underline_set;
2517 gboolean strikethrough, strikethrough_set;
2518 gboolean position_set;
2519 gboolean font_size_set, font_set, color_set;
2522 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2523 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2525 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2527 /* First we get the currently selected font information */
2528 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2529 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2531 switch (oldfmt.text_position) {
2532 case TEXT_POSITION_NORMAL:
2535 case TEXT_POSITION_SUPERSCRIPT:
2543 g_object_set (G_OBJECT (dialog),
2544 "bold", oldfmt.bold != FALSE,
2545 "bold-set", !oldfmt.cs.bold,
2546 "underline", oldfmt.underline != FALSE,
2547 "underline-set", !oldfmt.cs.underline,
2548 "italic", oldfmt.italic != FALSE,
2549 "italic-set", !oldfmt.cs.italic,
2550 "strikethrough", oldfmt.strikethrough != FALSE,
2551 "strikethrough-set", !oldfmt.cs.strikethrough,
2552 "color", &oldfmt.color,
2553 "color-set", !oldfmt.cs.color,
2554 "size", wp_font_size[oldfmt.font_size],
2555 "size-set", !oldfmt.cs.font_size,
2556 "position", old_position,
2557 "position-set", !oldfmt.cs.text_position,
2558 "family", wp_get_font_name (oldfmt.font),
2559 "family-set", !oldfmt.cs.font,
2562 gtk_widget_show_all (dialog);
2563 response = gtk_dialog_run (GTK_DIALOG (dialog));
2564 if (response == GTK_RESPONSE_OK) {
2566 g_object_get( dialog,
2568 "bold-set", &bold_set,
2569 "underline", &underline,
2570 "underline-set", &underline_set,
2572 "italic-set", &italic_set,
2573 "strikethrough", &strikethrough,
2574 "strikethrough-set", &strikethrough_set,
2576 "color-set", &color_set,
2578 "size-set", &font_size_set,
2579 "family", &font_name,
2580 "family-set", &font_set,
2581 "position", &position,
2582 "position-set", &position_set,
2587 if (response == GTK_RESPONSE_OK) {
2588 memset(&fmt, 0, sizeof(fmt));
2594 fmt.italic = italic;
2595 fmt.cs.italic = TRUE;
2597 if (underline_set) {
2598 fmt.underline = underline;
2599 fmt.cs.underline = TRUE;
2601 if (strikethrough_set) {
2602 fmt.strikethrough = strikethrough;
2603 fmt.cs.strikethrough = TRUE;
2608 ? TEXT_POSITION_NORMAL
2609 : ( ( position == 1 )
2610 ? TEXT_POSITION_SUPERSCRIPT
2611 : TEXT_POSITION_SUBSCRIPT );
2612 fmt.cs.text_position = TRUE;
2616 fmt.cs.color = TRUE;
2619 fmt.font = wp_get_font_index(font_name,
2624 if (font_size_set) {
2625 fmt.font_size = wp_get_font_size_index(
2626 font_size, DEFAULT_FONT_SIZE);
2627 fmt.cs.font_size = TRUE;
2629 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2630 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2632 gtk_widget_destroy (dialog);
2634 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2638 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2640 ModestMsgEditWindowPrivate *priv;
2642 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2643 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2645 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2647 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2652 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2654 ModestMsgEditWindowPrivate *priv;
2656 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2657 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2659 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2661 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2666 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2668 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2670 priv->can_undo = can_undo;
2674 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2676 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2678 priv->can_redo = can_redo;
2682 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2684 ModestMsgEditWindowPrivate *priv;
2685 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2686 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2688 return priv->can_undo;
2692 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2694 ModestMsgEditWindowPrivate *priv;
2695 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2696 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2698 return priv->can_redo;
2703 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2706 GtkTextIter match_start, match_end;
2708 if (image_id == NULL)
2711 gtk_text_buffer_get_start_iter (buffer, &iter);
2713 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2714 GSList *tags = gtk_text_iter_get_tags (&match_start);
2716 for (node = tags; node != NULL; node = g_slist_next (node)) {
2717 GtkTextTag *tag = (GtkTextTag *) node->data;
2718 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2719 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2720 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2722 offset = gtk_text_iter_get_offset (&match_start);
2723 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2724 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2728 gtk_text_iter_forward_char (&iter);
2733 message_is_empty (ModestMsgEditWindow *window)
2735 ModestMsgEditWindowPrivate *priv = NULL;
2737 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2738 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2740 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2741 * so we can ignore markup.
2743 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2746 count = gtk_text_buffer_get_char_count (buf);
2752 msg_body_focus (GtkWidget *focus,
2753 GdkEventFocus *event,
2757 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2762 recpt_field_changed (GtkTextBuffer *buffer,
2763 ModestMsgEditWindow *editor)
2765 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2769 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2771 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2775 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2777 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2778 GtkTextBuffer *buffer;
2780 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2781 gtk_text_buffer_set_modified (buffer, FALSE);
2782 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2783 gtk_text_buffer_set_modified (buffer, FALSE);
2784 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2785 gtk_text_buffer_set_modified (buffer, FALSE);
2786 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2790 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2792 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2793 GtkTextBuffer *buffer;
2795 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2796 if (gtk_text_buffer_get_modified (buffer))
2798 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2799 if (gtk_text_buffer_get_modified (buffer))
2801 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2802 if (gtk_text_buffer_get_modified (buffer))
2804 if (gtk_text_buffer_get_modified (priv->text_buffer))
2814 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2816 ModestMsgEditWindowPrivate *priv = NULL;
2818 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2819 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2821 /* check if there's no recipient added */
2822 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2823 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2824 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2825 /* no recipient contents, then select contacts */
2826 modest_msg_edit_window_open_addressbook (window, NULL);
2830 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2831 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2834 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2835 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2838 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2839 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2843 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2844 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2845 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2852 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2853 ModestMsgEditWindow *window)
2855 modest_msg_edit_window_offer_attach_file (window);
2859 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2861 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2863 return priv->clipboard_text;
2867 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2869 ModestMsgEditWindow *window)
2871 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2872 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2874 if (!GTK_WIDGET_VISIBLE (window))
2877 text = gtk_clipboard_wait_for_text (selection_clipboard);
2879 if (priv->clipboard_text != NULL) {
2880 g_free (priv->clipboard_text);
2882 priv->clipboard_text = text;
2884 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2887 subject_field_move_cursor (GtkEntry *entry,
2888 GtkMovementStep step,
2893 if (!GTK_WIDGET_VISIBLE (window))
2896 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2900 update_window_title (ModestMsgEditWindow *window)
2902 ModestMsgEditWindowPrivate *priv = NULL;
2903 const gchar *subject;
2905 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2906 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2907 if (subject == NULL || subject[0] == '\0')
2908 subject = _("mail_va_new_email");
2910 gtk_window_set_title (GTK_WINDOW (window), subject);
2915 subject_field_changed (GtkEditable *editable,
2916 ModestMsgEditWindow *window)
2918 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2919 update_window_title (window);
2920 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2921 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2925 subject_field_insert_text (GtkEditable *editable,
2927 gint new_text_length,
2929 ModestMsgEditWindow *window)
2931 GString *result = g_string_new ("");
2933 gint result_len = 0;
2934 const gchar *entry_text = NULL;
2937 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2938 old_length = g_utf8_strlen (entry_text, -1);
2940 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2941 gunichar c = g_utf8_get_char_validated (current, 8);
2942 /* Invalid unichar, stop */
2948 result = g_string_append_unichar (result, c);
2952 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2953 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2956 /* Prevent endless recursion */
2957 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2958 g_signal_emit_by_name (editable, "insert-text",
2959 (gpointer) result->str, (gpointer) result->len,
2960 (gpointer) position, (gpointer) window);
2961 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2965 if (result_len + old_length > 1000) {
2966 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2967 dgettext("hildon-common-strings",
2968 "ckdg_ib_maximum_characters_reached"));
2971 g_string_free (result, TRUE);
2975 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2978 ModestMsgEditWindowPrivate *priv = NULL;
2980 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2981 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2983 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2986 gtk_widget_show_all (priv->find_toolbar);
2987 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2989 gtk_widget_hide_all (priv->find_toolbar);
2990 gtk_widget_grab_focus (priv->msg_body);
2996 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2998 GtkTextIter *match_start,
2999 GtkTextIter *match_end)
3001 GtkTextIter end_iter;
3002 gchar *str_casefold;
3005 gchar *range_casefold;
3008 gboolean result = FALSE;
3015 gtk_text_iter_forward_to_end (&end_iter);
3017 str_casefold = g_utf8_casefold (str, -1);
3018 str_chars_n = strlen (str);
3020 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3021 range_casefold = g_utf8_casefold (range_text, -1);
3022 range_chars_n = strlen (range_casefold);
3024 if (range_chars_n < str_chars_n) {
3025 g_free (str_casefold);
3026 g_free (range_text);
3027 g_free (range_casefold);
3031 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3032 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3033 if (!g_utf8_collate (range_subtext, str_casefold)) {
3034 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3036 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3037 match_start, match_end, NULL);
3038 g_free (found_text);
3040 g_free (range_subtext);
3044 g_free (str_casefold);
3045 g_free (range_text);
3046 g_free (range_casefold);
3053 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3054 ModestMsgEditWindow *window)
3056 gchar *current_search = NULL;
3057 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3059 GtkTextIter selection_start, selection_end;
3060 GtkTextIter match_start, match_end;
3061 gboolean continue_search = FALSE;
3063 if (message_is_empty (window)) {
3064 g_free (priv->last_search);
3065 priv->last_search = NULL;
3066 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3070 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3071 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3072 g_free (current_search);
3073 g_free (priv->last_search);
3074 priv->last_search = NULL;
3075 /* Information banner about empty search */
3076 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3080 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3081 continue_search = TRUE;
3083 g_free (priv->last_search);
3084 priv->last_search = g_strdup (current_search);
3087 if (continue_search) {
3088 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3089 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3090 &match_start, &match_end);
3092 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3094 GtkTextIter buffer_start;
3095 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3096 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3097 &match_start, &match_end);
3099 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3102 /* Mark as selected the string found in search */
3104 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3105 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3107 g_free (priv->last_search);
3108 priv->last_search = NULL;
3110 g_free (current_search);
3114 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3115 ModestMsgEditWindow *window)
3117 GtkToggleAction *toggle;
3118 ModestWindowPrivate *parent_priv;
3119 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3121 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3122 gtk_toggle_action_set_active (toggle, FALSE);
3126 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3128 ModestMsgEditWindowPrivate *priv;
3130 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3135 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3138 ModestMsgEditWindowPrivate *priv;
3140 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3146 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3149 ModestMsgEditWindowPrivate *priv;
3150 TnyHeader *header = NULL;
3152 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3153 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3155 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3156 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3158 if (priv->draft_msg != NULL) {
3159 header = tny_msg_get_header (priv->draft_msg);
3160 if (TNY_IS_HEADER (header)) {
3161 modest_window_mgr_unregister_header (mgr, header);
3163 g_object_unref (priv->draft_msg);
3166 if (draft != NULL) {
3167 g_object_ref (draft);
3168 header = tny_msg_get_header (draft);
3169 if (TNY_IS_HEADER (header))
3170 modest_window_mgr_register_header (mgr, header);
3171 if (priv->msg_uid) {
3172 g_free (priv->msg_uid);
3173 priv->msg_uid = NULL;
3175 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3178 priv->draft_msg = draft;
3182 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3183 GtkTextIter *start, GtkTextIter *end,
3186 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3187 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3190 if (tag == NULL+13) return;
3191 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3192 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3193 replace_with_images (window, priv->images);
3198 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3201 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3203 g_return_if_fail (TNY_IS_MIME_PART (part));
3204 priv->attachments = g_list_prepend (priv->attachments, part);
3205 g_object_ref (part);
3206 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3207 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3208 gtk_widget_show_all (priv->attachments_caption);
3209 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3213 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3215 ModestMsgEditWindowPrivate *priv;
3217 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3218 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3220 return priv->msg_uid;
3224 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3225 ModestMsgEditWindowWidgetType widget_type)
3227 ModestMsgEditWindowPrivate *priv;
3229 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3232 switch (widget_type) {
3233 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3234 return priv->msg_body;
3236 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3237 return priv->to_field;
3239 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3240 return priv->cc_field;
3242 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3243 return priv->bcc_field;
3245 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3246 return priv->subject_field;
3248 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3249 return priv->attachments_view;
3257 remove_tags (WPTextBuffer *buffer)
3259 GtkTextIter start, end;
3261 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3262 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3264 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);