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;
248 TnyHeaderFlags priority_flags;
252 gboolean can_undo, can_redo;
253 gulong clipboard_change_handler_id;
254 gulong default_clipboard_change_handler_id;
255 gchar *clipboard_text;
264 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
265 MODEST_TYPE_MSG_EDIT_WINDOW, \
266 ModestMsgEditWindowPrivate))
268 static GtkWindowClass *parent_class = NULL;
270 /* uncomment the following if you have defined any signals */
271 /* static guint signals[LAST_SIGNAL] = {0}; */
274 modest_msg_edit_window_get_type (void)
276 static GType my_type = 0;
278 static const GTypeInfo my_info = {
279 sizeof(ModestMsgEditWindowClass),
280 NULL, /* base init */
281 NULL, /* base finalize */
282 (GClassInitFunc) modest_msg_edit_window_class_init,
283 NULL, /* class finalize */
284 NULL, /* class data */
285 sizeof(ModestMsgEditWindow),
287 (GInstanceInitFunc) modest_msg_edit_window_init,
290 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
291 "ModestMsgEditWindow",
294 wp_text_buffer_library_init ();
300 save_state (ModestWindow *self)
302 modest_widget_memory_save (modest_runtime_get_conf(),
303 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
308 restore_settings (ModestMsgEditWindow *self)
310 modest_widget_memory_restore (modest_runtime_get_conf(),
311 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
316 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
318 GObjectClass *gobject_class;
319 ModestWindowClass *modest_window_class;
320 gobject_class = (GObjectClass*) klass;
321 modest_window_class = (ModestWindowClass*) klass;
323 parent_class = g_type_class_peek_parent (klass);
324 gobject_class->finalize = modest_msg_edit_window_finalize;
326 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
327 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
328 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
329 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
330 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
331 modest_window_class->save_state_func = save_state;
332 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
334 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
338 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
340 ModestMsgEditWindowPrivate *priv;
341 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
343 priv->msg_body = NULL;
344 priv->from_field = NULL;
345 priv->to_field = NULL;
346 priv->cc_field = NULL;
347 priv->bcc_field = NULL;
348 priv->subject_field = NULL;
349 priv->attachments = NULL;
351 priv->zoom_level = 1.0;
353 priv->cc_caption = NULL;
354 priv->bcc_caption = NULL;
355 priv->update_caption_visibility = FALSE;
357 priv->priority_flags = 0;
359 priv->find_toolbar = NULL;
360 priv->last_search = NULL;
362 priv->draft_msg = NULL;
363 priv->outbox_msg = NULL;
364 priv->msg_uid = NULL;
366 priv->can_undo = FALSE;
367 priv->can_redo = FALSE;
368 priv->clipboard_change_handler_id = 0;
369 priv->default_clipboard_change_handler_id = 0;
370 priv->clipboard_text = NULL;
373 priv->last_vadj_upper = 0;
377 /* FIXME: this is a dup from the one in gtk/ */
380 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
382 static ModestPairList*
383 get_transports (void)
385 GSList *transports = NULL;
387 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
388 GSList *accounts = modest_account_mgr_account_names (account_mgr,
389 TRUE /* only enabled accounts. */);
391 GSList *cursor = accounts;
393 gchar *account_name = cursor->data;
394 gchar *from_string = NULL;
396 from_string = modest_account_mgr_get_from_string (account_mgr,
400 if (from_string && account_name) {
401 gchar *name = account_name;
402 ModestPair *pair = modest_pair_new ((gpointer) name,
403 (gpointer) from_string , TRUE);
404 transports = g_slist_prepend (transports, pair);
407 cursor = cursor->next;
409 g_slist_free (accounts); /* only free the accounts, not the elements,
410 * because they are used in the pairlist */
414 void vadj_changed (GtkAdjustment *adj,
415 ModestMsgEditWindow *window)
417 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
419 GdkRectangle rectangle, cursor_rectangle;
420 GtkTextIter position;
424 /* We detect if cursor is visible using the full height, not only the center. This
426 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
427 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
429 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
430 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
432 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
433 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
435 if (gtk_widget_is_focus (priv->msg_body) &&
437 if (priv->last_vadj_upper != adj->upper) {
440 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
441 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
442 insert, 0.1, FALSE, 0.0, 0.0);
445 priv->last_vadj_upper = adj->upper;
450 init_window (ModestMsgEditWindow *obj)
452 GtkWidget *from_caption, *to_caption, *subject_caption;
453 GtkWidget *main_vbox;
454 ModestMsgEditWindowPrivate *priv;
456 GtkSizeGroup *size_group;
458 GtkWidget *subject_box;
459 GtkWidget *attachment_icon;
460 GtkWidget *window_box;
461 #if (GTK_MINOR_VERSION >= 10)
462 GdkAtom deserialize_type;
464 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
466 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
468 /* Note: This ModestPairList* must exist for as long as the combo
469 * that uses it, because the ModestComboBox uses the ID opaquely,
470 * so it can't know how to manage its memory. */
471 priv->from_field_protos = get_transports ();
473 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
475 priv->to_field = modest_recpt_editor_new ();
476 priv->cc_field = modest_recpt_editor_new ();
477 priv->bcc_field = modest_recpt_editor_new ();
478 subject_box = gtk_hbox_new (FALSE, 0);
479 priv->priority_icon = gtk_image_new ();
480 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
481 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
482 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
483 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
484 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
485 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
486 priv->add_attachment_button = gtk_button_new ();
487 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
488 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
489 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
490 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
491 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
492 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
493 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
494 priv->attachments_view = modest_attachments_view_new (NULL);
496 priv->header_box = gtk_vbox_new (FALSE, 0);
498 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
499 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
500 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
501 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
502 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
503 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
504 g_object_unref (size_group);
506 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
507 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
508 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
509 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
510 gtk_size_group_add_widget (size_group, priv->subject_field);
511 gtk_size_group_add_widget (size_group, priv->attachments_view);
512 g_object_unref (size_group);
514 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
515 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
516 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
517 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
518 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
519 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
520 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
523 priv->msg_body = wp_text_view_new ();
524 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
525 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
526 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
527 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
528 #if (GTK_MINOR_VERSION >= 10)
529 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
530 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
532 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
533 deserialize_type, TRUE);
535 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
537 priv->find_toolbar = hildon_find_toolbar_new (NULL);
538 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
540 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
542 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
543 G_CALLBACK (text_buffer_refresh_attributes), obj);
544 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
545 G_CALLBACK (text_buffer_can_undo), obj);
546 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
547 G_CALLBACK (text_buffer_can_redo), obj);
548 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
549 G_CALLBACK (body_changed), obj);
550 g_signal_connect (G_OBJECT (obj), "window-state-event",
551 G_CALLBACK (modest_msg_edit_window_window_state_event),
553 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
554 G_CALLBACK (text_buffer_apply_tag), obj);
555 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
556 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
557 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
558 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
559 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
560 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
562 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
563 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
565 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
566 G_CALLBACK (msg_body_focus), obj);
567 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
568 G_CALLBACK (msg_body_focus), obj);
569 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
570 "changed", G_CALLBACK (recpt_field_changed), obj);
571 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
572 "changed", G_CALLBACK (recpt_field_changed), obj);
573 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
574 "changed", G_CALLBACK (recpt_field_changed), obj);
575 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
576 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
577 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
579 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
580 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
582 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
583 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
584 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
585 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
587 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
589 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
590 frame = gtk_frame_new (NULL);
591 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
593 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
594 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
595 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
597 G_CALLBACK (vadj_changed),
599 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
601 window_box = gtk_vbox_new (FALSE, 0);
602 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
603 gtk_container_add (GTK_CONTAINER(obj), window_box);
604 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
605 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
607 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
608 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
609 priv->default_clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
610 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
615 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
617 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
619 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
620 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
621 priv->clipboard_change_handler_id))
622 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
623 priv->clipboard_change_handler_id);
624 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
625 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
626 priv->default_clipboard_change_handler_id))
627 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
628 priv->default_clipboard_change_handler_id);
632 modest_msg_edit_window_finalize (GObject *obj)
634 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
636 /* Sanity check: shouldn't be needed, the window mgr should
637 call this function before */
638 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
640 if (priv->clipboard_text != NULL) {
641 g_free (priv->clipboard_text);
642 priv->clipboard_text = NULL;
645 if (priv->draft_msg != NULL) {
646 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
647 if (TNY_IS_HEADER (header)) {
648 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
649 modest_window_mgr_unregister_header (mgr, header);
651 g_object_unref (priv->draft_msg);
652 priv->draft_msg = NULL;
654 if (priv->outbox_msg != NULL) {
655 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
656 if (TNY_IS_HEADER (header)) {
657 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
658 modest_window_mgr_unregister_header (mgr, header);
660 g_object_unref (priv->outbox_msg);
661 priv->outbox_msg = NULL;
663 if (priv->msg_uid != NULL) {
664 g_free (priv->msg_uid);
665 priv->msg_uid = NULL;
668 /* This had to stay alive for as long as the combobox that used it: */
669 modest_pair_list_free (priv->from_field_protos);
671 G_OBJECT_CLASS(parent_class)->finalize (obj);
675 menubar_to_menu (GtkUIManager *ui_manager)
677 GtkWidget *main_menu;
681 /* Create new main menu */
682 main_menu = gtk_menu_new();
684 /* Get the menubar from the UI manager */
685 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
687 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
691 menu = GTK_WIDGET (iter->data);
692 gtk_widget_reparent(menu, main_menu);
694 iter = g_list_next (iter);
700 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
702 GdkPixbufLoader *loader;
705 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
710 tny_stream_reset (TNY_STREAM (stream));
711 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
712 unsigned char read_buffer[128];
714 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
715 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
719 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
720 g_object_ref (pixbuf);
721 gdk_pixbuf_loader_close (loader, NULL);
722 g_object_unref (loader);
724 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
725 GdkPixbuf *new_pixbuf;
727 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
728 gdk_pixbuf_get_width (pixbuf);
729 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
730 g_object_unref (pixbuf);
738 replace_with_attachments (ModestMsgEditWindow *self, GList *attachments)
740 ModestMsgEditWindowPrivate *priv;
743 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
745 for (node = attachments; node != NULL; node = g_list_next (node)) {
746 TnyMimePart *part = (TnyMimePart *) node->data;
747 const gchar *cid = tny_mime_part_get_content_id (part);
748 const gchar *mime_type = tny_mime_part_get_content_type (part);
749 if ((cid != NULL)&&(mime_type != NULL)) {
750 TnyStream *stream = tny_mime_part_get_stream (part);
751 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
752 g_object_unref (stream);
754 if (pixbuf != NULL) {
755 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
756 g_object_unref (pixbuf);
763 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
766 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
768 for (node = attachments; node != NULL; node = g_list_next (node)) {
769 TnyMimePart *part = (TnyMimePart *) node->data;
770 const gchar *cid = tny_mime_part_get_content_id (part);
772 char *invalid = NULL;
773 gint int_cid = strtol (cid, &invalid, 10);
774 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
775 priv->last_cid = int_cid;
783 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
786 const gchar *to, *cc, *bcc, *subject;
788 ModestMsgEditWindowPrivate *priv;
790 TnyHeaderFlags priority_flags;
791 TnyFolder *msg_folder;
792 gboolean is_html = FALSE;
794 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
795 g_return_if_fail (TNY_IS_MSG (msg));
797 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
799 header = tny_msg_get_header (msg);
800 to = tny_header_get_to (header);
801 cc = tny_header_get_cc (header);
802 bcc = tny_header_get_bcc (header);
803 subject = tny_header_get_subject (header);
804 priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
807 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
809 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
810 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
811 gtk_widget_show (priv->cc_caption);
812 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
813 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
814 gtk_widget_hide (priv->cc_caption);
817 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
818 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
819 gtk_widget_show (priv->bcc_caption);
820 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
821 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
822 gtk_widget_hide (priv->bcc_caption);
825 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
826 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
829 update_window_title (self);
831 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
832 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
834 if ((body == NULL)||(body[0] == '\0')) {
836 body = modest_text_utils_convert_to_html ("");
839 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
840 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
843 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
846 /* Add attachments to the view */
847 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
848 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
849 if (priv->attachments == NULL) {
850 gtk_widget_hide (priv->attachments_caption);
852 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
853 gtk_widget_show_all (priv->attachments_caption);
854 replace_with_attachments (self, priv->attachments);
856 update_last_cid (self, priv->attachments);
858 if (preserve_is_rich && !is_html) {
859 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
860 /* Get the default format required from configuration */
861 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
862 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
865 /* Set the default focus depending on having already a To: field or not */
866 if ((!to)||(*to == '\0')) {
867 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
869 gtk_widget_grab_focus (priv->msg_body);
872 /* TODO: lower priority, select in the From: combo to the
873 value that comes from msg <- not sure, should it be
876 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
878 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
879 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
881 modest_msg_edit_window_reset_modified (self);
883 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
884 text_buffer_can_undo (priv->text_buffer, FALSE, self);
885 text_buffer_can_redo (priv->text_buffer, FALSE, self);
888 g_free (priv->msg_uid);
889 priv->msg_uid = NULL;
892 /* we should set a reference to the incoming message if it is a draft */
893 msg_folder = tny_msg_get_folder (msg);
895 if (modest_tny_folder_is_local_folder (msg_folder)) {
896 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
897 if (type == TNY_FOLDER_TYPE_DRAFTS)
898 priv->draft_msg = g_object_ref(msg);
899 if (type == TNY_FOLDER_TYPE_OUTBOX)
900 priv->outbox_msg = g_object_ref(msg);
901 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
903 g_object_unref (msg_folder);
908 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
911 GList *item_children, *node;
912 GtkWidget *bin_child;
914 bin_child = gtk_bin_get_child (GTK_BIN(item));
916 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
918 for (node = item_children; node != NULL; node = g_list_next (node)) {
919 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
920 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
923 g_list_free (item_children);
927 menu_tool_button_dont_expand (GtkMenuToolButton *item)
930 GList *item_children, *node;
932 box = gtk_bin_get_child (GTK_BIN (item));
933 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
934 item_children = gtk_container_get_children (GTK_CONTAINER (box));
936 for (node = item_children; node != NULL; node = g_list_next (node)) {
937 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
938 if (GTK_IS_TOGGLE_BUTTON (node->data))
939 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
940 else if (GTK_IS_BUTTON (node->data))
941 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
943 g_list_free (item_children);
948 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
950 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
951 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
952 GtkWidget *placeholder;
953 GtkWidget *tool_item;
958 GtkWidget *sizes_menu;
959 GtkWidget *fonts_menu;
960 GSList *radio_group = NULL;
965 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
966 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
968 /* Font color placeholder */
969 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
970 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
973 tool_item = GTK_WIDGET (gtk_tool_item_new ());
974 priv->font_color_button = hildon_color_button_new ();
975 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
976 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
977 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
978 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
979 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
980 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
981 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
983 G_CALLBACK (modest_msg_edit_window_color_button_change),
986 /* Font size and face placeholder */
987 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
988 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
990 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
991 priv->size_tool_button_label = gtk_label_new (NULL);
992 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
993 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
994 size_text,"</span>", NULL);
995 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
997 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
998 sizes_menu = gtk_menu_new ();
999 priv->size_items_group = NULL;
1001 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1002 GtkWidget *size_menu_item;
1004 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1005 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1006 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1007 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1008 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1009 gtk_widget_show (size_menu_item);
1011 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1015 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1016 GtkWidget *item = (GtkWidget *) node->data;
1017 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1021 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1022 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1023 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1024 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1025 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1026 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1027 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1028 priv->font_size_toolitem = tool_item;
1031 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1032 priv->font_tool_button_label = gtk_label_new (NULL);
1033 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1034 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1036 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1037 fonts_menu = gtk_menu_new ();
1038 priv->font_items_group = NULL;
1040 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1041 GtkWidget *font_menu_item;
1042 GtkWidget *child_label;
1044 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1045 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1046 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1047 wp_get_font_name (font_index), "</span>", NULL);
1048 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1051 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1052 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1053 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1054 gtk_widget_show (font_menu_item);
1056 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1059 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1060 GtkWidget *item = (GtkWidget *) node->data;
1061 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1064 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1065 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1066 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1067 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1068 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1069 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1070 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1071 priv->font_face_toolitem = tool_item;
1073 /* Set expand and homogeneous for remaining items */
1074 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1075 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1076 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1077 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1078 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1079 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1080 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1081 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1082 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1084 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1085 will not show the tool items added to the placeholders) */
1086 gtk_widget_show_all (parent_priv->toolbar);
1088 /* Set the no show all *after* showing all items. We do not
1089 want the toolbar to be shown with a show all because it
1090 could go agains the gconf setting regarding showing or not
1091 the toolbar of the editor window */
1092 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1098 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1101 ModestWindowPrivate *parent_priv;
1102 ModestMsgEditWindowPrivate *priv;
1103 GtkActionGroup *action_group;
1104 GError *error = NULL;
1105 GdkPixbuf *window_icon = NULL;
1108 ModestPair *account_pair = NULL;
1109 ModestDimmingRulesGroup *menu_rules_group = NULL;
1110 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1111 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1113 g_return_val_if_fail (msg, NULL);
1114 g_return_val_if_fail (account_name, NULL);
1116 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1118 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1119 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1121 parent_priv->ui_manager = gtk_ui_manager_new();
1122 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1123 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1125 /* Add common actions */
1126 gtk_action_group_add_actions (action_group,
1127 modest_msg_edit_action_entries,
1128 G_N_ELEMENTS (modest_msg_edit_action_entries),
1130 gtk_action_group_add_toggle_actions (action_group,
1131 modest_msg_edit_toggle_action_entries,
1132 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1134 gtk_action_group_add_radio_actions (action_group,
1135 modest_msg_edit_alignment_radio_action_entries,
1136 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1138 G_CALLBACK (modest_ui_actions_on_change_justify),
1140 gtk_action_group_add_radio_actions (action_group,
1141 modest_msg_edit_zoom_action_entries,
1142 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1144 G_CALLBACK (modest_ui_actions_on_change_zoom),
1146 gtk_action_group_add_radio_actions (action_group,
1147 modest_msg_edit_priority_action_entries,
1148 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1150 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1152 gtk_action_group_add_radio_actions (action_group,
1153 modest_msg_edit_file_format_action_entries,
1154 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1155 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1156 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1158 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1159 g_object_unref (action_group);
1161 /* Load the UI definition */
1162 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1164 if (error != NULL) {
1165 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1166 g_clear_error (&error);
1169 /* Add accelerators */
1170 gtk_window_add_accel_group (GTK_WINDOW (obj),
1171 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1173 /* Menubar. Update the state of some toggles */
1174 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1175 conf = modest_runtime_get_conf ();
1176 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1177 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1178 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1179 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1180 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1181 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1182 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1183 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1185 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1188 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1190 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1192 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1194 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1195 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1197 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1198 if (account_pair != NULL)
1199 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1201 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1202 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1203 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1204 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1205 /* Add common dimming rules */
1206 modest_dimming_rules_group_add_rules (menu_rules_group,
1207 modest_msg_edit_window_menu_dimming_entries,
1208 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1209 MODEST_WINDOW (obj));
1210 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1211 modest_msg_edit_window_toolbar_dimming_entries,
1212 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1213 MODEST_WINDOW (obj));
1214 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1215 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1216 MODEST_WINDOW (obj));
1217 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1218 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1219 MODEST_WINDOW (obj));
1220 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1221 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1222 MODEST_WINDOW (obj));
1223 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1224 modest_msg_edit_window_clipboard_dimming_entries,
1225 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1226 MODEST_WINDOW (obj));
1227 /* Insert dimming rules group for this window */
1228 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1229 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1230 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1231 /* Checks the dimming rules */
1232 g_object_unref (menu_rules_group);
1233 g_object_unref (toolbar_rules_group);
1234 g_object_unref (clipboard_rules_group);
1236 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1238 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1240 /* Set window icon */
1241 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1243 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1244 g_object_unref (window_icon);
1247 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1248 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1250 /* Dim at start clipboard actions */
1251 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1252 gtk_action_set_sensitive (action, FALSE);
1253 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1254 gtk_action_set_sensitive (action, FALSE);
1255 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1256 gtk_action_set_sensitive (action, FALSE);
1258 /* set initial state of cc and bcc */
1259 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1260 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1261 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1262 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1263 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1264 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1266 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1267 priv->update_caption_visibility = TRUE;
1269 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1271 return (ModestWindow*) obj;
1275 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1277 GString **string_buffer = (GString **) user_data;
1279 *string_buffer = g_string_append (*string_buffer, buffer);
1285 * @result: A new string which should be freed with g_free().
1288 get_formatted_data (ModestMsgEditWindow *edit_window)
1290 ModestMsgEditWindowPrivate *priv;
1291 GString *string_buffer = g_string_new ("");
1293 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1295 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1297 return g_string_free (string_buffer, FALSE);
1302 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1305 const gchar *account_name;
1306 ModestMsgEditWindowPrivate *priv;
1308 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1310 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1312 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1313 g_return_val_if_fail (account_name, NULL);
1316 /* don't free these (except from) */
1317 data = g_slice_new0 (MsgData);
1318 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1320 data->account_name = g_strdup (account_name);
1321 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1322 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1323 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1324 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1325 if (priv->draft_msg) {
1326 data->draft_msg = g_object_ref (priv->draft_msg);
1327 } else if (priv->outbox_msg) {
1328 data->draft_msg = g_object_ref (priv->outbox_msg);
1330 data->draft_msg = NULL;
1333 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1335 gtk_text_buffer_get_bounds (buf, &b, &e);
1336 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1338 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1339 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1341 data->html_body = NULL;
1343 /* deep-copy the data */
1344 GList *cursor = priv->attachments;
1345 data->attachments = NULL;
1347 if (!(TNY_IS_MIME_PART(cursor->data))) {
1348 g_warning ("strange data in attachment list");
1349 cursor = g_list_next (cursor);
1352 data->attachments = g_list_append (data->attachments,
1353 g_object_ref (cursor->data));
1354 cursor = g_list_next (cursor);
1357 data->priority_flags = priv->priority_flags;
1364 unref_gobject (GObject *obj, gpointer data)
1366 if (!G_IS_OBJECT(obj))
1368 g_object_unref (obj);
1372 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1375 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1383 g_free (data->subject);
1384 g_free (data->plain_body);
1385 g_free (data->html_body);
1386 g_free (data->account_name);
1388 if (data->draft_msg != NULL) {
1389 g_object_unref (data->draft_msg);
1390 data->draft_msg = NULL;
1393 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1394 g_list_free (data->attachments);
1396 g_slice_free (MsgData, data);
1400 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1403 ModestMsgEditWindowPrivate *priv = NULL;
1404 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1406 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1408 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1410 return MODEST_MSG_EDIT_FORMAT_HTML;
1412 return MODEST_MSG_EDIT_FORMAT_TEXT;
1416 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1417 ModestMsgEditFormat format)
1419 ModestMsgEditWindowPrivate *priv;
1421 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1422 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1425 case MODEST_MSG_EDIT_FORMAT_HTML:
1426 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1428 case MODEST_MSG_EDIT_FORMAT_TEXT:
1429 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1432 g_return_if_reached ();
1436 ModestMsgEditFormatState *
1437 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1439 ModestMsgEditFormatState *format_state = NULL;
1440 ModestMsgEditWindowPrivate *priv;
1441 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1443 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1444 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1446 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1448 format_state = g_new0 (ModestMsgEditFormatState, 1);
1449 format_state->bold = buffer_format->bold&0x1;
1450 format_state->italics = buffer_format->italic&0x1;
1451 format_state->bullet = buffer_format->bullet&0x1;
1452 format_state->color = buffer_format->color;
1453 format_state->font_size = buffer_format->font_size;
1454 format_state->font_family = wp_get_font_name (buffer_format->font);
1455 format_state->justification = buffer_format->justification;
1456 g_free (buffer_format);
1458 return format_state;
1463 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1464 const ModestMsgEditFormatState *format_state)
1466 ModestMsgEditWindowPrivate *priv;
1467 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1468 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1469 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1470 g_return_if_fail (format_state != NULL);
1472 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1473 gtk_widget_grab_focus (priv->msg_body);
1474 buffer_format->bold = (format_state->bold != FALSE);
1475 buffer_format->italic = (format_state->italics != FALSE);
1476 buffer_format->color = format_state->color;
1477 buffer_format->font_size = format_state->font_size;
1478 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1479 buffer_format->justification = format_state->justification;
1480 buffer_format->bullet = format_state->bullet;
1482 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1484 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1485 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1486 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1487 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1488 buffer_format->cs.font = (buffer_format->font != current_format->font);
1489 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1490 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1492 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1493 if (buffer_format->cs.bold) {
1494 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1496 if (buffer_format->cs.italic) {
1497 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1499 if (buffer_format->cs.color) {
1500 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1502 if (buffer_format->cs.font_size) {
1503 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1505 if (buffer_format->cs.justification) {
1506 switch (buffer_format->justification) {
1507 case GTK_JUSTIFY_LEFT:
1508 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1510 case GTK_JUSTIFY_CENTER:
1511 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1513 case GTK_JUSTIFY_RIGHT:
1514 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1521 if (buffer_format->cs.font) {
1522 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1524 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1525 if (buffer_format->cs.bullet) {
1526 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1528 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1530 g_free (current_format);
1535 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1537 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1539 ModestWindowPrivate *parent_priv;
1540 ModestMsgEditWindowPrivate *priv;
1541 GtkWidget *new_size_menuitem;
1542 GtkWidget *new_font_menuitem;
1544 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1545 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1547 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1548 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1549 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1550 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1552 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1553 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1554 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1557 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1559 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1560 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1562 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1563 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1565 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1566 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1568 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1569 G_CALLBACK (modest_msg_edit_window_color_button_change),
1571 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1572 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1573 G_CALLBACK (modest_msg_edit_window_color_button_change),
1576 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1577 buffer_format->font_size))->data);
1578 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1582 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1583 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1584 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1586 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1587 G_CALLBACK (modest_msg_edit_window_size_change),
1589 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1590 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1591 G_CALLBACK (modest_msg_edit_window_size_change),
1595 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1596 buffer_format->font))->data);
1597 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1601 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1602 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1603 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1605 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1606 G_CALLBACK (modest_msg_edit_window_font_change),
1608 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1609 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1610 G_CALLBACK (modest_msg_edit_window_font_change),
1614 g_free (buffer_format);
1620 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1623 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1624 ModestMsgEditWindowPrivate *priv;
1625 GtkWidget *dialog = NULL;
1627 const GdkColor *new_color = NULL;
1629 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1630 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1632 #ifdef MODEST_HILDON_VERSION_0
1633 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1634 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1636 dialog = hildon_color_chooser_new ();
1637 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1638 #endif /*MODEST_HILDON_VERSION_0*/
1639 g_free (buffer_format);
1641 response = gtk_dialog_run (GTK_DIALOG (dialog));
1643 case GTK_RESPONSE_OK: {
1644 #ifdef MODEST_HILDON_VERSION_0
1645 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1648 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1650 #endif /*MODEST_HILDON_VERSION_0*/
1657 gtk_widget_destroy (dialog);
1659 if (new_color != NULL)
1660 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1665 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1668 ModestMsgEditWindowPrivate *priv;
1669 GtkWidget *dialog = NULL;
1671 GdkColor *old_color = NULL;
1672 const GdkColor *new_color = NULL;
1674 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1675 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1677 #ifdef MODEST_HILDON_VERSION_0
1678 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1679 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1681 dialog = hildon_color_chooser_new ();
1682 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1683 #endif /*MODEST_HILDON_VERSION_9*/
1685 response = gtk_dialog_run (GTK_DIALOG (dialog));
1687 case GTK_RESPONSE_OK: {
1688 #ifdef MODEST_HILDON_VERSION_0
1689 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1692 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1694 #endif /*MODEST_HILDON_VERSION_0*/
1700 gtk_widget_destroy (dialog);
1702 if (new_color != NULL)
1703 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1707 static TnyStream* create_stream_for_uri (const gchar* uri)
1712 TnyStream *result = NULL;
1714 GnomeVFSHandle *handle = NULL;
1715 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1716 if (test == GNOME_VFS_OK) {
1717 /* Create the tinymail stream: */
1718 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1719 result = TNY_STREAM (tny_vfs_stream_new (handle));
1726 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1729 ModestMsgEditWindowPrivate *priv;
1730 GtkWidget *dialog = NULL;
1732 GSList *uris = NULL;
1733 GSList *uri_node = NULL;
1735 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1737 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1738 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1739 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1741 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1743 response = gtk_dialog_run (GTK_DIALOG (dialog));
1745 case GTK_RESPONSE_OK:
1746 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1751 gtk_widget_destroy (dialog);
1753 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1755 GnomeVFSHandle *handle = NULL;
1756 GnomeVFSResult result;
1757 GtkTextIter position;
1758 GtkTextMark *insert_mark;
1760 uri = (const gchar *) uri_node->data;
1761 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1762 if (result == GNOME_VFS_OK) {
1764 GnomeVFSFileInfo info;
1765 gchar *filename, *basename, *escaped_filename;
1766 TnyMimePart *mime_part;
1768 const gchar *mime_type = NULL;
1769 GnomeVFSURI *vfs_uri;
1771 vfs_uri = gnome_vfs_uri_new (uri);
1773 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1774 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1775 g_free (escaped_filename);
1776 gnome_vfs_uri_unref (vfs_uri);
1778 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1779 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1781 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1783 mime_part = tny_platform_factory_new_mime_part
1784 (modest_runtime_get_platform_factory ());
1786 TnyStream *stream = create_stream_for_uri (uri);
1787 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1789 content_id = g_strdup_printf ("%d", priv->last_cid);
1790 tny_mime_part_set_content_id (mime_part, content_id);
1791 g_free (content_id);
1794 basename = g_path_get_basename (filename);
1795 tny_mime_part_set_filename (mime_part, basename);
1798 pixbuf = pixbuf_from_stream (stream, mime_type);
1800 if (pixbuf != NULL) {
1801 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1802 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1803 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1806 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1807 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1809 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1810 gtk_widget_show_all (priv->attachments_caption);
1811 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1821 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1824 ModestMsgEditWindowPrivate *priv;
1825 GtkWidget *dialog = NULL;
1827 GSList *uris = NULL;
1830 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1832 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1833 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1834 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1836 response = gtk_dialog_run (GTK_DIALOG (dialog));
1838 case GTK_RESPONSE_OK:
1839 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1844 gtk_widget_destroy (dialog);
1846 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1847 const gchar *uri = (const gchar *) uri_node->data;
1848 modest_msg_edit_window_attach_file_one (window, uri);
1850 g_slist_foreach (uris, (GFunc) g_free, NULL);
1851 g_slist_free (uris);
1855 modest_msg_edit_window_attach_file_one (
1856 ModestMsgEditWindow *window,
1859 g_return_if_fail (window);
1860 g_return_if_fail (uri);
1862 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1865 GnomeVFSHandle *handle = NULL;
1866 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1867 if (result == GNOME_VFS_OK) {
1868 TnyMimePart *mime_part;
1870 const gchar *mime_type = NULL;
1872 gchar *escaped_filename;
1875 GnomeVFSFileInfo info;
1876 GnomeVFSURI *vfs_uri;
1878 vfs_uri = gnome_vfs_uri_new (uri);
1881 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1882 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1883 g_free (escaped_filename);
1884 gnome_vfs_uri_unref (vfs_uri);
1886 if (gnome_vfs_get_file_info (uri,
1888 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1889 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1891 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1892 mime_part = tny_platform_factory_new_mime_part
1893 (modest_runtime_get_platform_factory ());
1894 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1896 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1898 content_id = g_strdup_printf ("%d", priv->last_cid);
1899 tny_mime_part_set_content_id (mime_part, content_id);
1900 g_free (content_id);
1903 basename = g_path_get_basename (filename);
1904 tny_mime_part_set_filename (mime_part, basename);
1907 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1908 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1910 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1911 gtk_widget_show_all (priv->attachments_caption);
1912 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1918 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1921 ModestMsgEditWindowPrivate *priv;
1922 gboolean clean_list = FALSE;
1924 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1925 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1927 if (att_list == NULL) {
1928 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1932 if (att_list == NULL) {
1933 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1935 GtkWidget *confirmation_dialog = NULL;
1936 gboolean dialog_response;
1938 gchar *message = NULL;
1939 const gchar *filename = NULL;
1941 if (att_list->next == NULL) {
1942 filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1946 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1947 att_list->next == NULL), filename);
1948 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1950 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1951 gtk_widget_destroy (confirmation_dialog);
1952 if (!dialog_response) {
1954 g_list_free (att_list);
1957 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1959 for (node = att_list; node != NULL; node = g_list_next (node)) {
1960 TnyMimePart *mime_part = (TnyMimePart *) node->data;
1961 const gchar *att_id;
1962 priv->attachments = g_list_remove (priv->attachments, mime_part);
1964 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1966 if (priv->attachments == NULL)
1967 gtk_widget_hide (priv->attachments_caption);
1968 att_id = tny_mime_part_get_content_id (mime_part);
1970 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1972 g_object_unref (mime_part);
1973 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1978 g_list_free (att_list);
1982 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1985 ModestMsgEditWindowPrivate *priv;
1986 GdkColor *new_color;
1987 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1989 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1990 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1993 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1995 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1997 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1999 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2004 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2007 ModestMsgEditWindowPrivate *priv;
2008 gint new_size_index;
2009 ModestMsgEditWindow *window;
2012 window = MODEST_MSG_EDIT_WINDOW (userdata);
2013 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2014 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2016 if (gtk_check_menu_item_get_active (menu_item)) {
2018 WPTextBufferFormat format;
2020 memset (&format, 0, sizeof (format));
2021 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2023 label = gtk_bin_get_child (GTK_BIN (menu_item));
2025 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2026 format.cs.font_size = TRUE;
2027 format.cs.text_position = TRUE;
2028 format.cs.font = TRUE;
2029 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2030 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2032 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2033 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2034 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2036 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2037 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2038 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2044 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2047 ModestMsgEditWindowPrivate *priv;
2048 gint new_font_index;
2049 ModestMsgEditWindow *window;
2052 window = MODEST_MSG_EDIT_WINDOW (userdata);
2053 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2054 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2056 if (gtk_check_menu_item_get_active (menu_item)) {
2059 label = gtk_bin_get_child (GTK_BIN (menu_item));
2061 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2063 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2064 (gpointer) new_font_index))
2065 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2067 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2068 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2069 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2075 modest_msg_edit_window_set_zoom (ModestWindow *window,
2078 ModestMsgEditWindowPrivate *priv;
2079 ModestWindowPrivate *parent_priv;
2080 GtkRadioAction *zoom_radio_action;
2082 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2084 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2085 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2086 priv->zoom_level = zoom;
2087 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2089 /* Zoom level menu options should be updated with the current zoom level */
2090 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2091 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2092 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2093 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2094 /* FIXME: Not availible before Gtk 2.10 */
2096 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2101 modest_msg_edit_window_get_zoom (ModestWindow *window)
2103 ModestMsgEditWindowPrivate *priv;
2105 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2107 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2108 return priv->zoom_level;
2112 zoom_allowed (ModestMsgEditWindow *window)
2116 focus = gtk_window_get_focus (GTK_WINDOW (window));
2117 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2121 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2123 ModestWindowPrivate *parent_priv;
2124 GtkRadioAction *zoom_radio_action;
2125 GSList *group, *node;
2127 /* First we check if the text view is focused. If not, zooming is not allowed */
2128 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2129 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2133 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2134 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2135 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2137 group = gtk_radio_action_get_group (zoom_radio_action);
2139 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2140 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2144 for (node = group; node != NULL; node = g_slist_next (node)) {
2145 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2146 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2154 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2156 ModestWindowPrivate *parent_priv;
2157 GtkRadioAction *zoom_radio_action;
2158 GSList *group, *node;
2160 /* First we check if the text view is focused. If not, zooming is not allowed */
2161 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2162 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2166 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2167 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2168 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2170 group = gtk_radio_action_get_group (zoom_radio_action);
2172 for (node = group; node != NULL; node = g_slist_next (node)) {
2173 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2174 if (node->next != NULL) {
2175 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2178 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2186 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2188 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2189 ModestWindowPrivate *parent_priv;
2190 ModestWindowMgr *mgr;
2191 gboolean is_fullscreen;
2192 GtkAction *fs_toggle_action;
2195 mgr = modest_runtime_get_window_mgr ();
2196 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2198 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2200 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2201 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2202 if (is_fullscreen != active)
2203 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2211 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2214 ModestMsgEditWindowPrivate *priv = NULL;
2215 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2217 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2218 if (!priv->update_caption_visibility)
2221 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2223 gtk_widget_show (priv->cc_caption);
2225 gtk_widget_hide (priv->cc_caption);
2227 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2231 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2234 ModestMsgEditWindowPrivate *priv = NULL;
2235 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2237 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2238 if (!priv->update_caption_visibility)
2241 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2243 gtk_widget_show (priv->bcc_caption);
2245 gtk_widget_hide (priv->bcc_caption);
2247 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2251 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2252 ModestRecptEditor *editor)
2254 ModestMsgEditWindowPrivate *priv;
2256 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2257 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2258 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2260 if (editor == NULL) {
2261 GtkWidget *view_focus;
2262 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2264 /* This code should be kept in sync with ModestRecptEditor. The
2265 textview inside the recpt editor is the one that really gets the
2266 focus. As it's inside a scrolled window, and this one inside the
2267 hbox recpt editor inherits from, we'll need to go up in the
2268 hierarchy to know if the text view is part of the recpt editor
2269 or if it's a different text entry */
2271 if (gtk_widget_get_parent (view_focus)) {
2272 GtkWidget *first_parent;
2274 first_parent = gtk_widget_get_parent (view_focus);
2275 if (gtk_widget_get_parent (first_parent) &&
2276 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2277 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2282 editor = MODEST_RECPT_EDITOR (priv->to_field);
2286 modest_address_book_select_addresses (editor);
2291 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2293 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2295 modest_msg_edit_window_open_addressbook (window, NULL);
2299 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2300 gboolean show_toolbar)
2302 ModestWindowPrivate *parent_priv;
2303 const gchar *action_name;
2306 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2307 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2309 /* We can not just use the code of
2310 modest_msg_edit_window_setup_toolbar because it has a
2311 mixture of both initialization and creation code. */
2313 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2315 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2317 /* Update also the actions (to update the toggles in the
2318 menus), we have to do it manually because some other window
2319 of the same time could have changed it (remember that the
2320 toolbar fullscreen mode is shared by all the windows of the
2322 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2323 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2325 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2327 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2328 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2334 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2335 TnyHeaderFlags priority_flags)
2337 ModestMsgEditWindowPrivate *priv;
2338 ModestWindowPrivate *parent_priv;
2340 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2342 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2343 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2344 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2346 if (priv->priority_flags != priority_flags) {
2347 GtkAction *priority_action = NULL;
2349 priv->priority_flags = priority_flags;
2351 switch (priority_flags) {
2352 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2353 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2354 gtk_widget_show (priv->priority_icon);
2355 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2356 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2358 case TNY_HEADER_FLAG_LOW_PRIORITY:
2359 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2360 gtk_widget_show (priv->priority_icon);
2361 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2362 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2365 gtk_widget_hide (priv->priority_icon);
2366 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2367 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2370 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2371 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2376 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2379 ModestMsgEditWindowPrivate *priv;
2380 ModestWindowPrivate *parent_priv;
2381 gint current_format;
2383 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2385 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2386 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2388 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2389 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2391 if (current_format != file_format) {
2392 switch (file_format) {
2393 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2394 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2395 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2397 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2401 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2402 response = gtk_dialog_run (GTK_DIALOG (dialog));
2403 gtk_widget_destroy (dialog);
2404 if (response == GTK_RESPONSE_OK) {
2405 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2407 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2408 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2413 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2418 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2421 ModestMsgEditWindowPrivate *priv;
2422 WPTextBufferFormat oldfmt, fmt;
2423 gint old_position = 0;
2427 GdkColor *color = NULL;
2428 gboolean bold, bold_set, italic, italic_set;
2429 gboolean underline, underline_set;
2430 gboolean strikethrough, strikethrough_set;
2431 gboolean position_set;
2432 gboolean font_size_set, font_set, color_set;
2435 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2436 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2438 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2440 /* First we get the currently selected font information */
2441 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2442 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2444 switch (oldfmt.text_position) {
2445 case TEXT_POSITION_NORMAL:
2448 case TEXT_POSITION_SUPERSCRIPT:
2456 g_object_set (G_OBJECT (dialog),
2457 "bold", oldfmt.bold != FALSE,
2458 "bold-set", !oldfmt.cs.bold,
2459 "underline", oldfmt.underline != FALSE,
2460 "underline-set", !oldfmt.cs.underline,
2461 "italic", oldfmt.italic != FALSE,
2462 "italic-set", !oldfmt.cs.italic,
2463 "strikethrough", oldfmt.strikethrough != FALSE,
2464 "strikethrough-set", !oldfmt.cs.strikethrough,
2465 "color", &oldfmt.color,
2466 "color-set", !oldfmt.cs.color,
2467 "size", wp_font_size[oldfmt.font_size],
2468 "size-set", !oldfmt.cs.font_size,
2469 "position", old_position,
2470 "position-set", !oldfmt.cs.text_position,
2471 "family", wp_get_font_name (oldfmt.font),
2472 "family-set", !oldfmt.cs.font,
2475 gtk_widget_show_all (dialog);
2476 response = gtk_dialog_run (GTK_DIALOG (dialog));
2477 if (response == GTK_RESPONSE_OK) {
2479 g_object_get( dialog,
2481 "bold-set", &bold_set,
2482 "underline", &underline,
2483 "underline-set", &underline_set,
2485 "italic-set", &italic_set,
2486 "strikethrough", &strikethrough,
2487 "strikethrough-set", &strikethrough_set,
2489 "color-set", &color_set,
2491 "size-set", &font_size_set,
2492 "family", &font_name,
2493 "family-set", &font_set,
2494 "position", &position,
2495 "position-set", &position_set,
2500 if (response == GTK_RESPONSE_OK) {
2501 memset(&fmt, 0, sizeof(fmt));
2507 fmt.italic = italic;
2508 fmt.cs.italic = TRUE;
2510 if (underline_set) {
2511 fmt.underline = underline;
2512 fmt.cs.underline = TRUE;
2514 if (strikethrough_set) {
2515 fmt.strikethrough = strikethrough;
2516 fmt.cs.strikethrough = TRUE;
2521 ? TEXT_POSITION_NORMAL
2522 : ( ( position == 1 )
2523 ? TEXT_POSITION_SUPERSCRIPT
2524 : TEXT_POSITION_SUBSCRIPT );
2525 fmt.cs.text_position = TRUE;
2529 fmt.cs.color = TRUE;
2532 fmt.font = wp_get_font_index(font_name,
2537 if (font_size_set) {
2538 fmt.font_size = wp_get_font_size_index(
2539 font_size, DEFAULT_FONT_SIZE);
2540 fmt.cs.font_size = TRUE;
2542 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2543 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2545 gtk_widget_destroy (dialog);
2547 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2551 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2553 ModestMsgEditWindowPrivate *priv;
2555 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2556 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2558 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2560 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2565 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2567 ModestMsgEditWindowPrivate *priv;
2569 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2570 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2572 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2574 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2579 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2581 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2583 priv->can_undo = can_undo;
2587 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2589 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2591 priv->can_redo = can_redo;
2595 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2597 ModestMsgEditWindowPrivate *priv;
2598 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2599 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2601 return priv->can_undo;
2605 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2607 ModestMsgEditWindowPrivate *priv;
2608 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2609 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2611 return priv->can_redo;
2616 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2619 GtkTextIter match_start, match_end;
2621 if (image_id == NULL)
2624 gtk_text_buffer_get_start_iter (buffer, &iter);
2626 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2627 GSList *tags = gtk_text_iter_get_tags (&match_start);
2629 for (node = tags; node != NULL; node = g_slist_next (node)) {
2630 GtkTextTag *tag = (GtkTextTag *) node->data;
2631 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2632 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2633 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2635 offset = gtk_text_iter_get_offset (&match_start);
2636 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2637 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2641 gtk_text_iter_forward_char (&iter);
2646 message_is_empty (ModestMsgEditWindow *window)
2648 ModestMsgEditWindowPrivate *priv = NULL;
2650 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2651 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2653 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2654 * so we can ignore markup.
2656 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2659 count = gtk_text_buffer_get_char_count (buf);
2665 msg_body_focus (GtkWidget *focus,
2666 GdkEventFocus *event,
2670 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2675 recpt_field_changed (GtkTextBuffer *buffer,
2676 ModestMsgEditWindow *editor)
2678 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2682 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2684 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2688 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2690 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2691 GtkTextBuffer *buffer;
2693 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2694 gtk_text_buffer_set_modified (buffer, FALSE);
2695 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2696 gtk_text_buffer_set_modified (buffer, FALSE);
2697 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2698 gtk_text_buffer_set_modified (buffer, FALSE);
2699 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2703 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2705 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2706 GtkTextBuffer *buffer;
2708 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2709 if (gtk_text_buffer_get_modified (buffer))
2711 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2712 if (gtk_text_buffer_get_modified (buffer))
2714 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2715 if (gtk_text_buffer_get_modified (buffer))
2717 if (gtk_text_buffer_get_modified (priv->text_buffer))
2727 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2729 ModestMsgEditWindowPrivate *priv = NULL;
2731 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2732 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2734 /* check if there's no recipient added */
2735 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2736 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2737 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2738 /* no recipient contents, then select contacts */
2739 modest_msg_edit_window_open_addressbook (window, NULL);
2743 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2744 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2747 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2748 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2751 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2752 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2756 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2757 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2758 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2765 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2766 ModestMsgEditWindow *window)
2768 modest_msg_edit_window_offer_attach_file (window);
2772 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2774 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2776 return priv->clipboard_text;
2780 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2782 ModestMsgEditWindow *window)
2784 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2785 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2787 if (!GTK_WIDGET_VISIBLE (window))
2790 text = gtk_clipboard_wait_for_text (selection_clipboard);
2792 if (priv->clipboard_text != NULL) {
2793 g_free (priv->clipboard_text);
2795 priv->clipboard_text = text;
2797 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2800 subject_field_move_cursor (GtkEntry *entry,
2801 GtkMovementStep step,
2806 if (!GTK_WIDGET_VISIBLE (window))
2809 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2813 update_window_title (ModestMsgEditWindow *window)
2815 ModestMsgEditWindowPrivate *priv = NULL;
2816 const gchar *subject;
2818 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2819 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2820 if (subject == NULL || subject[0] == '\0')
2821 subject = _("mail_va_new_email");
2823 gtk_window_set_title (GTK_WINDOW (window), subject);
2828 subject_field_changed (GtkEditable *editable,
2829 ModestMsgEditWindow *window)
2831 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2832 update_window_title (window);
2833 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2834 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2838 subject_field_insert_text (GtkEditable *editable,
2840 gint new_text_length,
2842 ModestMsgEditWindow *window)
2844 GString *result = g_string_new ("");
2846 gint result_len = 0;
2847 const gchar *entry_text = NULL;
2850 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2851 old_length = g_utf8_strlen (entry_text, -1);
2853 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2854 gunichar c = g_utf8_get_char_validated (current, 8);
2855 /* Invalid unichar, stop */
2861 result = g_string_append_unichar (result, c);
2865 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2866 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2869 /* Prevent endless recursion */
2870 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2871 g_signal_emit_by_name (editable, "insert-text",
2872 (gpointer) result->str, (gpointer) result->len,
2873 (gpointer) position, (gpointer) window);
2874 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2878 if (result_len + old_length > 1000) {
2879 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2880 dgettext("hildon-common-strings",
2881 "ckdg_ib_maximum_characters_reached"));
2884 g_string_free (result, TRUE);
2888 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2891 ModestMsgEditWindowPrivate *priv = NULL;
2893 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2894 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2896 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2899 gtk_widget_show_all (priv->find_toolbar);
2900 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2902 gtk_widget_hide_all (priv->find_toolbar);
2903 gtk_widget_grab_focus (priv->msg_body);
2909 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2911 GtkTextIter *match_start,
2912 GtkTextIter *match_end)
2914 GtkTextIter end_iter;
2915 gchar *str_casefold;
2918 gchar *range_casefold;
2921 gboolean result = FALSE;
2928 gtk_text_iter_forward_to_end (&end_iter);
2930 str_casefold = g_utf8_casefold (str, -1);
2931 str_chars_n = strlen (str);
2933 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2934 range_casefold = g_utf8_casefold (range_text, -1);
2935 range_chars_n = strlen (range_casefold);
2937 if (range_chars_n < str_chars_n) {
2938 g_free (str_casefold);
2939 g_free (range_text);
2940 g_free (range_casefold);
2944 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2945 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2946 if (!g_utf8_collate (range_subtext, str_casefold)) {
2947 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2949 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2950 match_start, match_end, NULL);
2951 g_free (found_text);
2953 g_free (range_subtext);
2957 g_free (str_casefold);
2958 g_free (range_text);
2959 g_free (range_casefold);
2966 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2967 ModestMsgEditWindow *window)
2969 gchar *current_search = NULL;
2970 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2972 GtkTextIter selection_start, selection_end;
2973 GtkTextIter match_start, match_end;
2974 gboolean continue_search = FALSE;
2976 if (message_is_empty (window)) {
2977 g_free (priv->last_search);
2978 priv->last_search = NULL;
2979 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
2983 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
2984 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2985 g_free (current_search);
2986 g_free (priv->last_search);
2987 priv->last_search = NULL;
2988 /* Information banner about empty search */
2989 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
2993 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
2994 continue_search = TRUE;
2996 g_free (priv->last_search);
2997 priv->last_search = g_strdup (current_search);
3000 if (continue_search) {
3001 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3002 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3003 &match_start, &match_end);
3005 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3007 GtkTextIter buffer_start;
3008 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3009 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3010 &match_start, &match_end);
3012 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3015 /* Mark as selected the string found in search */
3017 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3018 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3020 g_free (priv->last_search);
3021 priv->last_search = NULL;
3023 g_free (current_search);
3027 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3028 ModestMsgEditWindow *window)
3030 GtkToggleAction *toggle;
3031 ModestWindowPrivate *parent_priv;
3032 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3034 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3035 gtk_toggle_action_set_active (toggle, FALSE);
3039 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3041 ModestMsgEditWindowPrivate *priv;
3043 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3048 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3051 ModestMsgEditWindowPrivate *priv;
3053 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3059 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3062 ModestMsgEditWindowPrivate *priv;
3063 TnyHeader *header = NULL;
3065 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3066 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3068 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3069 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3071 if (priv->draft_msg != NULL) {
3072 header = tny_msg_get_header (priv->draft_msg);
3073 if (TNY_IS_HEADER (header)) {
3074 modest_window_mgr_unregister_header (mgr, header);
3076 g_object_unref (priv->draft_msg);
3079 if (draft != NULL) {
3080 g_object_ref (draft);
3081 header = tny_msg_get_header (draft);
3082 if (TNY_IS_HEADER (header))
3083 modest_window_mgr_register_header (mgr, header);
3084 if (priv->msg_uid) {
3085 g_free (priv->msg_uid);
3086 priv->msg_uid = NULL;
3088 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3091 priv->draft_msg = draft;
3095 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3096 GtkTextIter *start, GtkTextIter *end,
3099 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3100 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3103 if (tag == NULL+13) return;
3104 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3105 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3106 replace_with_attachments (window, priv->attachments);
3111 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3114 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3116 g_return_if_fail (TNY_IS_MIME_PART (part));
3117 priv->attachments = g_list_prepend (priv->attachments, part);
3118 g_object_ref (part);
3119 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3120 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3121 gtk_widget_show_all (priv->attachments_caption);
3122 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3126 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3128 ModestMsgEditWindowPrivate *priv;
3130 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3131 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3133 return priv->msg_uid;
3137 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3138 ModestMsgEditWindowWidgetType widget_type)
3140 ModestMsgEditWindowPrivate *priv;
3142 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3143 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3145 switch (widget_type) {
3146 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3147 return priv->msg_body;
3149 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3150 return priv->to_field;
3152 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3153 return priv->cc_field;
3155 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3156 return priv->bcc_field;
3158 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3159 return priv->subject_field;
3161 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3162 return priv->attachments_view;
3170 remove_tags (WPTextBuffer *buffer)
3172 GtkTextIter start, end;
3174 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3175 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3177 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);