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"
66 #include "modest-hildon-includes.h"
67 #ifdef MODEST_HAVE_HILDON0_WIDGETS
68 #include <hildon-widgets/hildon-color-chooser.h>
70 #include "widgets/modest-msg-edit-window-ui.h"
71 #ifdef MODEST_HAVE_HILDON0_WIDGETS
72 #include <libgnomevfs/gnome-vfs-mime-utils.h>
74 #include <libgnomevfs/gnome-vfs-mime.h>
76 #include "modest-maemo-utils.h"
79 #define DEFAULT_FONT_SIZE 3
80 #define DEFAULT_FONT 2
81 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
82 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
83 #define DEFAULT_MAIN_VBOX_SPACING 6
84 #define SUBJECT_MAX_LENGTH 1000
85 #define IMAGE_MAX_WIDTH 560
86 #define DEFAULT_FONT_SCALE 1.5
88 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
89 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
90 static void modest_msg_edit_window_finalize (GObject *obj);
92 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
93 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
94 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
95 static void send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
96 static void style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
97 static void setup_insensitive_handlers (ModestMsgEditWindow *editor);
98 static void reset_modified (ModestMsgEditWindow *editor);
100 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
101 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
102 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
103 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
104 GtkTextIter *start, GtkTextIter *end,
106 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
107 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
108 static void subject_field_insert_text (GtkEditable *editable,
110 gint new_text_length,
112 ModestMsgEditWindow *window);
113 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
115 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
117 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
119 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
120 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
121 GdkEventWindowState *event,
123 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
124 ModestRecptEditor *editor);
125 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
126 ModestMsgEditWindow *window);
128 /* ModestWindow methods implementation */
129 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
130 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
131 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
132 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
133 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
134 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
135 gboolean show_toolbar);
136 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
138 ModestMsgEditWindow *window);
139 static void update_window_title (ModestMsgEditWindow *window);
140 static void update_dimmed (ModestMsgEditWindow *window);
141 static void update_paste_dimming (ModestMsgEditWindow *window);
142 static void update_remove_attachment_dimming (ModestMsgEditWindow *window);
143 static void update_copy_cut_dimming (ModestMsgEditWindow *window);
144 static void update_select_all_dimming (ModestMsgEditWindow *window);
145 static void update_zoom_dimming (ModestMsgEditWindow *window);
146 static void update_send_dimming (ModestMsgEditWindow *window);
149 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
150 ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
152 ModestMsgEditWindow *window);
153 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
155 GtkTextIter *match_start,
156 GtkTextIter *match_end);
158 static void DEBUG_BUFFER (WPTextBuffer *buffer)
163 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
164 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
165 while (!gtk_text_iter_is_end (&iter)) {
166 GString *output = g_string_new ("");
167 GSList *toggled_tags;
170 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
171 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
172 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
173 GtkTextTag *tag = (GtkTextTag *) node->data;
175 g_object_get (G_OBJECT (tag), "name", &name, NULL);
176 output = g_string_append (output, name);
177 g_string_append (output, " ");
179 output = g_string_append (output, "] OPENED [ ");
180 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
181 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
182 GtkTextTag *tag = (GtkTextTag *) node->data;
184 g_object_get (G_OBJECT (tag), "name", &name, NULL);
185 output = g_string_append (output, name);
186 g_string_append (output, " ");
188 output = g_string_append (output, "]\n");
189 g_message ("%s", output->str);
190 g_string_free (output, TRUE);
191 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
193 g_message ("END BUFFER");
198 /* static gboolean */
199 /* on_key_pressed (GtkWidget *self, */
200 /* GdkEventKey *event, */
201 /* gpointer user_data); */
203 static void edit_menu_activated (GtkAction *action,
205 static void view_menu_activated (GtkAction *action,
208 /* list my signals */
215 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
216 struct _ModestMsgEditWindowPrivate {
218 GtkWidget *header_box;
220 ModestPairList *from_field_protos;
221 GtkWidget *from_field;
225 GtkWidget *bcc_field;
226 GtkWidget *subject_field;
227 GtkWidget *attachments_view;
228 GtkWidget *priority_icon;
229 GtkWidget *add_attachment_button;
231 GtkWidget *cc_caption;
232 GtkWidget *bcc_caption;
233 gboolean update_caption_visibility;
234 GtkWidget *attachments_caption;
236 GtkTextBuffer *text_buffer;
238 GtkWidget *font_size_toolitem;
239 GtkWidget *font_face_toolitem;
240 GtkWidget *font_color_button;
241 GSList *font_items_group;
242 GtkWidget *font_tool_button_label;
243 GSList *size_items_group;
244 GtkWidget *size_tool_button_label;
246 GtkWidget *find_toolbar;
250 GtkWidget *scroll_area;
251 gint last_vadj_upper;
256 TnyHeaderFlags priority_flags;
260 gulong clipboard_change_handler_id;
269 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
270 MODEST_TYPE_MSG_EDIT_WINDOW, \
271 ModestMsgEditWindowPrivate))
273 static GtkWindowClass *parent_class = NULL;
275 /* uncomment the following if you have defined any signals */
276 /* static guint signals[LAST_SIGNAL] = {0}; */
279 modest_msg_edit_window_get_type (void)
281 static GType my_type = 0;
283 static const GTypeInfo my_info = {
284 sizeof(ModestMsgEditWindowClass),
285 NULL, /* base init */
286 NULL, /* base finalize */
287 (GClassInitFunc) modest_msg_edit_window_class_init,
288 NULL, /* class finalize */
289 NULL, /* class data */
290 sizeof(ModestMsgEditWindow),
292 (GInstanceInitFunc) modest_msg_edit_window_init,
295 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
296 "ModestMsgEditWindow",
299 wp_text_buffer_library_init ();
305 save_state (ModestWindow *self)
307 modest_widget_memory_save (modest_runtime_get_conf(),
308 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
313 restore_settings (ModestMsgEditWindow *self)
315 modest_widget_memory_restore (modest_runtime_get_conf(),
316 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
321 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
323 GObjectClass *gobject_class;
324 ModestWindowClass *modest_window_class;
325 gobject_class = (GObjectClass*) klass;
326 modest_window_class = (ModestWindowClass*) klass;
328 parent_class = g_type_class_peek_parent (klass);
329 gobject_class->finalize = modest_msg_edit_window_finalize;
331 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
332 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
333 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
334 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
335 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
336 modest_window_class->save_state_func = save_state;
337 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
339 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
343 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
345 ModestMsgEditWindowPrivate *priv;
346 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
348 priv->msg_body = NULL;
349 priv->from_field = NULL;
350 priv->to_field = NULL;
351 priv->cc_field = NULL;
352 priv->bcc_field = NULL;
353 priv->subject_field = NULL;
354 priv->attachments = NULL;
356 priv->zoom_level = 1.0;
358 priv->cc_caption = NULL;
359 priv->bcc_caption = NULL;
360 priv->update_caption_visibility = FALSE;
362 priv->priority_flags = 0;
364 priv->find_toolbar = NULL;
365 priv->last_search = NULL;
367 priv->draft_msg = NULL;
368 priv->outbox_msg = NULL;
369 priv->msg_uid = NULL;
370 priv->clipboard_change_handler_id = 0;
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 static gboolean attachment_view_focus_lost (
416 GdkEventFocus *event,
417 ModestMsgEditWindow *window)
419 g_return_val_if_fail(MODEST_IS_MSG_EDIT_WINDOW(window), FALSE);
421 update_remove_attachment_dimming(window);
426 void vadj_changed (GtkAdjustment *adj,
427 ModestMsgEditWindow *window)
429 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
431 GdkRectangle rectangle, cursor_rectangle;
432 GtkTextIter position;
436 /* We detect if cursor is visible using the full height, not only the center. This
438 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
439 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
441 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
442 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
444 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
445 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
447 if (gtk_widget_is_focus (priv->msg_body) &&
449 if (priv->last_vadj_upper != adj->upper) {
452 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
453 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
454 insert, 0.1, FALSE, 0.0, 0.0);
457 priv->last_vadj_upper = adj->upper;
462 init_window (ModestMsgEditWindow *obj)
464 GtkWidget *from_caption, *to_caption, *subject_caption;
465 GtkWidget *main_vbox;
466 ModestMsgEditWindowPrivate *priv;
468 GtkSizeGroup *size_group;
470 GtkWidget *subject_box;
471 GtkWidget *attachment_icon;
472 GtkWidget *window_box;
473 #if (GTK_MINOR_VERSION >= 10)
474 GdkAtom deserialize_type;
476 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
478 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
480 /* Note: This ModestPairList* must exist for as long as the combo
481 * that uses it, because the ModestComboBox uses the ID opaquely,
482 * so it can't know how to manage its memory. */
483 priv->from_field_protos = get_transports ();
485 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
487 priv->to_field = modest_recpt_editor_new ();
488 priv->cc_field = modest_recpt_editor_new ();
489 priv->bcc_field = modest_recpt_editor_new ();
490 subject_box = gtk_hbox_new (FALSE, 0);
491 priv->priority_icon = gtk_image_new ();
492 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
493 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
494 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
495 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
496 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
497 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
498 priv->add_attachment_button = gtk_button_new ();
499 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
500 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
501 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
502 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
503 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
504 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
505 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
506 priv->attachments_view = modest_attachments_view_new (NULL);
507 g_signal_connect (G_OBJECT (priv->attachments_view), "focus-out-event",
508 G_CALLBACK (attachment_view_focus_lost), obj);
510 priv->header_box = gtk_vbox_new (FALSE, 0);
512 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
513 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
514 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
515 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
516 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
517 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
518 g_object_unref (size_group);
520 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
521 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
522 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
523 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
524 gtk_size_group_add_widget (size_group, priv->subject_field);
525 gtk_size_group_add_widget (size_group, priv->attachments_view);
526 g_object_unref (size_group);
528 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
529 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
530 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
531 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
532 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
533 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
534 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
537 priv->msg_body = wp_text_view_new ();
538 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
539 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
540 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
541 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
542 #if (GTK_MINOR_VERSION >= 10)
543 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
544 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
546 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
547 deserialize_type, TRUE);
549 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
551 priv->find_toolbar = hildon_find_toolbar_new (NULL);
552 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
554 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
556 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
557 G_CALLBACK (text_buffer_refresh_attributes), obj);
558 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
559 G_CALLBACK (text_buffer_can_undo), obj);
560 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
561 G_CALLBACK (text_buffer_can_redo), obj);
562 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
563 G_CALLBACK (body_changed), obj);
564 g_signal_connect (G_OBJECT (obj), "window-state-event",
565 G_CALLBACK (modest_msg_edit_window_window_state_event),
567 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
568 G_CALLBACK (text_buffer_apply_tag), obj);
569 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
570 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
571 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
572 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
573 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
574 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
576 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
577 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
579 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
580 G_CALLBACK (msg_body_focus), obj);
581 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
582 G_CALLBACK (msg_body_focus), obj);
583 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
584 "changed", G_CALLBACK (recpt_field_changed), obj);
585 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
586 "changed", G_CALLBACK (recpt_field_changed), obj);
587 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
588 "changed", G_CALLBACK (recpt_field_changed), obj);
589 recpt_field_changed (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)), MODEST_MSG_EDIT_WINDOW (obj));
590 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
591 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
593 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
594 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
596 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
597 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
598 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
599 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
601 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
603 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
604 frame = gtk_frame_new (NULL);
605 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
607 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
608 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
609 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
611 G_CALLBACK (vadj_changed),
613 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
615 window_box = gtk_vbox_new (FALSE, 0);
616 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
617 gtk_container_add (GTK_CONTAINER(obj), window_box);
618 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
619 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
621 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
622 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
627 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
629 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
631 if (g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
632 priv->clipboard_change_handler_id))
633 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
634 priv->clipboard_change_handler_id);
638 modest_msg_edit_window_finalize (GObject *obj)
640 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
642 /* Sanity check: shouldn't be needed, the window mgr should
643 call this function before */
644 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
646 if (priv->draft_msg != NULL) {
647 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
648 if (TNY_IS_HEADER (header)) {
649 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
650 modest_window_mgr_unregister_header (mgr, header);
652 g_object_unref (priv->draft_msg);
653 priv->draft_msg = NULL;
655 if (priv->outbox_msg != NULL) {
656 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
657 if (TNY_IS_HEADER (header)) {
658 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
659 modest_window_mgr_unregister_header (mgr, header);
661 g_object_unref (priv->outbox_msg);
662 priv->outbox_msg = NULL;
664 if (priv->msg_uid != NULL) {
665 g_free (priv->msg_uid);
666 priv->msg_uid = NULL;
669 /* This had to stay alive for as long as the combobox that used it: */
670 modest_pair_list_free (priv->from_field_protos);
672 G_OBJECT_CLASS(parent_class)->finalize (obj);
676 menubar_to_menu (GtkUIManager *ui_manager)
678 GtkWidget *main_menu;
682 /* Create new main menu */
683 main_menu = gtk_menu_new();
685 /* Get the menubar from the UI manager */
686 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
688 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
692 menu = GTK_WIDGET (iter->data);
693 gtk_widget_reparent(menu, main_menu);
695 iter = g_list_next (iter);
701 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
703 GdkPixbufLoader *loader;
706 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
711 tny_stream_reset (TNY_STREAM (stream));
712 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
713 unsigned char read_buffer[128];
715 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
716 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
720 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
721 g_object_ref (pixbuf);
722 gdk_pixbuf_loader_close (loader, NULL);
723 g_object_unref (loader);
725 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
726 GdkPixbuf *new_pixbuf;
728 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
729 gdk_pixbuf_get_width (pixbuf);
730 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
731 g_object_unref (pixbuf);
739 replace_with_attachments (ModestMsgEditWindow *self, GList *attachments)
741 ModestMsgEditWindowPrivate *priv;
744 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
746 for (node = attachments; node != NULL; node = g_list_next (node)) {
747 TnyMimePart *part = (TnyMimePart *) node->data;
748 const gchar *cid = tny_mime_part_get_content_id (part);
749 const gchar *mime_type = tny_mime_part_get_content_type (part);
750 if ((cid != NULL)&&(mime_type != NULL)) {
751 TnyStream *stream = tny_mime_part_get_stream (part);
752 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
753 g_object_unref (stream);
755 if (pixbuf != NULL) {
756 /* wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf); */
757 g_object_unref (pixbuf);
764 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
767 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
769 for (node = attachments; node != NULL; node = g_list_next (node)) {
770 TnyMimePart *part = (TnyMimePart *) node->data;
771 const gchar *cid = tny_mime_part_get_content_id (part);
773 char *invalid = NULL;
774 gint int_cid = strtol (cid, &invalid, 10);
775 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
776 priv->last_cid = int_cid;
784 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
787 const gchar *to, *cc, *bcc, *subject;
789 ModestMsgEditWindowPrivate *priv;
791 TnyHeaderFlags priority_flags;
792 TnyFolder *msg_folder;
793 gboolean is_html = FALSE;
795 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
796 g_return_if_fail (TNY_IS_MSG (msg));
798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
800 header = tny_msg_get_header (msg);
801 to = tny_header_get_to (header);
802 cc = tny_header_get_cc (header);
803 bcc = tny_header_get_bcc (header);
804 subject = tny_header_get_subject (header);
805 priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
808 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
810 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
811 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
812 gtk_widget_show (priv->cc_caption);
813 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
814 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
815 gtk_widget_hide (priv->cc_caption);
818 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
819 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
820 gtk_widget_show (priv->bcc_caption);
821 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
822 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
823 gtk_widget_hide (priv->bcc_caption);
826 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
827 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
830 update_window_title (self);
832 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
833 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
835 if ((body == NULL)||(body[0] == '\0')) {
837 body = modest_text_utils_convert_to_html ("");
840 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
841 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
844 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
847 if (preserve_is_rich && !is_html) {
848 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
849 /* Get the default format required from configuration */
850 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
851 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
854 /* Set the default focus depending on having already a To: field or not */
855 if ((!to)||(*to == '\0')) {
856 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
858 gtk_widget_grab_focus (priv->msg_body);
861 /* TODO: lower priority, select in the From: combo to the
862 value that comes from msg <- not sure, should it be
865 /* Add attachments to the view */
866 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
867 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
868 if (priv->attachments == NULL) {
869 gtk_widget_hide (priv->attachments_caption);
871 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
872 gtk_widget_show_all (priv->attachments_caption);
873 replace_with_attachments (self, priv->attachments);
875 update_last_cid (self, priv->attachments);
877 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
879 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
880 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
882 reset_modified (self);
884 update_dimmed (self);
885 text_buffer_can_undo (priv->text_buffer, FALSE, self);
886 text_buffer_can_redo (priv->text_buffer, FALSE, self);
889 g_free (priv->msg_uid);
890 priv->msg_uid = NULL;
893 /* we should set a reference to the incoming message if it is a draft */
894 msg_folder = tny_msg_get_folder (msg);
896 if (modest_tny_folder_is_local_folder (msg_folder)) {
897 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
898 if (type == TNY_FOLDER_TYPE_DRAFTS)
899 priv->draft_msg = g_object_ref(msg);
900 if (type == TNY_FOLDER_TYPE_OUTBOX)
901 priv->outbox_msg = g_object_ref(msg);
902 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
904 g_object_unref (msg_folder);
909 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
912 GList *item_children, *node;
913 GtkWidget *bin_child;
915 bin_child = gtk_bin_get_child (GTK_BIN(item));
917 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
919 for (node = item_children; node != NULL; node = g_list_next (node)) {
920 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
921 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
924 g_list_free (item_children);
928 menu_tool_button_dont_expand (GtkMenuToolButton *item)
931 GList *item_children, *node;
933 box = gtk_bin_get_child (GTK_BIN (item));
934 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
935 item_children = gtk_container_get_children (GTK_CONTAINER (box));
937 for (node = item_children; node != NULL; node = g_list_next (node)) {
938 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
939 if (GTK_IS_TOGGLE_BUTTON (node->data))
940 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
941 else if (GTK_IS_BUTTON (node->data))
942 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
944 g_list_free (item_children);
949 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
951 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
952 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
953 GtkWidget *placeholder;
954 GtkWidget *tool_item;
959 GtkWidget *sizes_menu;
960 GtkWidget *fonts_menu;
961 GSList *radio_group = NULL;
966 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
967 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
969 /* should we hide the toolbar? */
970 if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
971 gtk_widget_hide (parent_priv->toolbar);
973 /* Font color placeholder */
974 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
975 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
978 tool_item = GTK_WIDGET (gtk_tool_item_new ());
979 priv->font_color_button = hildon_color_button_new ();
980 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
981 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
982 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
983 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
984 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
985 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
986 g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
988 /* Font size and face placeholder */
989 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
990 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
992 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
993 priv->size_tool_button_label = gtk_label_new (NULL);
994 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
995 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
996 size_text,"</span>", NULL);
997 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
999 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1000 sizes_menu = gtk_menu_new ();
1001 priv->size_items_group = NULL;
1003 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1004 GtkWidget *size_menu_item;
1006 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1007 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1008 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1009 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1010 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1011 gtk_widget_show (size_menu_item);
1013 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1017 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1018 GtkWidget *item = (GtkWidget *) node->data;
1019 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1023 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1024 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1025 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1026 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1027 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1028 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1029 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1030 priv->font_size_toolitem = tool_item;
1033 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1034 priv->font_tool_button_label = gtk_label_new (NULL);
1035 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1036 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1038 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1039 fonts_menu = gtk_menu_new ();
1040 priv->font_items_group = NULL;
1042 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1043 GtkWidget *font_menu_item;
1044 GtkWidget *child_label;
1046 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1047 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1048 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1049 wp_get_font_name (font_index), "</span>", NULL);
1050 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1053 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1054 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1055 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1056 gtk_widget_show (font_menu_item);
1058 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1061 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1062 GtkWidget *item = (GtkWidget *) node->data;
1063 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1066 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1067 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1068 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1069 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1070 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1071 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1072 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1073 priv->font_face_toolitem = tool_item;
1075 /* Set expand and homogeneous for remaining items */
1076 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1077 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1078 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1079 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1080 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1081 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1082 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1083 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1084 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1092 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1095 ModestWindowPrivate *parent_priv;
1096 ModestMsgEditWindowPrivate *priv;
1097 GtkActionGroup *action_group;
1098 GError *error = NULL;
1099 GdkPixbuf *window_icon = NULL;
1102 gboolean prefer_formatted;
1104 ModestPair *account_pair = NULL;
1106 g_return_val_if_fail (msg, NULL);
1107 g_return_val_if_fail (account_name, NULL);
1109 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1111 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1112 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1114 parent_priv->ui_manager = gtk_ui_manager_new();
1115 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1116 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1118 /* Add common actions */
1119 gtk_action_group_add_actions (action_group,
1120 modest_msg_edit_action_entries,
1121 G_N_ELEMENTS (modest_msg_edit_action_entries),
1123 gtk_action_group_add_toggle_actions (action_group,
1124 modest_msg_edit_toggle_action_entries,
1125 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1127 gtk_action_group_add_radio_actions (action_group,
1128 modest_msg_edit_alignment_radio_action_entries,
1129 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1131 G_CALLBACK (modest_ui_actions_on_change_justify),
1133 gtk_action_group_add_radio_actions (action_group,
1134 modest_msg_edit_zoom_action_entries,
1135 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1137 G_CALLBACK (modest_ui_actions_on_change_zoom),
1139 gtk_action_group_add_radio_actions (action_group,
1140 modest_msg_edit_priority_action_entries,
1141 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1143 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1145 gtk_action_group_add_radio_actions (action_group,
1146 modest_msg_edit_file_format_action_entries,
1147 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1148 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1149 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1151 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1152 g_object_unref (action_group);
1154 /* Load the UI definition */
1155 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1157 if (error != NULL) {
1158 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1159 g_clear_error (&error);
1162 /* Add accelerators */
1163 gtk_window_add_accel_group (GTK_WINDOW (obj),
1164 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1167 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1168 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1171 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1173 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1175 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1177 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1178 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1180 setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
1182 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1183 if (account_pair != NULL)
1184 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1186 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1188 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1190 /* Set window icon */
1191 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1193 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1194 g_object_unref (window_icon);
1197 /* Dim at start clipboard actions */
1198 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1199 gtk_action_set_sensitive (action, FALSE);
1200 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1201 gtk_action_set_sensitive (action, FALSE);
1202 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1203 gtk_action_set_sensitive (action, FALSE);
1205 /* Update select all */
1206 update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1207 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
1208 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
1209 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
1210 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
1212 /* set initial state of cc and bcc */
1213 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1214 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1215 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1216 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1217 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1218 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1220 /* Setup the file format */
1221 conf = modest_runtime_get_conf ();
1222 prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
1224 g_clear_error (&error);
1225 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
1227 file_format = (prefer_formatted) ?
1228 MODEST_FILE_FORMAT_FORMATTED_TEXT :
1229 MODEST_FILE_FORMAT_PLAIN_TEXT;
1230 modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
1232 update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1233 priv->update_caption_visibility = TRUE;
1235 reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1237 return (ModestWindow*) obj;
1241 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1243 GString **string_buffer = (GString **) user_data;
1245 *string_buffer = g_string_append (*string_buffer, buffer);
1251 * @result: A new string which should be freed with g_free().
1254 get_formatted_data (ModestMsgEditWindow *edit_window)
1256 ModestMsgEditWindowPrivate *priv;
1257 GString *string_buffer = g_string_new ("");
1259 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1261 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1263 return g_string_free (string_buffer, FALSE);
1268 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1271 const gchar *account_name;
1272 ModestMsgEditWindowPrivate *priv;
1274 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1276 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1278 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1279 g_return_val_if_fail (account_name, NULL);
1282 /* don't free these (except from) */
1283 data = g_slice_new0 (MsgData);
1284 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1286 data->account_name = g_strdup (account_name);
1287 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1288 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1289 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1290 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1291 if (priv->draft_msg) {
1292 data->draft_msg = g_object_ref (priv->draft_msg);
1293 } else if (priv->outbox_msg) {
1294 data->draft_msg = g_object_ref (priv->outbox_msg);
1296 data->draft_msg = NULL;
1299 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1301 gtk_text_buffer_get_bounds (buf, &b, &e);
1302 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1304 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1305 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1307 data->html_body = NULL;
1309 /* deep-copy the data */
1310 GList *cursor = priv->attachments;
1311 data->attachments = NULL;
1313 if (!(TNY_IS_MIME_PART(cursor->data))) {
1314 g_warning ("strange data in attachment list");
1315 cursor = g_list_next (cursor);
1318 data->attachments = g_list_append (data->attachments,
1319 g_object_ref (cursor->data));
1320 cursor = g_list_next (cursor);
1323 data->priority_flags = priv->priority_flags;
1330 unref_gobject (GObject *obj, gpointer data)
1332 if (!G_IS_OBJECT(obj))
1334 g_object_unref (obj);
1338 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1341 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1349 g_free (data->subject);
1350 g_free (data->plain_body);
1351 g_free (data->html_body);
1352 g_free (data->account_name);
1354 if (data->draft_msg != NULL) {
1355 g_object_unref (data->draft_msg);
1356 data->draft_msg = NULL;
1359 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1360 g_list_free (data->attachments);
1362 g_slice_free (MsgData, data);
1366 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1369 ModestMsgEditWindowPrivate *priv = NULL;
1370 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1372 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1374 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1376 return MODEST_MSG_EDIT_FORMAT_HTML;
1378 return MODEST_MSG_EDIT_FORMAT_TEXT;
1382 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1383 ModestMsgEditFormat format)
1385 ModestMsgEditWindowPrivate *priv;
1387 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1388 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1391 case MODEST_MSG_EDIT_FORMAT_HTML:
1392 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1394 case MODEST_MSG_EDIT_FORMAT_TEXT:
1395 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1398 g_return_if_reached ();
1402 ModestMsgEditFormatState *
1403 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1405 ModestMsgEditFormatState *format_state = NULL;
1406 ModestMsgEditWindowPrivate *priv;
1407 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1409 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1410 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1412 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1414 format_state = g_new0 (ModestMsgEditFormatState, 1);
1415 format_state->bold = buffer_format->bold&0x1;
1416 format_state->italics = buffer_format->italic&0x1;
1417 format_state->bullet = buffer_format->bullet&0x1;
1418 format_state->color = buffer_format->color;
1419 format_state->font_size = buffer_format->font_size;
1420 format_state->font_family = wp_get_font_name (buffer_format->font);
1421 format_state->justification = buffer_format->justification;
1422 g_free (buffer_format);
1424 return format_state;
1429 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1430 const ModestMsgEditFormatState *format_state)
1432 ModestMsgEditWindowPrivate *priv;
1433 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1434 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1435 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1436 g_return_if_fail (format_state != NULL);
1438 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1439 gtk_widget_grab_focus (priv->msg_body);
1440 buffer_format->bold = (format_state->bold != FALSE);
1441 buffer_format->italic = (format_state->italics != FALSE);
1442 buffer_format->color = format_state->color;
1443 buffer_format->font_size = format_state->font_size;
1444 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1445 buffer_format->justification = format_state->justification;
1446 buffer_format->bullet = format_state->bullet;
1448 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1450 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1451 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1452 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1453 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1454 buffer_format->cs.font = (buffer_format->font != current_format->font);
1455 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1456 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1458 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1459 if (buffer_format->cs.bold) {
1460 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1462 if (buffer_format->cs.italic) {
1463 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1465 if (buffer_format->cs.color) {
1466 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1468 if (buffer_format->cs.font_size) {
1469 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1471 if (buffer_format->cs.justification) {
1472 switch (buffer_format->justification) {
1473 case GTK_JUSTIFY_LEFT:
1474 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1476 case GTK_JUSTIFY_CENTER:
1477 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1479 case GTK_JUSTIFY_RIGHT:
1480 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1487 if (buffer_format->cs.font) {
1488 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1490 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1491 if (buffer_format->cs.bullet) {
1492 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1494 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1496 g_free (current_format);
1501 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1503 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1505 ModestWindowPrivate *parent_priv;
1506 ModestMsgEditWindowPrivate *priv;
1507 GtkWidget *new_size_menuitem;
1508 GtkWidget *new_font_menuitem;
1510 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1511 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1513 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1514 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1515 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1516 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1518 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1519 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1520 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1523 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1525 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1526 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1528 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1529 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1531 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1532 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1534 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1535 G_CALLBACK (modest_msg_edit_window_color_button_change),
1537 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1538 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1539 G_CALLBACK (modest_msg_edit_window_color_button_change),
1542 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1543 buffer_format->font_size))->data);
1544 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1548 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1549 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1550 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1552 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1553 G_CALLBACK (modest_msg_edit_window_size_change),
1555 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1556 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1557 G_CALLBACK (modest_msg_edit_window_size_change),
1561 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1562 buffer_format->font))->data);
1563 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1567 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1568 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1569 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1571 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1572 G_CALLBACK (modest_msg_edit_window_font_change),
1574 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1575 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1576 G_CALLBACK (modest_msg_edit_window_font_change),
1580 g_free (buffer_format);
1586 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1589 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1590 ModestMsgEditWindowPrivate *priv;
1591 GtkWidget *dialog = NULL;
1593 const GdkColor *new_color = NULL;
1595 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1596 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1598 #ifdef MODEST_HILDON_VERSION_0
1599 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1600 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1602 dialog = hildon_color_chooser_new ();
1603 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1604 #endif /*MODEST_HILDON_VERSION_0*/
1605 g_free (buffer_format);
1607 response = gtk_dialog_run (GTK_DIALOG (dialog));
1609 case GTK_RESPONSE_OK: {
1610 #ifdef MODEST_HILDON_VERSION_0
1611 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1614 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1616 #endif /*MODEST_HILDON_VERSION_0*/
1623 gtk_widget_destroy (dialog);
1625 if (new_color != NULL)
1626 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1631 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1634 ModestMsgEditWindowPrivate *priv;
1635 GtkWidget *dialog = NULL;
1637 GdkColor *old_color = NULL;
1638 const GdkColor *new_color = NULL;
1640 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1641 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1643 #ifdef MODEST_HILDON_VERSION_0
1644 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1645 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1647 dialog = hildon_color_chooser_new ();
1648 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1649 #endif /*MODEST_HILDON_VERSION_9*/
1651 response = gtk_dialog_run (GTK_DIALOG (dialog));
1653 case GTK_RESPONSE_OK: {
1654 #ifdef MODEST_HILDON_VERSION_0
1655 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1658 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1660 #endif /*MODEST_HILDON_VERSION_0*/
1666 gtk_widget_destroy (dialog);
1668 if (new_color != NULL)
1669 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1673 static TnyStream* create_stream_for_uri (const gchar* uri)
1678 TnyStream *result = NULL;
1680 GnomeVFSHandle *handle = NULL;
1681 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1682 if (test == GNOME_VFS_OK) {
1683 /* Create the tinymail stream: */
1684 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1685 result = TNY_STREAM (tny_vfs_stream_new (handle));
1692 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1695 ModestMsgEditWindowPrivate *priv;
1696 GtkWidget *dialog = NULL;
1698 GSList *uris = NULL;
1699 GSList *uri_node = NULL;
1701 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1703 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1704 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1705 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1707 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1709 response = gtk_dialog_run (GTK_DIALOG (dialog));
1711 case GTK_RESPONSE_OK:
1712 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1717 gtk_widget_destroy (dialog);
1719 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1721 GnomeVFSHandle *handle = NULL;
1722 GnomeVFSResult result;
1723 GtkTextIter position;
1724 GtkTextMark *insert_mark;
1726 uri = (const gchar *) uri_node->data;
1727 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1728 if (result == GNOME_VFS_OK) {
1730 GnomeVFSFileInfo info;
1731 gchar *filename, *basename, *escaped_filename;
1732 TnyMimePart *mime_part;
1734 const gchar *mime_type = NULL;
1735 GnomeVFSURI *vfs_uri;
1737 vfs_uri = gnome_vfs_uri_new (uri);
1739 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1740 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1741 g_free (escaped_filename);
1742 gnome_vfs_uri_unref (vfs_uri);
1744 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1745 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1747 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1749 mime_part = tny_platform_factory_new_mime_part
1750 (modest_runtime_get_platform_factory ());
1752 TnyStream *stream = create_stream_for_uri (uri);
1753 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1755 content_id = g_strdup_printf ("%d", priv->last_cid);
1756 tny_mime_part_set_content_id (mime_part, content_id);
1757 g_free (content_id);
1760 basename = g_path_get_basename (filename);
1761 tny_mime_part_set_filename (mime_part, basename);
1764 pixbuf = pixbuf_from_stream (stream, mime_type);
1766 if (pixbuf != NULL) {
1767 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1768 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1769 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1772 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1773 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1775 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1776 gtk_widget_show_all (priv->attachments_caption);
1777 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1787 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1790 ModestMsgEditWindowPrivate *priv;
1791 GtkWidget *dialog = NULL;
1793 GSList *uris = NULL;
1796 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1798 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1799 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1800 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1802 response = gtk_dialog_run (GTK_DIALOG (dialog));
1804 case GTK_RESPONSE_OK:
1805 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1810 gtk_widget_destroy (dialog);
1812 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1813 const gchar *uri = (const gchar *) uri_node->data;
1814 modest_msg_edit_window_attach_file_one (window, uri);
1816 g_slist_foreach (uris, (GFunc) g_free, NULL);
1817 g_slist_free (uris);
1821 modest_msg_edit_window_attach_file_one (
1822 ModestMsgEditWindow *window,
1825 g_return_if_fail (window);
1826 g_return_if_fail (uri);
1828 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1831 GnomeVFSHandle *handle = NULL;
1832 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1833 if (result == GNOME_VFS_OK) {
1834 TnyMimePart *mime_part;
1836 const gchar *mime_type = NULL;
1838 gchar *escaped_filename;
1841 GnomeVFSFileInfo info;
1842 GnomeVFSURI *vfs_uri;
1844 vfs_uri = gnome_vfs_uri_new (uri);
1847 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1848 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1849 g_free (escaped_filename);
1850 gnome_vfs_uri_unref (vfs_uri);
1852 if (gnome_vfs_get_file_info (uri,
1854 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1855 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1857 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1858 mime_part = tny_platform_factory_new_mime_part
1859 (modest_runtime_get_platform_factory ());
1860 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1862 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1864 content_id = g_strdup_printf ("%d", priv->last_cid);
1865 tny_mime_part_set_content_id (mime_part, content_id);
1866 g_free (content_id);
1869 basename = g_path_get_basename (filename);
1870 tny_mime_part_set_filename (mime_part, basename);
1873 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1874 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1876 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1877 gtk_widget_show_all (priv->attachments_caption);
1878 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1884 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1887 ModestMsgEditWindowPrivate *priv;
1888 gboolean clean_list = FALSE;
1890 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1891 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1893 if (att_list == NULL) {
1894 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1898 if (att_list == NULL) {
1899 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1901 GtkWidget *confirmation_dialog = NULL;
1902 gboolean dialog_response;
1904 gchar *message = NULL;
1905 const gchar *filename = NULL;
1907 if (att_list->next == NULL) {
1908 filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1912 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1913 att_list->next == NULL), filename);
1914 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1916 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1917 gtk_widget_destroy (confirmation_dialog);
1918 if (!dialog_response) {
1920 g_list_free (att_list);
1923 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1925 for (node = att_list; node != NULL; node = g_list_next (node)) {
1926 TnyMimePart *mime_part = (TnyMimePart *) node->data;
1927 const gchar *att_id;
1928 priv->attachments = g_list_remove (priv->attachments, mime_part);
1930 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1932 if (priv->attachments == NULL)
1933 gtk_widget_hide (priv->attachments_caption);
1934 att_id = tny_mime_part_get_content_id (mime_part);
1936 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1938 g_object_unref (mime_part);
1939 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1944 g_list_free (att_list);
1948 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1951 ModestMsgEditWindowPrivate *priv;
1952 GdkColor *new_color;
1953 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1955 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1956 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1959 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1961 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1963 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1965 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1970 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1973 ModestMsgEditWindowPrivate *priv;
1974 gint new_size_index;
1975 ModestMsgEditWindow *window;
1978 window = MODEST_MSG_EDIT_WINDOW (userdata);
1979 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1980 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1982 if (gtk_check_menu_item_get_active (menu_item)) {
1984 WPTextBufferFormat format;
1986 memset (&format, 0, sizeof (format));
1987 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
1989 label = gtk_bin_get_child (GTK_BIN (menu_item));
1991 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1992 format.cs.font_size = TRUE;
1993 format.cs.text_position = TRUE;
1994 format.cs.font = TRUE;
1995 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1996 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
1998 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1999 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2000 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2002 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2003 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2004 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2010 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2013 ModestMsgEditWindowPrivate *priv;
2014 gint new_font_index;
2015 ModestMsgEditWindow *window;
2018 window = MODEST_MSG_EDIT_WINDOW (userdata);
2019 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2020 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2022 if (gtk_check_menu_item_get_active (menu_item)) {
2025 label = gtk_bin_get_child (GTK_BIN (menu_item));
2027 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2029 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2030 (gpointer) new_font_index))
2031 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2033 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2034 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2035 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2041 modest_msg_edit_window_set_zoom (ModestWindow *window,
2044 ModestMsgEditWindowPrivate *priv;
2045 ModestWindowPrivate *parent_priv;
2046 GtkRadioAction *zoom_radio_action;
2048 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2050 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2051 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2052 priv->zoom_level = zoom;
2053 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2055 /* Zoom level menu options should be updated with the current zoom level */
2056 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2057 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2058 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2059 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2060 /* FIXME: Not availible before Gtk 2.10 */
2062 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2067 modest_msg_edit_window_get_zoom (ModestWindow *window)
2069 ModestMsgEditWindowPrivate *priv;
2071 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2073 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2074 return priv->zoom_level;
2078 zoom_allowed (ModestMsgEditWindow *window)
2082 focus = gtk_window_get_focus (GTK_WINDOW (window));
2083 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2087 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2089 ModestWindowPrivate *parent_priv;
2090 GtkRadioAction *zoom_radio_action;
2091 GSList *group, *node;
2093 /* First we check if the text view is focused. If not, zooming is not allowed */
2094 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2095 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2099 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2100 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2101 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2103 group = gtk_radio_action_get_group (zoom_radio_action);
2105 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2106 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2110 for (node = group; node != NULL; node = g_slist_next (node)) {
2111 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2112 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2120 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2122 ModestWindowPrivate *parent_priv;
2123 GtkRadioAction *zoom_radio_action;
2124 GSList *group, *node;
2126 /* First we check if the text view is focused. If not, zooming is not allowed */
2127 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2128 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2132 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2133 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2134 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2136 group = gtk_radio_action_get_group (zoom_radio_action);
2138 for (node = group; node != NULL; node = g_slist_next (node)) {
2139 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2140 if (node->next != NULL) {
2141 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2144 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2152 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2154 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2155 ModestWindowPrivate *parent_priv;
2156 ModestWindowMgr *mgr;
2157 gboolean is_fullscreen;
2158 GtkAction *fs_toggle_action;
2161 mgr = modest_runtime_get_window_mgr ();
2162 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2164 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2166 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2167 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2168 if (is_fullscreen != active)
2169 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2177 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
2179 ModestWindowPrivate *parent_priv;
2180 GtkAction *fs_toggle_action;
2183 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2185 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2186 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
2187 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
2191 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2194 ModestMsgEditWindowPrivate *priv = NULL;
2195 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2197 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2198 if (!priv->update_caption_visibility)
2201 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2203 gtk_widget_show (priv->cc_caption);
2205 gtk_widget_hide (priv->cc_caption);
2207 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2211 modest_msg_edit_window_show_bcc (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->bcc_caption, TRUE);
2223 gtk_widget_show (priv->bcc_caption);
2225 gtk_widget_hide (priv->bcc_caption);
2227 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2231 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2232 ModestRecptEditor *editor)
2234 ModestMsgEditWindowPrivate *priv;
2236 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2237 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2238 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2240 if (editor == NULL) {
2241 GtkWidget *view_focus;
2242 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2244 /* This code should be kept in sync with ModestRecptEditor. The
2245 textview inside the recpt editor is the one that really gets the
2246 focus. As it's inside a scrolled window, and this one inside the
2247 hbox recpt editor inherits from, we'll need to go up in the
2248 hierarchy to know if the text view is part of the recpt editor
2249 or if it's a different text entry */
2251 if (gtk_widget_get_parent (view_focus)) {
2252 GtkWidget *first_parent;
2254 first_parent = gtk_widget_get_parent (view_focus);
2255 if (gtk_widget_get_parent (first_parent) &&
2256 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2257 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2262 editor = MODEST_RECPT_EDITOR (priv->to_field);
2266 modest_address_book_select_addresses (editor);
2271 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2273 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2275 modest_msg_edit_window_open_addressbook (window, NULL);
2279 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2280 gboolean show_toolbar)
2282 ModestWindowPrivate *parent_priv;
2284 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2285 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2287 /* FIXME: we can not just use the code of
2288 modest_msg_edit_window_setup_toolbar because it has a
2289 mixture of both initialization and creation code. */
2292 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2294 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2298 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2299 TnyHeaderFlags priority_flags)
2301 ModestMsgEditWindowPrivate *priv;
2302 ModestWindowPrivate *parent_priv;
2304 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2306 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2307 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2308 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2310 if (priv->priority_flags != priority_flags) {
2311 GtkAction *priority_action = NULL;
2313 priv->priority_flags = priority_flags;
2315 switch (priority_flags) {
2316 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2317 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2318 gtk_widget_show (priv->priority_icon);
2319 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2320 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2322 case TNY_HEADER_FLAG_LOW_PRIORITY:
2323 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2324 gtk_widget_show (priv->priority_icon);
2325 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2326 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2329 gtk_widget_hide (priv->priority_icon);
2330 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2331 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2334 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2335 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2340 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2343 ModestMsgEditWindowPrivate *priv;
2344 ModestWindowPrivate *parent_priv;
2345 gint current_format;
2347 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2349 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2350 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2352 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2353 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2355 if (current_format != file_format) {
2356 switch (file_format) {
2357 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2358 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2360 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2364 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2365 response = gtk_dialog_run (GTK_DIALOG (dialog));
2366 gtk_widget_destroy (dialog);
2367 if (response == GTK_RESPONSE_OK) {
2368 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2370 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2371 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2376 update_dimmed (window);
2381 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2384 ModestMsgEditWindowPrivate *priv;
2385 WPTextBufferFormat oldfmt, fmt;
2386 gint old_position = 0;
2390 GdkColor *color = NULL;
2391 gboolean bold, bold_set, italic, italic_set;
2392 gboolean underline, underline_set;
2393 gboolean strikethrough, strikethrough_set;
2394 gboolean position_set;
2395 gboolean font_size_set, font_set, color_set;
2398 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2399 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2401 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2403 /* First we get the currently selected font information */
2404 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2405 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2407 switch (oldfmt.text_position) {
2408 case TEXT_POSITION_NORMAL:
2411 case TEXT_POSITION_SUPERSCRIPT:
2419 g_object_set (G_OBJECT (dialog),
2420 "bold", oldfmt.bold != FALSE,
2421 "bold-set", !oldfmt.cs.bold,
2422 "underline", oldfmt.underline != FALSE,
2423 "underline-set", !oldfmt.cs.underline,
2424 "italic", oldfmt.italic != FALSE,
2425 "italic-set", !oldfmt.cs.italic,
2426 "strikethrough", oldfmt.strikethrough != FALSE,
2427 "strikethrough-set", !oldfmt.cs.strikethrough,
2428 "color", &oldfmt.color,
2429 "color-set", !oldfmt.cs.color,
2430 "size", wp_font_size[oldfmt.font_size],
2431 "size-set", !oldfmt.cs.font_size,
2432 "position", old_position,
2433 "position-set", !oldfmt.cs.text_position,
2434 "family", wp_get_font_name (oldfmt.font),
2435 "family-set", !oldfmt.cs.font,
2438 gtk_widget_show_all (dialog);
2439 response = gtk_dialog_run (GTK_DIALOG (dialog));
2440 if (response == GTK_RESPONSE_OK) {
2442 g_object_get( dialog,
2444 "bold-set", &bold_set,
2445 "underline", &underline,
2446 "underline-set", &underline_set,
2448 "italic-set", &italic_set,
2449 "strikethrough", &strikethrough,
2450 "strikethrough-set", &strikethrough_set,
2452 "color-set", &color_set,
2454 "size-set", &font_size_set,
2455 "family", &font_name,
2456 "family-set", &font_set,
2457 "position", &position,
2458 "position-set", &position_set,
2463 if (response == GTK_RESPONSE_OK) {
2464 memset(&fmt, 0, sizeof(fmt));
2470 fmt.italic = italic;
2471 fmt.cs.italic = TRUE;
2473 if (underline_set) {
2474 fmt.underline = underline;
2475 fmt.cs.underline = TRUE;
2477 if (strikethrough_set) {
2478 fmt.strikethrough = strikethrough;
2479 fmt.cs.strikethrough = TRUE;
2484 ? TEXT_POSITION_NORMAL
2485 : ( ( position == 1 )
2486 ? TEXT_POSITION_SUPERSCRIPT
2487 : TEXT_POSITION_SUBSCRIPT );
2488 fmt.cs.text_position = TRUE;
2492 fmt.cs.color = TRUE;
2495 fmt.font = wp_get_font_index(font_name,
2500 if (font_size_set) {
2501 fmt.font_size = wp_get_font_size_index(
2502 font_size, DEFAULT_FONT_SIZE);
2503 fmt.cs.font_size = TRUE;
2505 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2507 gtk_widget_destroy (dialog);
2509 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2513 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2515 ModestMsgEditWindowPrivate *priv;
2517 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2518 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2520 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2522 update_dimmed (window);
2527 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2529 ModestMsgEditWindowPrivate *priv;
2531 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2532 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2534 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2536 update_dimmed (window);
2541 update_dimmed (ModestMsgEditWindow *window)
2543 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2544 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2548 gboolean editor_focused;
2550 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2551 editor_focused = gtk_widget_is_focus (priv->msg_body);
2553 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2554 gtk_action_set_sensitive (action, rich_text && editor_focused);
2555 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2556 /* gtk_action_set_sensitive (action, rich_text && editor_focused); */
2557 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2558 gtk_action_set_sensitive (action, rich_text && editor_focused);
2559 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2560 gtk_action_set_sensitive (action, rich_text && editor_focused);
2561 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2562 gtk_action_set_sensitive (action, rich_text && editor_focused);
2563 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2564 gtk_action_set_sensitive (action, rich_text && editor_focused);
2565 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2566 gtk_action_set_sensitive (action, rich_text && editor_focused);
2567 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2568 gtk_action_set_sensitive (action, rich_text && editor_focused);
2569 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2570 gtk_action_set_sensitive (action, rich_text && editor_focused);
2571 widget = priv->font_color_button;
2572 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2573 widget = priv->font_size_toolitem;
2574 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2575 widget = priv->font_face_toolitem;
2576 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2580 setup_insensitive_handlers (ModestMsgEditWindow *window)
2582 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2583 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2586 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2587 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2588 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2589 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2590 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2591 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2592 widget = priv->font_color_button;
2593 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2594 widget = priv->font_size_toolitem;
2595 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2596 widget = priv->font_face_toolitem;
2597 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2602 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2604 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2607 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2608 gtk_action_set_sensitive (action, can_undo);
2612 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2614 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2617 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/RedoMenu");
2618 gtk_action_set_sensitive (action, can_redo);
2622 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2625 GtkTextIter match_start, match_end;
2627 if (image_id == NULL)
2630 gtk_text_buffer_get_start_iter (buffer, &iter);
2632 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2633 GSList *tags = gtk_text_iter_get_tags (&match_start);
2635 for (node = tags; node != NULL; node = g_slist_next (node)) {
2636 GtkTextTag *tag = (GtkTextTag *) node->data;
2637 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2638 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2639 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2641 offset = gtk_text_iter_get_offset (&match_start);
2642 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2643 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2647 gtk_text_iter_forward_char (&iter);
2652 message_is_empty (ModestMsgEditWindow *window)
2654 ModestMsgEditWindowPrivate *priv = NULL;
2656 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2657 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2659 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2660 * so we can ignore markup.
2662 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2665 count = gtk_text_buffer_get_char_count (buf);
2671 msg_body_focus (GtkWidget *focus,
2672 GdkEventFocus *event,
2676 update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2681 recpt_field_changed (GtkTextBuffer *buffer,
2682 ModestMsgEditWindow *editor)
2684 update_send_dimming (editor);
2688 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2690 update_send_dimming (editor);
2694 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2696 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2697 const gchar *subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2698 if (message_is_empty(editor) || (subject == NULL || subject[0] == '\0')) {
2699 hildon_banner_show_information (NULL, NULL, _("mcen_ib_subject_or_body_not_modified"));
2701 hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2706 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2708 gboolean rich_text, editor_focused;
2710 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2711 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2712 editor_focused = gtk_widget_is_focus (priv->msg_body);
2715 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2716 else if (!editor_focused)
2717 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2721 reset_modified (ModestMsgEditWindow *editor)
2723 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2724 GtkTextBuffer *buffer;
2726 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2727 gtk_text_buffer_set_modified (buffer, FALSE);
2728 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2729 gtk_text_buffer_set_modified (buffer, FALSE);
2730 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2731 gtk_text_buffer_set_modified (buffer, FALSE);
2732 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2736 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2738 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2739 GtkTextBuffer *buffer;
2741 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2742 if (gtk_text_buffer_get_modified (buffer))
2744 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2745 if (gtk_text_buffer_get_modified (buffer))
2747 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2748 if (gtk_text_buffer_get_modified (buffer))
2750 if (gtk_text_buffer_get_modified (priv->text_buffer))
2760 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2762 ModestMsgEditWindowPrivate *priv = NULL;
2764 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2765 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2767 /* check if there's no recipient added */
2768 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2769 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2770 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2771 /* no recipient contents, then select contacts */
2772 modest_msg_edit_window_open_addressbook (window, NULL);
2776 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2777 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2780 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2781 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2784 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2785 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2789 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2790 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2791 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2798 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2799 ModestMsgEditWindow *window)
2801 modest_msg_edit_window_offer_attach_file (window);
2805 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2807 ModestMsgEditWindow *window)
2809 if (!GTK_WIDGET_VISIBLE (window))
2812 update_remove_attachment_dimming (window);
2813 update_copy_cut_dimming (window);
2814 update_paste_dimming (window);
2818 update_window_title (ModestMsgEditWindow *window)
2820 ModestMsgEditWindowPrivate *priv = NULL;
2821 const gchar *subject;
2823 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2824 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2825 if (subject == NULL || subject[0] == '\0')
2826 subject = _("mail_va_new_email");
2828 gtk_window_set_title (GTK_WINDOW (window), subject);
2833 subject_field_changed (GtkEditable *editable,
2834 ModestMsgEditWindow *window)
2836 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2837 update_window_title (window);
2838 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2839 update_send_dimming (window);
2843 subject_field_insert_text (GtkEditable *editable,
2845 gint new_text_length,
2847 ModestMsgEditWindow *window)
2849 GString *result = g_string_new ("");
2851 gint result_len = 0;
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 g_string_free (result, TRUE);
2882 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2885 ModestMsgEditWindowPrivate *priv = NULL;
2887 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2888 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2890 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2893 gtk_widget_show_all (priv->find_toolbar);
2894 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2896 gtk_widget_hide_all (priv->find_toolbar);
2897 gtk_widget_grab_focus (priv->msg_body);
2903 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2905 GtkTextIter *match_start,
2906 GtkTextIter *match_end)
2908 GtkTextIter end_iter;
2909 gchar *str_casefold;
2912 gchar *range_casefold;
2915 gboolean result = FALSE;
2922 gtk_text_iter_forward_to_end (&end_iter);
2924 str_casefold = g_utf8_casefold (str, -1);
2925 str_chars_n = strlen (str);
2927 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2928 range_casefold = g_utf8_casefold (range_text, -1);
2929 range_chars_n = strlen (range_casefold);
2931 if (range_chars_n < str_chars_n) {
2932 g_free (str_casefold);
2933 g_free (range_text);
2934 g_free (range_casefold);
2938 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2939 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2940 if (!g_utf8_collate (range_subtext, str_casefold)) {
2941 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2943 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2944 match_start, match_end, NULL);
2945 g_free (found_text);
2947 g_free (range_subtext);
2951 g_free (str_casefold);
2952 g_free (range_text);
2953 g_free (range_casefold);
2960 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2961 ModestMsgEditWindow *window)
2963 gchar *current_search = NULL;
2964 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2966 GtkTextIter selection_start, selection_end;
2967 GtkTextIter match_start, match_end;
2968 gboolean continue_search = FALSE;
2970 if (message_is_empty (window)) {
2971 g_free (priv->last_search);
2972 priv->last_search = NULL;
2973 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
2977 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
2978 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2979 g_free (current_search);
2980 g_free (priv->last_search);
2981 priv->last_search = NULL;
2982 /* Information banner about empty search */
2983 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
2987 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
2988 continue_search = TRUE;
2990 g_free (priv->last_search);
2991 priv->last_search = g_strdup (current_search);
2994 if (continue_search) {
2995 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
2996 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
2997 &match_start, &match_end);
2999 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3001 GtkTextIter buffer_start;
3002 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3003 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3004 &match_start, &match_end);
3006 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3009 /* Mark as selected the string found in search */
3011 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3012 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3014 g_free (priv->last_search);
3015 priv->last_search = NULL;
3017 g_free (current_search);
3021 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3022 ModestMsgEditWindow *window)
3024 GtkToggleAction *toggle;
3025 ModestWindowPrivate *parent_priv;
3026 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3028 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3029 gtk_toggle_action_set_active (toggle, FALSE);
3033 update_remove_attachment_dimming (ModestMsgEditWindow *window)
3035 ModestWindowPrivate *parent_priv;
3036 ModestMsgEditWindowPrivate *priv;
3038 GList *selected_attachments = NULL;
3039 gint n_att_selected = 0;
3041 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3042 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3044 selected_attachments = modest_attachments_view_get_selection (
3045 MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
3046 n_att_selected = g_list_length (selected_attachments);
3047 g_list_free (selected_attachments);
3049 action = gtk_ui_manager_get_action (
3050 parent_priv->ui_manager,
3051 "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
3052 gtk_action_set_sensitive (action, n_att_selected == 1);
3056 update_copy_cut_dimming (ModestMsgEditWindow *window)
3058 ModestWindowPrivate *parent_priv = NULL;
3059 ModestMsgEditWindowPrivate *priv = NULL;
3060 GtkClipboard *clipboard = NULL;
3061 GtkAction *action = NULL;
3062 gboolean has_selection = FALSE;
3063 GtkWidget *focused = NULL;
3064 gchar *selection = NULL;
3066 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3067 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3068 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3069 focused = gtk_window_get_focus (GTK_WINDOW (window));
3071 has_selection = gtk_clipboard_wait_for_targets (clipboard, NULL, NULL);
3073 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
3074 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3075 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
3076 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3078 if (selection != NULL)
3083 update_paste_dimming (ModestMsgEditWindow *window)
3085 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3086 GtkAction *action = NULL;
3087 GtkClipboard *clipboard = NULL;
3088 ModestEmailClipboard *e_clipboard;
3092 focused = gtk_window_get_focus (GTK_WINDOW (window));
3094 e_clipboard = modest_runtime_get_email_clipboard ();
3095 if (!modest_email_clipboard_cleared (e_clipboard)) {
3098 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3099 active = gtk_clipboard_wait_is_text_available (clipboard);
3103 if (MODEST_IS_ATTACHMENTS_VIEW (focused))
3107 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
3108 gtk_action_set_sensitive (action, active);
3113 update_select_all_dimming (ModestMsgEditWindow *window)
3116 gboolean dimmed = FALSE;
3118 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3120 focused = gtk_window_get_focus (GTK_WINDOW (window));
3121 if (GTK_IS_ENTRY (focused)) {
3122 const gchar *current_text;
3123 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
3124 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
3125 } else if (GTK_IS_TEXT_VIEW (focused)) {
3126 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
3127 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
3128 } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
3131 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
3132 gtk_action_set_sensitive (action, !dimmed);
3136 update_zoom_dimming (ModestMsgEditWindow *window)
3139 gboolean dimmed = FALSE;
3141 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3143 focused = gtk_window_get_focus (GTK_WINDOW (window));
3144 dimmed = ! WP_IS_TEXT_VIEW (focused);
3145 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
3146 gtk_action_set_sensitive (action, !dimmed);
3150 update_send_dimming (ModestMsgEditWindow *window)
3152 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3153 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3154 GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
3155 const gchar *subject;
3156 gboolean dim = FALSE;
3159 to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
3160 cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
3161 bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
3162 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3164 dim = ((gtk_text_buffer_get_char_count (to_buffer) +
3165 gtk_text_buffer_get_char_count (cc_buffer) +
3166 gtk_text_buffer_get_char_count (bcc_buffer)) == 0)
3167 || (subject == NULL || subject[0] == '\0')
3168 || message_is_empty(window);
3170 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
3171 gtk_action_set_sensitive (action, !dim);
3172 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
3173 gtk_action_set_sensitive (action, !dim);
3177 edit_menu_activated (GtkAction *action,
3180 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3182 update_select_all_dimming (window);
3183 update_copy_cut_dimming (window);
3184 update_paste_dimming (window);
3187 view_menu_activated (GtkAction *action,
3190 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3192 update_zoom_dimming (window);
3196 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3198 ModestMsgEditWindowPrivate *priv;
3200 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3205 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3208 ModestMsgEditWindowPrivate *priv;
3210 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3216 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3219 ModestMsgEditWindowPrivate *priv;
3220 TnyHeader *header = NULL;
3222 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3223 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3225 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3226 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3228 if (priv->draft_msg != NULL) {
3229 header = tny_msg_get_header (priv->draft_msg);
3230 if (TNY_IS_HEADER (header)) {
3231 modest_window_mgr_unregister_header (mgr, header);
3233 g_object_unref (priv->draft_msg);
3236 if (draft != NULL) {
3237 g_object_ref (draft);
3238 header = tny_msg_get_header (draft);
3239 if (TNY_IS_HEADER (header))
3240 modest_window_mgr_register_header (mgr, header);
3241 if (priv->msg_uid) {
3242 g_free (priv->msg_uid);
3243 priv->msg_uid = NULL;
3245 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3248 priv->draft_msg = draft;
3252 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3253 GtkTextIter *start, GtkTextIter *end,
3256 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3257 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3260 if (tag == NULL+13) return;
3261 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3262 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3263 replace_with_attachments (window, priv->attachments);
3268 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3271 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3273 g_return_if_fail (TNY_IS_MIME_PART (part));
3274 priv->attachments = g_list_prepend (priv->attachments, part);
3275 g_object_ref (part);
3276 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3277 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3278 gtk_widget_show_all (priv->attachments_caption);
3279 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3283 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3285 ModestMsgEditWindowPrivate *priv;
3287 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3288 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3290 return priv->msg_uid;