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 /* Font color placeholder */
970 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
971 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
974 tool_item = GTK_WIDGET (gtk_tool_item_new ());
975 priv->font_color_button = hildon_color_button_new ();
976 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
977 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
978 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
979 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
980 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
981 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
982 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
984 G_CALLBACK (modest_msg_edit_window_color_button_change),
987 /* Font size and face placeholder */
988 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
989 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
991 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
992 priv->size_tool_button_label = gtk_label_new (NULL);
993 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
994 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
995 size_text,"</span>", NULL);
996 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
998 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
999 sizes_menu = gtk_menu_new ();
1000 priv->size_items_group = NULL;
1002 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1003 GtkWidget *size_menu_item;
1005 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1006 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1007 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1008 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1009 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1010 gtk_widget_show (size_menu_item);
1012 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1016 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1017 GtkWidget *item = (GtkWidget *) node->data;
1018 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1022 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1023 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1024 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1025 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1026 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1027 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1028 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1029 priv->font_size_toolitem = tool_item;
1032 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1033 priv->font_tool_button_label = gtk_label_new (NULL);
1034 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1035 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1037 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1038 fonts_menu = gtk_menu_new ();
1039 priv->font_items_group = NULL;
1041 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1042 GtkWidget *font_menu_item;
1043 GtkWidget *child_label;
1045 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1046 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1047 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1048 wp_get_font_name (font_index), "</span>", NULL);
1049 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1052 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1053 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1054 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1055 gtk_widget_show (font_menu_item);
1057 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1060 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1061 GtkWidget *item = (GtkWidget *) node->data;
1062 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1065 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1066 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1067 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1068 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1069 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1070 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1071 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1072 priv->font_face_toolitem = tool_item;
1074 /* Set expand and homogeneous for remaining items */
1075 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1076 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1077 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1078 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1079 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1080 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1081 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1082 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1083 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1085 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1086 will not show the tool items added to the placeholders) */
1087 gtk_widget_show_all (parent_priv->toolbar);
1089 /* Set the no show all *after* showing all items. We do not
1090 want the toolbar to be shown with a show all because it
1091 could go agains the gconf setting regarding showing or not
1092 the toolbar of the editor window */
1093 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1099 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1102 ModestWindowPrivate *parent_priv;
1103 ModestMsgEditWindowPrivate *priv;
1104 GtkActionGroup *action_group;
1105 GError *error = NULL;
1106 GdkPixbuf *window_icon = NULL;
1109 gboolean prefer_formatted;
1111 ModestPair *account_pair = NULL;
1113 g_return_val_if_fail (msg, NULL);
1114 g_return_val_if_fail (account_name, NULL);
1116 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1118 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1119 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1121 parent_priv->ui_manager = gtk_ui_manager_new();
1122 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1123 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1125 /* Add common actions */
1126 gtk_action_group_add_actions (action_group,
1127 modest_msg_edit_action_entries,
1128 G_N_ELEMENTS (modest_msg_edit_action_entries),
1130 gtk_action_group_add_toggle_actions (action_group,
1131 modest_msg_edit_toggle_action_entries,
1132 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1134 gtk_action_group_add_radio_actions (action_group,
1135 modest_msg_edit_alignment_radio_action_entries,
1136 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1138 G_CALLBACK (modest_ui_actions_on_change_justify),
1140 gtk_action_group_add_radio_actions (action_group,
1141 modest_msg_edit_zoom_action_entries,
1142 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1144 G_CALLBACK (modest_ui_actions_on_change_zoom),
1146 gtk_action_group_add_radio_actions (action_group,
1147 modest_msg_edit_priority_action_entries,
1148 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1150 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1152 gtk_action_group_add_radio_actions (action_group,
1153 modest_msg_edit_file_format_action_entries,
1154 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1155 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1156 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1158 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1159 g_object_unref (action_group);
1161 /* Load the UI definition */
1162 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1164 if (error != NULL) {
1165 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1166 g_clear_error (&error);
1169 /* Add accelerators */
1170 gtk_window_add_accel_group (GTK_WINDOW (obj),
1171 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1173 /* Menubar. Update the state of some toggles */
1174 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1175 conf = modest_runtime_get_conf ();
1176 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1177 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1178 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1179 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1180 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1181 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1182 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1183 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1185 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1188 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1190 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1192 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1194 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1195 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1197 setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
1199 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1200 if (account_pair != NULL)
1201 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1203 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1205 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1207 /* Set window icon */
1208 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1210 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1211 g_object_unref (window_icon);
1214 /* Dim at start clipboard actions */
1215 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1216 gtk_action_set_sensitive (action, FALSE);
1217 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1218 gtk_action_set_sensitive (action, FALSE);
1219 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1220 gtk_action_set_sensitive (action, FALSE);
1222 /* Update select all */
1223 update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1224 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
1225 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
1226 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
1227 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
1229 /* set initial state of cc and bcc */
1230 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1231 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1232 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1233 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1234 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1235 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1237 /* Setup the file format */
1238 conf = modest_runtime_get_conf ();
1239 prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
1241 g_clear_error (&error);
1242 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
1244 file_format = (prefer_formatted) ?
1245 MODEST_FILE_FORMAT_FORMATTED_TEXT :
1246 MODEST_FILE_FORMAT_PLAIN_TEXT;
1247 modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
1249 update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1250 priv->update_caption_visibility = TRUE;
1252 reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1254 return (ModestWindow*) obj;
1258 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1260 GString **string_buffer = (GString **) user_data;
1262 *string_buffer = g_string_append (*string_buffer, buffer);
1268 * @result: A new string which should be freed with g_free().
1271 get_formatted_data (ModestMsgEditWindow *edit_window)
1273 ModestMsgEditWindowPrivate *priv;
1274 GString *string_buffer = g_string_new ("");
1276 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1278 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1280 return g_string_free (string_buffer, FALSE);
1285 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1288 const gchar *account_name;
1289 ModestMsgEditWindowPrivate *priv;
1291 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1293 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1295 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1296 g_return_val_if_fail (account_name, NULL);
1299 /* don't free these (except from) */
1300 data = g_slice_new0 (MsgData);
1301 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1303 data->account_name = g_strdup (account_name);
1304 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1305 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1306 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1307 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1308 if (priv->draft_msg) {
1309 data->draft_msg = g_object_ref (priv->draft_msg);
1310 } else if (priv->outbox_msg) {
1311 data->draft_msg = g_object_ref (priv->outbox_msg);
1313 data->draft_msg = NULL;
1316 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1318 gtk_text_buffer_get_bounds (buf, &b, &e);
1319 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1321 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1322 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1324 data->html_body = NULL;
1326 /* deep-copy the data */
1327 GList *cursor = priv->attachments;
1328 data->attachments = NULL;
1330 if (!(TNY_IS_MIME_PART(cursor->data))) {
1331 g_warning ("strange data in attachment list");
1332 cursor = g_list_next (cursor);
1335 data->attachments = g_list_append (data->attachments,
1336 g_object_ref (cursor->data));
1337 cursor = g_list_next (cursor);
1340 data->priority_flags = priv->priority_flags;
1347 unref_gobject (GObject *obj, gpointer data)
1349 if (!G_IS_OBJECT(obj))
1351 g_object_unref (obj);
1355 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1358 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1366 g_free (data->subject);
1367 g_free (data->plain_body);
1368 g_free (data->html_body);
1369 g_free (data->account_name);
1371 if (data->draft_msg != NULL) {
1372 g_object_unref (data->draft_msg);
1373 data->draft_msg = NULL;
1376 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1377 g_list_free (data->attachments);
1379 g_slice_free (MsgData, data);
1383 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1386 ModestMsgEditWindowPrivate *priv = NULL;
1387 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1389 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1391 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1393 return MODEST_MSG_EDIT_FORMAT_HTML;
1395 return MODEST_MSG_EDIT_FORMAT_TEXT;
1399 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1400 ModestMsgEditFormat format)
1402 ModestMsgEditWindowPrivate *priv;
1404 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1405 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1408 case MODEST_MSG_EDIT_FORMAT_HTML:
1409 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1411 case MODEST_MSG_EDIT_FORMAT_TEXT:
1412 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1415 g_return_if_reached ();
1419 ModestMsgEditFormatState *
1420 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1422 ModestMsgEditFormatState *format_state = NULL;
1423 ModestMsgEditWindowPrivate *priv;
1424 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1426 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1427 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1429 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1431 format_state = g_new0 (ModestMsgEditFormatState, 1);
1432 format_state->bold = buffer_format->bold&0x1;
1433 format_state->italics = buffer_format->italic&0x1;
1434 format_state->bullet = buffer_format->bullet&0x1;
1435 format_state->color = buffer_format->color;
1436 format_state->font_size = buffer_format->font_size;
1437 format_state->font_family = wp_get_font_name (buffer_format->font);
1438 format_state->justification = buffer_format->justification;
1439 g_free (buffer_format);
1441 return format_state;
1446 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1447 const ModestMsgEditFormatState *format_state)
1449 ModestMsgEditWindowPrivate *priv;
1450 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1451 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1452 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1453 g_return_if_fail (format_state != NULL);
1455 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1456 gtk_widget_grab_focus (priv->msg_body);
1457 buffer_format->bold = (format_state->bold != FALSE);
1458 buffer_format->italic = (format_state->italics != FALSE);
1459 buffer_format->color = format_state->color;
1460 buffer_format->font_size = format_state->font_size;
1461 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1462 buffer_format->justification = format_state->justification;
1463 buffer_format->bullet = format_state->bullet;
1465 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1467 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1468 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1469 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1470 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1471 buffer_format->cs.font = (buffer_format->font != current_format->font);
1472 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1473 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1475 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1476 if (buffer_format->cs.bold) {
1477 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1479 if (buffer_format->cs.italic) {
1480 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1482 if (buffer_format->cs.color) {
1483 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1485 if (buffer_format->cs.font_size) {
1486 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1488 if (buffer_format->cs.justification) {
1489 switch (buffer_format->justification) {
1490 case GTK_JUSTIFY_LEFT:
1491 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1493 case GTK_JUSTIFY_CENTER:
1494 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1496 case GTK_JUSTIFY_RIGHT:
1497 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1504 if (buffer_format->cs.font) {
1505 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1507 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1508 if (buffer_format->cs.bullet) {
1509 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1511 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1513 g_free (current_format);
1518 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1520 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1522 ModestWindowPrivate *parent_priv;
1523 ModestMsgEditWindowPrivate *priv;
1524 GtkWidget *new_size_menuitem;
1525 GtkWidget *new_font_menuitem;
1527 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1528 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1530 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1531 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1532 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1533 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1535 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1536 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1537 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1540 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1542 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1543 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1545 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1546 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1548 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1549 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1551 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1552 G_CALLBACK (modest_msg_edit_window_color_button_change),
1554 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1555 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1556 G_CALLBACK (modest_msg_edit_window_color_button_change),
1559 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1560 buffer_format->font_size))->data);
1561 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1565 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1566 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1567 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1569 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1570 G_CALLBACK (modest_msg_edit_window_size_change),
1572 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1573 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1574 G_CALLBACK (modest_msg_edit_window_size_change),
1578 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1579 buffer_format->font))->data);
1580 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1584 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1585 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1586 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1588 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1589 G_CALLBACK (modest_msg_edit_window_font_change),
1591 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1592 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1593 G_CALLBACK (modest_msg_edit_window_font_change),
1597 g_free (buffer_format);
1603 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1606 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1607 ModestMsgEditWindowPrivate *priv;
1608 GtkWidget *dialog = NULL;
1610 const GdkColor *new_color = NULL;
1612 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1613 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1615 #ifdef MODEST_HILDON_VERSION_0
1616 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1617 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1619 dialog = hildon_color_chooser_new ();
1620 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1621 #endif /*MODEST_HILDON_VERSION_0*/
1622 g_free (buffer_format);
1624 response = gtk_dialog_run (GTK_DIALOG (dialog));
1626 case GTK_RESPONSE_OK: {
1627 #ifdef MODEST_HILDON_VERSION_0
1628 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1631 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1633 #endif /*MODEST_HILDON_VERSION_0*/
1640 gtk_widget_destroy (dialog);
1642 if (new_color != NULL)
1643 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1648 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1651 ModestMsgEditWindowPrivate *priv;
1652 GtkWidget *dialog = NULL;
1654 GdkColor *old_color = NULL;
1655 const GdkColor *new_color = NULL;
1657 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1658 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1660 #ifdef MODEST_HILDON_VERSION_0
1661 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1662 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1664 dialog = hildon_color_chooser_new ();
1665 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1666 #endif /*MODEST_HILDON_VERSION_9*/
1668 response = gtk_dialog_run (GTK_DIALOG (dialog));
1670 case GTK_RESPONSE_OK: {
1671 #ifdef MODEST_HILDON_VERSION_0
1672 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1675 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1677 #endif /*MODEST_HILDON_VERSION_0*/
1683 gtk_widget_destroy (dialog);
1685 if (new_color != NULL)
1686 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1690 static TnyStream* create_stream_for_uri (const gchar* uri)
1695 TnyStream *result = NULL;
1697 GnomeVFSHandle *handle = NULL;
1698 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1699 if (test == GNOME_VFS_OK) {
1700 /* Create the tinymail stream: */
1701 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1702 result = TNY_STREAM (tny_vfs_stream_new (handle));
1709 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1712 ModestMsgEditWindowPrivate *priv;
1713 GtkWidget *dialog = NULL;
1715 GSList *uris = NULL;
1716 GSList *uri_node = NULL;
1718 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1720 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1721 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1722 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1724 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1726 response = gtk_dialog_run (GTK_DIALOG (dialog));
1728 case GTK_RESPONSE_OK:
1729 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1734 gtk_widget_destroy (dialog);
1736 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1738 GnomeVFSHandle *handle = NULL;
1739 GnomeVFSResult result;
1740 GtkTextIter position;
1741 GtkTextMark *insert_mark;
1743 uri = (const gchar *) uri_node->data;
1744 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1745 if (result == GNOME_VFS_OK) {
1747 GnomeVFSFileInfo info;
1748 gchar *filename, *basename, *escaped_filename;
1749 TnyMimePart *mime_part;
1751 const gchar *mime_type = NULL;
1752 GnomeVFSURI *vfs_uri;
1754 vfs_uri = gnome_vfs_uri_new (uri);
1756 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1757 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1758 g_free (escaped_filename);
1759 gnome_vfs_uri_unref (vfs_uri);
1761 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1762 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1764 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1766 mime_part = tny_platform_factory_new_mime_part
1767 (modest_runtime_get_platform_factory ());
1769 TnyStream *stream = create_stream_for_uri (uri);
1770 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1772 content_id = g_strdup_printf ("%d", priv->last_cid);
1773 tny_mime_part_set_content_id (mime_part, content_id);
1774 g_free (content_id);
1777 basename = g_path_get_basename (filename);
1778 tny_mime_part_set_filename (mime_part, basename);
1781 pixbuf = pixbuf_from_stream (stream, mime_type);
1783 if (pixbuf != NULL) {
1784 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1785 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1786 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1789 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1790 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1792 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1793 gtk_widget_show_all (priv->attachments_caption);
1794 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1804 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1807 ModestMsgEditWindowPrivate *priv;
1808 GtkWidget *dialog = NULL;
1810 GSList *uris = NULL;
1813 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1815 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1816 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1817 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1819 response = gtk_dialog_run (GTK_DIALOG (dialog));
1821 case GTK_RESPONSE_OK:
1822 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1827 gtk_widget_destroy (dialog);
1829 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1830 const gchar *uri = (const gchar *) uri_node->data;
1831 modest_msg_edit_window_attach_file_one (window, uri);
1833 g_slist_foreach (uris, (GFunc) g_free, NULL);
1834 g_slist_free (uris);
1838 modest_msg_edit_window_attach_file_one (
1839 ModestMsgEditWindow *window,
1842 g_return_if_fail (window);
1843 g_return_if_fail (uri);
1845 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1848 GnomeVFSHandle *handle = NULL;
1849 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1850 if (result == GNOME_VFS_OK) {
1851 TnyMimePart *mime_part;
1853 const gchar *mime_type = NULL;
1855 gchar *escaped_filename;
1858 GnomeVFSFileInfo info;
1859 GnomeVFSURI *vfs_uri;
1861 vfs_uri = gnome_vfs_uri_new (uri);
1864 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1865 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1866 g_free (escaped_filename);
1867 gnome_vfs_uri_unref (vfs_uri);
1869 if (gnome_vfs_get_file_info (uri,
1871 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1872 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1874 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1875 mime_part = tny_platform_factory_new_mime_part
1876 (modest_runtime_get_platform_factory ());
1877 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1879 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1881 content_id = g_strdup_printf ("%d", priv->last_cid);
1882 tny_mime_part_set_content_id (mime_part, content_id);
1883 g_free (content_id);
1886 basename = g_path_get_basename (filename);
1887 tny_mime_part_set_filename (mime_part, basename);
1890 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1891 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1893 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1894 gtk_widget_show_all (priv->attachments_caption);
1895 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1901 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1904 ModestMsgEditWindowPrivate *priv;
1905 gboolean clean_list = FALSE;
1907 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1908 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1910 if (att_list == NULL) {
1911 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1915 if (att_list == NULL) {
1916 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1918 GtkWidget *confirmation_dialog = NULL;
1919 gboolean dialog_response;
1921 gchar *message = NULL;
1922 const gchar *filename = NULL;
1924 if (att_list->next == NULL) {
1925 filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1929 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1930 att_list->next == NULL), filename);
1931 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1933 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1934 gtk_widget_destroy (confirmation_dialog);
1935 if (!dialog_response) {
1937 g_list_free (att_list);
1940 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1942 for (node = att_list; node != NULL; node = g_list_next (node)) {
1943 TnyMimePart *mime_part = (TnyMimePart *) node->data;
1944 const gchar *att_id;
1945 priv->attachments = g_list_remove (priv->attachments, mime_part);
1947 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1949 if (priv->attachments == NULL)
1950 gtk_widget_hide (priv->attachments_caption);
1951 att_id = tny_mime_part_get_content_id (mime_part);
1953 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1955 g_object_unref (mime_part);
1956 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1961 g_list_free (att_list);
1965 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1968 ModestMsgEditWindowPrivate *priv;
1969 GdkColor *new_color;
1970 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1972 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1973 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1976 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1978 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1980 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1982 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1987 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1990 ModestMsgEditWindowPrivate *priv;
1991 gint new_size_index;
1992 ModestMsgEditWindow *window;
1995 window = MODEST_MSG_EDIT_WINDOW (userdata);
1996 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1997 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1999 if (gtk_check_menu_item_get_active (menu_item)) {
2001 WPTextBufferFormat format;
2003 memset (&format, 0, sizeof (format));
2004 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2006 label = gtk_bin_get_child (GTK_BIN (menu_item));
2008 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2009 format.cs.font_size = TRUE;
2010 format.cs.text_position = TRUE;
2011 format.cs.font = TRUE;
2012 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2013 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2015 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2016 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2017 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2019 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2020 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2021 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2027 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2030 ModestMsgEditWindowPrivate *priv;
2031 gint new_font_index;
2032 ModestMsgEditWindow *window;
2035 window = MODEST_MSG_EDIT_WINDOW (userdata);
2036 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2037 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2039 if (gtk_check_menu_item_get_active (menu_item)) {
2042 label = gtk_bin_get_child (GTK_BIN (menu_item));
2044 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2046 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2047 (gpointer) new_font_index))
2048 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2050 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2051 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2052 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2058 modest_msg_edit_window_set_zoom (ModestWindow *window,
2061 ModestMsgEditWindowPrivate *priv;
2062 ModestWindowPrivate *parent_priv;
2063 GtkRadioAction *zoom_radio_action;
2065 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2067 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2068 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2069 priv->zoom_level = zoom;
2070 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2072 /* Zoom level menu options should be updated with the current zoom level */
2073 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2074 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2075 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2076 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2077 /* FIXME: Not availible before Gtk 2.10 */
2079 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2084 modest_msg_edit_window_get_zoom (ModestWindow *window)
2086 ModestMsgEditWindowPrivate *priv;
2088 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2090 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2091 return priv->zoom_level;
2095 zoom_allowed (ModestMsgEditWindow *window)
2099 focus = gtk_window_get_focus (GTK_WINDOW (window));
2100 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2104 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2106 ModestWindowPrivate *parent_priv;
2107 GtkRadioAction *zoom_radio_action;
2108 GSList *group, *node;
2110 /* First we check if the text view is focused. If not, zooming is not allowed */
2111 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2112 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2116 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2117 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2118 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2120 group = gtk_radio_action_get_group (zoom_radio_action);
2122 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2123 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2127 for (node = group; node != NULL; node = g_slist_next (node)) {
2128 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2129 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2137 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2139 ModestWindowPrivate *parent_priv;
2140 GtkRadioAction *zoom_radio_action;
2141 GSList *group, *node;
2143 /* First we check if the text view is focused. If not, zooming is not allowed */
2144 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2145 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2149 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2150 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2151 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2153 group = gtk_radio_action_get_group (zoom_radio_action);
2155 for (node = group; node != NULL; node = g_slist_next (node)) {
2156 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2157 if (node->next != NULL) {
2158 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2161 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2169 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2171 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2172 ModestWindowPrivate *parent_priv;
2173 ModestWindowMgr *mgr;
2174 gboolean is_fullscreen;
2175 GtkAction *fs_toggle_action;
2178 mgr = modest_runtime_get_window_mgr ();
2179 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2181 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2183 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2184 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2185 if (is_fullscreen != active)
2186 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2194 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2197 ModestMsgEditWindowPrivate *priv = NULL;
2198 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2200 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2201 if (!priv->update_caption_visibility)
2204 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2206 gtk_widget_show (priv->cc_caption);
2208 gtk_widget_hide (priv->cc_caption);
2210 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2214 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2217 ModestMsgEditWindowPrivate *priv = NULL;
2218 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2220 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2221 if (!priv->update_caption_visibility)
2224 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2226 gtk_widget_show (priv->bcc_caption);
2228 gtk_widget_hide (priv->bcc_caption);
2230 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2234 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2235 ModestRecptEditor *editor)
2237 ModestMsgEditWindowPrivate *priv;
2239 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2240 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2241 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2243 if (editor == NULL) {
2244 GtkWidget *view_focus;
2245 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2247 /* This code should be kept in sync with ModestRecptEditor. The
2248 textview inside the recpt editor is the one that really gets the
2249 focus. As it's inside a scrolled window, and this one inside the
2250 hbox recpt editor inherits from, we'll need to go up in the
2251 hierarchy to know if the text view is part of the recpt editor
2252 or if it's a different text entry */
2254 if (gtk_widget_get_parent (view_focus)) {
2255 GtkWidget *first_parent;
2257 first_parent = gtk_widget_get_parent (view_focus);
2258 if (gtk_widget_get_parent (first_parent) &&
2259 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2260 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2265 editor = MODEST_RECPT_EDITOR (priv->to_field);
2269 modest_address_book_select_addresses (editor);
2274 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2276 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2278 modest_msg_edit_window_open_addressbook (window, NULL);
2282 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2283 gboolean show_toolbar)
2285 ModestWindowPrivate *parent_priv;
2286 const gchar *action_name;
2289 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2290 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2292 /* We can not just use the code of
2293 modest_msg_edit_window_setup_toolbar because it has a
2294 mixture of both initialization and creation code. */
2296 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2298 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2300 /* Update also the actions (to update the toggles in the
2301 menus), we have to do it manually because some other window
2302 of the same time could have changed it (remember that the
2303 toolbar fullscreen mode is shared by all the windows of the
2305 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2306 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2308 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2310 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2311 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2317 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2318 TnyHeaderFlags priority_flags)
2320 ModestMsgEditWindowPrivate *priv;
2321 ModestWindowPrivate *parent_priv;
2323 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2325 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2326 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2327 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2329 if (priv->priority_flags != priority_flags) {
2330 GtkAction *priority_action = NULL;
2332 priv->priority_flags = priority_flags;
2334 switch (priority_flags) {
2335 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2336 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2337 gtk_widget_show (priv->priority_icon);
2338 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2339 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2341 case TNY_HEADER_FLAG_LOW_PRIORITY:
2342 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2343 gtk_widget_show (priv->priority_icon);
2344 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2345 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2348 gtk_widget_hide (priv->priority_icon);
2349 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2350 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2353 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2354 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2359 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2362 ModestMsgEditWindowPrivate *priv;
2363 ModestWindowPrivate *parent_priv;
2364 gint current_format;
2366 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2368 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2369 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2371 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2372 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2374 if (current_format != file_format) {
2375 switch (file_format) {
2376 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2377 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2379 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2383 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2384 response = gtk_dialog_run (GTK_DIALOG (dialog));
2385 gtk_widget_destroy (dialog);
2386 if (response == GTK_RESPONSE_OK) {
2387 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2389 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2390 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2395 update_dimmed (window);
2400 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2403 ModestMsgEditWindowPrivate *priv;
2404 WPTextBufferFormat oldfmt, fmt;
2405 gint old_position = 0;
2409 GdkColor *color = NULL;
2410 gboolean bold, bold_set, italic, italic_set;
2411 gboolean underline, underline_set;
2412 gboolean strikethrough, strikethrough_set;
2413 gboolean position_set;
2414 gboolean font_size_set, font_set, color_set;
2417 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2418 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2420 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2422 /* First we get the currently selected font information */
2423 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2424 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2426 switch (oldfmt.text_position) {
2427 case TEXT_POSITION_NORMAL:
2430 case TEXT_POSITION_SUPERSCRIPT:
2438 g_object_set (G_OBJECT (dialog),
2439 "bold", oldfmt.bold != FALSE,
2440 "bold-set", !oldfmt.cs.bold,
2441 "underline", oldfmt.underline != FALSE,
2442 "underline-set", !oldfmt.cs.underline,
2443 "italic", oldfmt.italic != FALSE,
2444 "italic-set", !oldfmt.cs.italic,
2445 "strikethrough", oldfmt.strikethrough != FALSE,
2446 "strikethrough-set", !oldfmt.cs.strikethrough,
2447 "color", &oldfmt.color,
2448 "color-set", !oldfmt.cs.color,
2449 "size", wp_font_size[oldfmt.font_size],
2450 "size-set", !oldfmt.cs.font_size,
2451 "position", old_position,
2452 "position-set", !oldfmt.cs.text_position,
2453 "family", wp_get_font_name (oldfmt.font),
2454 "family-set", !oldfmt.cs.font,
2457 gtk_widget_show_all (dialog);
2458 response = gtk_dialog_run (GTK_DIALOG (dialog));
2459 if (response == GTK_RESPONSE_OK) {
2461 g_object_get( dialog,
2463 "bold-set", &bold_set,
2464 "underline", &underline,
2465 "underline-set", &underline_set,
2467 "italic-set", &italic_set,
2468 "strikethrough", &strikethrough,
2469 "strikethrough-set", &strikethrough_set,
2471 "color-set", &color_set,
2473 "size-set", &font_size_set,
2474 "family", &font_name,
2475 "family-set", &font_set,
2476 "position", &position,
2477 "position-set", &position_set,
2482 if (response == GTK_RESPONSE_OK) {
2483 memset(&fmt, 0, sizeof(fmt));
2489 fmt.italic = italic;
2490 fmt.cs.italic = TRUE;
2492 if (underline_set) {
2493 fmt.underline = underline;
2494 fmt.cs.underline = TRUE;
2496 if (strikethrough_set) {
2497 fmt.strikethrough = strikethrough;
2498 fmt.cs.strikethrough = TRUE;
2503 ? TEXT_POSITION_NORMAL
2504 : ( ( position == 1 )
2505 ? TEXT_POSITION_SUPERSCRIPT
2506 : TEXT_POSITION_SUBSCRIPT );
2507 fmt.cs.text_position = TRUE;
2511 fmt.cs.color = TRUE;
2514 fmt.font = wp_get_font_index(font_name,
2519 if (font_size_set) {
2520 fmt.font_size = wp_get_font_size_index(
2521 font_size, DEFAULT_FONT_SIZE);
2522 fmt.cs.font_size = TRUE;
2524 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2526 gtk_widget_destroy (dialog);
2528 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2532 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2534 ModestMsgEditWindowPrivate *priv;
2536 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2537 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2539 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2541 update_dimmed (window);
2546 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2548 ModestMsgEditWindowPrivate *priv;
2550 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2551 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2553 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2555 update_dimmed (window);
2560 update_dimmed (ModestMsgEditWindow *window)
2562 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2563 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2567 gboolean editor_focused;
2569 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2570 editor_focused = gtk_widget_is_focus (priv->msg_body);
2572 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2573 gtk_action_set_sensitive (action, rich_text && editor_focused);
2574 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2575 /* gtk_action_set_sensitive (action, rich_text && editor_focused); */
2576 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2577 gtk_action_set_sensitive (action, rich_text && editor_focused);
2578 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2579 gtk_action_set_sensitive (action, rich_text && editor_focused);
2580 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2581 gtk_action_set_sensitive (action, rich_text && editor_focused);
2582 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2583 gtk_action_set_sensitive (action, rich_text && editor_focused);
2584 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2585 gtk_action_set_sensitive (action, rich_text && editor_focused);
2586 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2587 gtk_action_set_sensitive (action, rich_text && editor_focused);
2588 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2589 gtk_action_set_sensitive (action, rich_text && editor_focused);
2590 widget = priv->font_color_button;
2591 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2592 widget = priv->font_size_toolitem;
2593 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2594 widget = priv->font_face_toolitem;
2595 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2599 setup_insensitive_handlers (ModestMsgEditWindow *window)
2601 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2602 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2605 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2606 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2607 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2608 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2609 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2610 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2611 widget = priv->font_color_button;
2612 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2613 widget = priv->font_size_toolitem;
2614 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2615 widget = priv->font_face_toolitem;
2616 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2621 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2623 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2626 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2627 gtk_action_set_sensitive (action, can_undo);
2631 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2633 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2636 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/RedoMenu");
2637 gtk_action_set_sensitive (action, can_redo);
2641 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2644 GtkTextIter match_start, match_end;
2646 if (image_id == NULL)
2649 gtk_text_buffer_get_start_iter (buffer, &iter);
2651 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2652 GSList *tags = gtk_text_iter_get_tags (&match_start);
2654 for (node = tags; node != NULL; node = g_slist_next (node)) {
2655 GtkTextTag *tag = (GtkTextTag *) node->data;
2656 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2657 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2658 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2660 offset = gtk_text_iter_get_offset (&match_start);
2661 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2662 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2666 gtk_text_iter_forward_char (&iter);
2671 message_is_empty (ModestMsgEditWindow *window)
2673 ModestMsgEditWindowPrivate *priv = NULL;
2675 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2676 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2678 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2679 * so we can ignore markup.
2681 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2684 count = gtk_text_buffer_get_char_count (buf);
2690 msg_body_focus (GtkWidget *focus,
2691 GdkEventFocus *event,
2695 update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2700 recpt_field_changed (GtkTextBuffer *buffer,
2701 ModestMsgEditWindow *editor)
2703 update_send_dimming (editor);
2707 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2709 update_send_dimming (editor);
2713 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2715 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2716 const gchar *subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2717 if (message_is_empty(editor) || (subject == NULL || subject[0] == '\0')) {
2718 hildon_banner_show_information (NULL, NULL, _("mcen_ib_subject_or_body_not_modified"));
2720 hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2725 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2727 gboolean rich_text, editor_focused;
2729 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2730 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2731 editor_focused = gtk_widget_is_focus (priv->msg_body);
2734 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2735 else if (!editor_focused)
2736 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2740 reset_modified (ModestMsgEditWindow *editor)
2742 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2743 GtkTextBuffer *buffer;
2745 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2746 gtk_text_buffer_set_modified (buffer, FALSE);
2747 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2748 gtk_text_buffer_set_modified (buffer, FALSE);
2749 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2750 gtk_text_buffer_set_modified (buffer, FALSE);
2751 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2755 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2757 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2758 GtkTextBuffer *buffer;
2760 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2761 if (gtk_text_buffer_get_modified (buffer))
2763 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2764 if (gtk_text_buffer_get_modified (buffer))
2766 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2767 if (gtk_text_buffer_get_modified (buffer))
2769 if (gtk_text_buffer_get_modified (priv->text_buffer))
2779 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2781 ModestMsgEditWindowPrivate *priv = NULL;
2783 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2784 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2786 /* check if there's no recipient added */
2787 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2788 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2789 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2790 /* no recipient contents, then select contacts */
2791 modest_msg_edit_window_open_addressbook (window, NULL);
2795 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2796 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2799 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2800 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2803 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2804 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2808 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2809 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2810 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2817 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2818 ModestMsgEditWindow *window)
2820 modest_msg_edit_window_offer_attach_file (window);
2824 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2826 ModestMsgEditWindow *window)
2828 if (!GTK_WIDGET_VISIBLE (window))
2831 update_remove_attachment_dimming (window);
2832 update_copy_cut_dimming (window);
2833 update_paste_dimming (window);
2837 update_window_title (ModestMsgEditWindow *window)
2839 ModestMsgEditWindowPrivate *priv = NULL;
2840 const gchar *subject;
2842 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2843 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2844 if (subject == NULL || subject[0] == '\0')
2845 subject = _("mail_va_new_email");
2847 gtk_window_set_title (GTK_WINDOW (window), subject);
2852 subject_field_changed (GtkEditable *editable,
2853 ModestMsgEditWindow *window)
2855 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2856 update_window_title (window);
2857 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2858 update_send_dimming (window);
2862 subject_field_insert_text (GtkEditable *editable,
2864 gint new_text_length,
2866 ModestMsgEditWindow *window)
2868 GString *result = g_string_new ("");
2870 gint result_len = 0;
2872 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2873 gunichar c = g_utf8_get_char_validated (current, 8);
2874 /* Invalid unichar, stop */
2880 result = g_string_append_unichar (result, c);
2884 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2885 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2888 /* Prevent endless recursion */
2889 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2890 g_signal_emit_by_name (editable, "insert-text",
2891 (gpointer) result->str, (gpointer) result->len,
2892 (gpointer) position, (gpointer) window);
2893 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2897 g_string_free (result, TRUE);
2901 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2904 ModestMsgEditWindowPrivate *priv = NULL;
2906 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2907 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2909 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2912 gtk_widget_show_all (priv->find_toolbar);
2913 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2915 gtk_widget_hide_all (priv->find_toolbar);
2916 gtk_widget_grab_focus (priv->msg_body);
2922 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2924 GtkTextIter *match_start,
2925 GtkTextIter *match_end)
2927 GtkTextIter end_iter;
2928 gchar *str_casefold;
2931 gchar *range_casefold;
2934 gboolean result = FALSE;
2941 gtk_text_iter_forward_to_end (&end_iter);
2943 str_casefold = g_utf8_casefold (str, -1);
2944 str_chars_n = strlen (str);
2946 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2947 range_casefold = g_utf8_casefold (range_text, -1);
2948 range_chars_n = strlen (range_casefold);
2950 if (range_chars_n < str_chars_n) {
2951 g_free (str_casefold);
2952 g_free (range_text);
2953 g_free (range_casefold);
2957 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2958 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2959 if (!g_utf8_collate (range_subtext, str_casefold)) {
2960 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2962 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2963 match_start, match_end, NULL);
2964 g_free (found_text);
2966 g_free (range_subtext);
2970 g_free (str_casefold);
2971 g_free (range_text);
2972 g_free (range_casefold);
2979 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2980 ModestMsgEditWindow *window)
2982 gchar *current_search = NULL;
2983 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2985 GtkTextIter selection_start, selection_end;
2986 GtkTextIter match_start, match_end;
2987 gboolean continue_search = FALSE;
2989 if (message_is_empty (window)) {
2990 g_free (priv->last_search);
2991 priv->last_search = NULL;
2992 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
2996 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
2997 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2998 g_free (current_search);
2999 g_free (priv->last_search);
3000 priv->last_search = NULL;
3001 /* Information banner about empty search */
3002 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3006 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3007 continue_search = TRUE;
3009 g_free (priv->last_search);
3010 priv->last_search = g_strdup (current_search);
3013 if (continue_search) {
3014 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3015 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3016 &match_start, &match_end);
3018 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3020 GtkTextIter buffer_start;
3021 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3022 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3023 &match_start, &match_end);
3025 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3028 /* Mark as selected the string found in search */
3030 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3031 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3033 g_free (priv->last_search);
3034 priv->last_search = NULL;
3036 g_free (current_search);
3040 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3041 ModestMsgEditWindow *window)
3043 GtkToggleAction *toggle;
3044 ModestWindowPrivate *parent_priv;
3045 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3047 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3048 gtk_toggle_action_set_active (toggle, FALSE);
3052 update_remove_attachment_dimming (ModestMsgEditWindow *window)
3054 ModestWindowPrivate *parent_priv;
3055 ModestMsgEditWindowPrivate *priv;
3057 GList *selected_attachments = NULL;
3058 gint n_att_selected = 0;
3060 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3061 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3063 selected_attachments = modest_attachments_view_get_selection (
3064 MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
3065 n_att_selected = g_list_length (selected_attachments);
3066 g_list_free (selected_attachments);
3068 action = gtk_ui_manager_get_action (
3069 parent_priv->ui_manager,
3070 "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
3071 gtk_action_set_sensitive (action, n_att_selected == 1);
3075 update_copy_cut_dimming (ModestMsgEditWindow *window)
3077 ModestWindowPrivate *parent_priv = NULL;
3078 ModestMsgEditWindowPrivate *priv = NULL;
3079 GtkAction *action = NULL;
3080 gboolean has_selection = FALSE;
3081 GtkWidget *focused = NULL;
3083 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3084 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3085 focused = gtk_window_get_focus (GTK_WINDOW (window));
3087 if (GTK_IS_TEXT_VIEW (focused)) {
3088 GtkTextBuffer *buffer = NULL;
3089 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
3090 has_selection = gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (buffer));
3091 } else if (GTK_IS_EDITABLE (focused)) {
3092 has_selection = gtk_editable_get_selection_bounds (GTK_EDITABLE (focused), NULL, NULL);
3095 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
3096 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3097 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
3098 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3103 update_paste_dimming (ModestMsgEditWindow *window)
3105 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3106 GtkAction *action = NULL;
3107 GtkClipboard *clipboard = NULL;
3108 ModestEmailClipboard *e_clipboard;
3112 focused = gtk_window_get_focus (GTK_WINDOW (window));
3114 e_clipboard = modest_runtime_get_email_clipboard ();
3115 if (!modest_email_clipboard_cleared (e_clipboard)) {
3118 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3119 active = gtk_clipboard_wait_is_text_available (clipboard);
3123 if (MODEST_IS_ATTACHMENTS_VIEW (focused))
3127 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
3128 gtk_action_set_sensitive (action, active);
3133 update_select_all_dimming (ModestMsgEditWindow *window)
3136 gboolean dimmed = FALSE;
3138 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3140 focused = gtk_window_get_focus (GTK_WINDOW (window));
3141 if (GTK_IS_ENTRY (focused)) {
3142 const gchar *current_text;
3143 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
3144 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
3145 } else if (GTK_IS_TEXT_VIEW (focused)) {
3146 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
3147 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
3148 } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
3151 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
3152 gtk_action_set_sensitive (action, !dimmed);
3156 update_zoom_dimming (ModestMsgEditWindow *window)
3159 gboolean dimmed = FALSE;
3161 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3163 focused = gtk_window_get_focus (GTK_WINDOW (window));
3164 dimmed = ! WP_IS_TEXT_VIEW (focused);
3165 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
3166 gtk_action_set_sensitive (action, !dimmed);
3170 update_send_dimming (ModestMsgEditWindow *window)
3172 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3173 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3174 GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
3175 const gchar *subject;
3176 gboolean dim = FALSE;
3179 to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
3180 cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
3181 bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
3182 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3184 dim = ((gtk_text_buffer_get_char_count (to_buffer) +
3185 gtk_text_buffer_get_char_count (cc_buffer) +
3186 gtk_text_buffer_get_char_count (bcc_buffer)) == 0)
3187 || (subject == NULL || subject[0] == '\0')
3188 || message_is_empty(window);
3190 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
3191 gtk_action_set_sensitive (action, !dim);
3192 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
3193 gtk_action_set_sensitive (action, !dim);
3197 edit_menu_activated (GtkAction *action,
3200 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3202 update_select_all_dimming (window);
3203 update_copy_cut_dimming (window);
3204 update_paste_dimming (window);
3207 view_menu_activated (GtkAction *action,
3210 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3212 update_zoom_dimming (window);
3216 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3218 ModestMsgEditWindowPrivate *priv;
3220 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3225 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3228 ModestMsgEditWindowPrivate *priv;
3230 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3236 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3239 ModestMsgEditWindowPrivate *priv;
3240 TnyHeader *header = NULL;
3242 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3243 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3245 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3246 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3248 if (priv->draft_msg != NULL) {
3249 header = tny_msg_get_header (priv->draft_msg);
3250 if (TNY_IS_HEADER (header)) {
3251 modest_window_mgr_unregister_header (mgr, header);
3253 g_object_unref (priv->draft_msg);
3256 if (draft != NULL) {
3257 g_object_ref (draft);
3258 header = tny_msg_get_header (draft);
3259 if (TNY_IS_HEADER (header))
3260 modest_window_mgr_register_header (mgr, header);
3261 if (priv->msg_uid) {
3262 g_free (priv->msg_uid);
3263 priv->msg_uid = NULL;
3265 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3268 priv->draft_msg = draft;
3272 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3273 GtkTextIter *start, GtkTextIter *end,
3276 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3277 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3280 if (tag == NULL+13) return;
3281 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3282 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3283 replace_with_attachments (window, priv->attachments);
3288 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3291 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3293 g_return_if_fail (TNY_IS_MIME_PART (part));
3294 priv->attachments = g_list_prepend (priv->attachments, part);
3295 g_object_ref (part);
3296 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3297 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3298 gtk_widget_show_all (priv->attachments_caption);
3299 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3303 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3305 ModestMsgEditWindowPrivate *priv;
3307 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3308 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3310 return priv->msg_uid;