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 ModestPair *account_pair = NULL;
1111 g_return_val_if_fail (msg, NULL);
1112 g_return_val_if_fail (account_name, NULL);
1114 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1116 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1117 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1119 parent_priv->ui_manager = gtk_ui_manager_new();
1120 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1121 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1123 /* Add common actions */
1124 gtk_action_group_add_actions (action_group,
1125 modest_msg_edit_action_entries,
1126 G_N_ELEMENTS (modest_msg_edit_action_entries),
1128 gtk_action_group_add_toggle_actions (action_group,
1129 modest_msg_edit_toggle_action_entries,
1130 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1132 gtk_action_group_add_radio_actions (action_group,
1133 modest_msg_edit_alignment_radio_action_entries,
1134 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1136 G_CALLBACK (modest_ui_actions_on_change_justify),
1138 gtk_action_group_add_radio_actions (action_group,
1139 modest_msg_edit_zoom_action_entries,
1140 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1142 G_CALLBACK (modest_ui_actions_on_change_zoom),
1144 gtk_action_group_add_radio_actions (action_group,
1145 modest_msg_edit_priority_action_entries,
1146 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1148 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1150 gtk_action_group_add_radio_actions (action_group,
1151 modest_msg_edit_file_format_action_entries,
1152 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1153 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1154 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1156 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1157 g_object_unref (action_group);
1159 /* Load the UI definition */
1160 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1162 if (error != NULL) {
1163 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1164 g_clear_error (&error);
1167 /* Add accelerators */
1168 gtk_window_add_accel_group (GTK_WINDOW (obj),
1169 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1171 /* Menubar. Update the state of some toggles */
1172 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1173 conf = modest_runtime_get_conf ();
1174 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1175 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1176 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1177 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1178 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1179 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1180 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1181 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1183 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1186 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1188 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1190 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1192 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1193 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1195 setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
1197 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1198 if (account_pair != NULL)
1199 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1201 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1203 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1205 /* Set window icon */
1206 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1208 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1209 g_object_unref (window_icon);
1212 /* Dim at start clipboard actions */
1213 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1214 gtk_action_set_sensitive (action, FALSE);
1215 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1216 gtk_action_set_sensitive (action, FALSE);
1217 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1218 gtk_action_set_sensitive (action, FALSE);
1220 /* Update select all */
1221 update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1222 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
1223 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
1224 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
1225 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
1227 /* set initial state of cc and bcc */
1228 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1229 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1230 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1231 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1232 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1233 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1235 update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1236 priv->update_caption_visibility = TRUE;
1238 reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1240 return (ModestWindow*) obj;
1244 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1246 GString **string_buffer = (GString **) user_data;
1248 *string_buffer = g_string_append (*string_buffer, buffer);
1254 * @result: A new string which should be freed with g_free().
1257 get_formatted_data (ModestMsgEditWindow *edit_window)
1259 ModestMsgEditWindowPrivate *priv;
1260 GString *string_buffer = g_string_new ("");
1262 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1264 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1266 return g_string_free (string_buffer, FALSE);
1271 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1274 const gchar *account_name;
1275 ModestMsgEditWindowPrivate *priv;
1277 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1279 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1281 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1282 g_return_val_if_fail (account_name, NULL);
1285 /* don't free these (except from) */
1286 data = g_slice_new0 (MsgData);
1287 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1289 data->account_name = g_strdup (account_name);
1290 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1291 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1292 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1293 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1294 if (priv->draft_msg) {
1295 data->draft_msg = g_object_ref (priv->draft_msg);
1296 } else if (priv->outbox_msg) {
1297 data->draft_msg = g_object_ref (priv->outbox_msg);
1299 data->draft_msg = NULL;
1302 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1304 gtk_text_buffer_get_bounds (buf, &b, &e);
1305 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1307 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1308 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1310 data->html_body = NULL;
1312 /* deep-copy the data */
1313 GList *cursor = priv->attachments;
1314 data->attachments = NULL;
1316 if (!(TNY_IS_MIME_PART(cursor->data))) {
1317 g_warning ("strange data in attachment list");
1318 cursor = g_list_next (cursor);
1321 data->attachments = g_list_append (data->attachments,
1322 g_object_ref (cursor->data));
1323 cursor = g_list_next (cursor);
1326 data->priority_flags = priv->priority_flags;
1333 unref_gobject (GObject *obj, gpointer data)
1335 if (!G_IS_OBJECT(obj))
1337 g_object_unref (obj);
1341 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1344 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1352 g_free (data->subject);
1353 g_free (data->plain_body);
1354 g_free (data->html_body);
1355 g_free (data->account_name);
1357 if (data->draft_msg != NULL) {
1358 g_object_unref (data->draft_msg);
1359 data->draft_msg = NULL;
1362 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1363 g_list_free (data->attachments);
1365 g_slice_free (MsgData, data);
1369 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1372 ModestMsgEditWindowPrivate *priv = NULL;
1373 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1375 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1377 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1379 return MODEST_MSG_EDIT_FORMAT_HTML;
1381 return MODEST_MSG_EDIT_FORMAT_TEXT;
1385 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1386 ModestMsgEditFormat format)
1388 ModestMsgEditWindowPrivate *priv;
1390 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1391 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1394 case MODEST_MSG_EDIT_FORMAT_HTML:
1395 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1397 case MODEST_MSG_EDIT_FORMAT_TEXT:
1398 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1401 g_return_if_reached ();
1405 ModestMsgEditFormatState *
1406 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1408 ModestMsgEditFormatState *format_state = NULL;
1409 ModestMsgEditWindowPrivate *priv;
1410 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1412 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1413 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1415 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1417 format_state = g_new0 (ModestMsgEditFormatState, 1);
1418 format_state->bold = buffer_format->bold&0x1;
1419 format_state->italics = buffer_format->italic&0x1;
1420 format_state->bullet = buffer_format->bullet&0x1;
1421 format_state->color = buffer_format->color;
1422 format_state->font_size = buffer_format->font_size;
1423 format_state->font_family = wp_get_font_name (buffer_format->font);
1424 format_state->justification = buffer_format->justification;
1425 g_free (buffer_format);
1427 return format_state;
1432 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1433 const ModestMsgEditFormatState *format_state)
1435 ModestMsgEditWindowPrivate *priv;
1436 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1437 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1438 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1439 g_return_if_fail (format_state != NULL);
1441 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1442 gtk_widget_grab_focus (priv->msg_body);
1443 buffer_format->bold = (format_state->bold != FALSE);
1444 buffer_format->italic = (format_state->italics != FALSE);
1445 buffer_format->color = format_state->color;
1446 buffer_format->font_size = format_state->font_size;
1447 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1448 buffer_format->justification = format_state->justification;
1449 buffer_format->bullet = format_state->bullet;
1451 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1453 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1454 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1455 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1456 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1457 buffer_format->cs.font = (buffer_format->font != current_format->font);
1458 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1459 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1461 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1462 if (buffer_format->cs.bold) {
1463 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1465 if (buffer_format->cs.italic) {
1466 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1468 if (buffer_format->cs.color) {
1469 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1471 if (buffer_format->cs.font_size) {
1472 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1474 if (buffer_format->cs.justification) {
1475 switch (buffer_format->justification) {
1476 case GTK_JUSTIFY_LEFT:
1477 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1479 case GTK_JUSTIFY_CENTER:
1480 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1482 case GTK_JUSTIFY_RIGHT:
1483 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1490 if (buffer_format->cs.font) {
1491 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1493 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1494 if (buffer_format->cs.bullet) {
1495 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1497 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1499 g_free (current_format);
1504 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1506 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1508 ModestWindowPrivate *parent_priv;
1509 ModestMsgEditWindowPrivate *priv;
1510 GtkWidget *new_size_menuitem;
1511 GtkWidget *new_font_menuitem;
1513 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1514 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1516 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1517 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1518 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1519 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1521 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1522 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1523 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1526 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1528 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1529 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1531 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1532 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1534 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1535 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1537 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1538 G_CALLBACK (modest_msg_edit_window_color_button_change),
1540 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1541 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1542 G_CALLBACK (modest_msg_edit_window_color_button_change),
1545 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1546 buffer_format->font_size))->data);
1547 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1551 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1552 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1553 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1555 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1556 G_CALLBACK (modest_msg_edit_window_size_change),
1558 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1559 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1560 G_CALLBACK (modest_msg_edit_window_size_change),
1564 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1565 buffer_format->font))->data);
1566 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1570 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1571 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1572 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1574 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1575 G_CALLBACK (modest_msg_edit_window_font_change),
1577 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1578 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1579 G_CALLBACK (modest_msg_edit_window_font_change),
1583 g_free (buffer_format);
1589 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1592 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1593 ModestMsgEditWindowPrivate *priv;
1594 GtkWidget *dialog = NULL;
1596 const GdkColor *new_color = NULL;
1598 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1599 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1601 #ifdef MODEST_HILDON_VERSION_0
1602 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1603 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1605 dialog = hildon_color_chooser_new ();
1606 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1607 #endif /*MODEST_HILDON_VERSION_0*/
1608 g_free (buffer_format);
1610 response = gtk_dialog_run (GTK_DIALOG (dialog));
1612 case GTK_RESPONSE_OK: {
1613 #ifdef MODEST_HILDON_VERSION_0
1614 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1617 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1619 #endif /*MODEST_HILDON_VERSION_0*/
1626 gtk_widget_destroy (dialog);
1628 if (new_color != NULL)
1629 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1634 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1637 ModestMsgEditWindowPrivate *priv;
1638 GtkWidget *dialog = NULL;
1640 GdkColor *old_color = NULL;
1641 const GdkColor *new_color = NULL;
1643 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1644 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1646 #ifdef MODEST_HILDON_VERSION_0
1647 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1648 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1650 dialog = hildon_color_chooser_new ();
1651 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1652 #endif /*MODEST_HILDON_VERSION_9*/
1654 response = gtk_dialog_run (GTK_DIALOG (dialog));
1656 case GTK_RESPONSE_OK: {
1657 #ifdef MODEST_HILDON_VERSION_0
1658 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1661 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1663 #endif /*MODEST_HILDON_VERSION_0*/
1669 gtk_widget_destroy (dialog);
1671 if (new_color != NULL)
1672 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1676 static TnyStream* create_stream_for_uri (const gchar* uri)
1681 TnyStream *result = NULL;
1683 GnomeVFSHandle *handle = NULL;
1684 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1685 if (test == GNOME_VFS_OK) {
1686 /* Create the tinymail stream: */
1687 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1688 result = TNY_STREAM (tny_vfs_stream_new (handle));
1695 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1698 ModestMsgEditWindowPrivate *priv;
1699 GtkWidget *dialog = NULL;
1701 GSList *uris = NULL;
1702 GSList *uri_node = NULL;
1704 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1706 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1707 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1708 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1710 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1712 response = gtk_dialog_run (GTK_DIALOG (dialog));
1714 case GTK_RESPONSE_OK:
1715 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1720 gtk_widget_destroy (dialog);
1722 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1724 GnomeVFSHandle *handle = NULL;
1725 GnomeVFSResult result;
1726 GtkTextIter position;
1727 GtkTextMark *insert_mark;
1729 uri = (const gchar *) uri_node->data;
1730 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1731 if (result == GNOME_VFS_OK) {
1733 GnomeVFSFileInfo info;
1734 gchar *filename, *basename, *escaped_filename;
1735 TnyMimePart *mime_part;
1737 const gchar *mime_type = NULL;
1738 GnomeVFSURI *vfs_uri;
1740 vfs_uri = gnome_vfs_uri_new (uri);
1742 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1743 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1744 g_free (escaped_filename);
1745 gnome_vfs_uri_unref (vfs_uri);
1747 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1748 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1750 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1752 mime_part = tny_platform_factory_new_mime_part
1753 (modest_runtime_get_platform_factory ());
1755 TnyStream *stream = create_stream_for_uri (uri);
1756 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1758 content_id = g_strdup_printf ("%d", priv->last_cid);
1759 tny_mime_part_set_content_id (mime_part, content_id);
1760 g_free (content_id);
1763 basename = g_path_get_basename (filename);
1764 tny_mime_part_set_filename (mime_part, basename);
1767 pixbuf = pixbuf_from_stream (stream, mime_type);
1769 if (pixbuf != NULL) {
1770 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1771 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1772 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1775 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1776 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1778 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1779 gtk_widget_show_all (priv->attachments_caption);
1780 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1790 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1793 ModestMsgEditWindowPrivate *priv;
1794 GtkWidget *dialog = NULL;
1796 GSList *uris = NULL;
1799 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1801 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1802 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1803 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1805 response = gtk_dialog_run (GTK_DIALOG (dialog));
1807 case GTK_RESPONSE_OK:
1808 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1813 gtk_widget_destroy (dialog);
1815 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1816 const gchar *uri = (const gchar *) uri_node->data;
1817 modest_msg_edit_window_attach_file_one (window, uri);
1819 g_slist_foreach (uris, (GFunc) g_free, NULL);
1820 g_slist_free (uris);
1824 modest_msg_edit_window_attach_file_one (
1825 ModestMsgEditWindow *window,
1828 g_return_if_fail (window);
1829 g_return_if_fail (uri);
1831 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1834 GnomeVFSHandle *handle = NULL;
1835 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1836 if (result == GNOME_VFS_OK) {
1837 TnyMimePart *mime_part;
1839 const gchar *mime_type = NULL;
1841 gchar *escaped_filename;
1844 GnomeVFSFileInfo info;
1845 GnomeVFSURI *vfs_uri;
1847 vfs_uri = gnome_vfs_uri_new (uri);
1850 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1851 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1852 g_free (escaped_filename);
1853 gnome_vfs_uri_unref (vfs_uri);
1855 if (gnome_vfs_get_file_info (uri,
1857 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1858 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1860 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1861 mime_part = tny_platform_factory_new_mime_part
1862 (modest_runtime_get_platform_factory ());
1863 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1865 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1867 content_id = g_strdup_printf ("%d", priv->last_cid);
1868 tny_mime_part_set_content_id (mime_part, content_id);
1869 g_free (content_id);
1872 basename = g_path_get_basename (filename);
1873 tny_mime_part_set_filename (mime_part, basename);
1876 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1877 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1879 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1880 gtk_widget_show_all (priv->attachments_caption);
1881 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1887 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1890 ModestMsgEditWindowPrivate *priv;
1891 gboolean clean_list = FALSE;
1893 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1894 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1896 if (att_list == NULL) {
1897 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1901 if (att_list == NULL) {
1902 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1904 GtkWidget *confirmation_dialog = NULL;
1905 gboolean dialog_response;
1907 gchar *message = NULL;
1908 const gchar *filename = NULL;
1910 if (att_list->next == NULL) {
1911 filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1915 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1916 att_list->next == NULL), filename);
1917 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1919 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1920 gtk_widget_destroy (confirmation_dialog);
1921 if (!dialog_response) {
1923 g_list_free (att_list);
1926 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1928 for (node = att_list; node != NULL; node = g_list_next (node)) {
1929 TnyMimePart *mime_part = (TnyMimePart *) node->data;
1930 const gchar *att_id;
1931 priv->attachments = g_list_remove (priv->attachments, mime_part);
1933 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1935 if (priv->attachments == NULL)
1936 gtk_widget_hide (priv->attachments_caption);
1937 att_id = tny_mime_part_get_content_id (mime_part);
1939 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1941 g_object_unref (mime_part);
1942 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1947 g_list_free (att_list);
1951 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1954 ModestMsgEditWindowPrivate *priv;
1955 GdkColor *new_color;
1956 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1958 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1959 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1962 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1964 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1966 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1968 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1973 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1976 ModestMsgEditWindowPrivate *priv;
1977 gint new_size_index;
1978 ModestMsgEditWindow *window;
1981 window = MODEST_MSG_EDIT_WINDOW (userdata);
1982 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1983 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1985 if (gtk_check_menu_item_get_active (menu_item)) {
1987 WPTextBufferFormat format;
1989 memset (&format, 0, sizeof (format));
1990 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
1992 label = gtk_bin_get_child (GTK_BIN (menu_item));
1994 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1995 format.cs.font_size = TRUE;
1996 format.cs.text_position = TRUE;
1997 format.cs.font = TRUE;
1998 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1999 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2001 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2002 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2003 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2005 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2006 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2007 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2013 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2016 ModestMsgEditWindowPrivate *priv;
2017 gint new_font_index;
2018 ModestMsgEditWindow *window;
2021 window = MODEST_MSG_EDIT_WINDOW (userdata);
2022 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2023 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2025 if (gtk_check_menu_item_get_active (menu_item)) {
2028 label = gtk_bin_get_child (GTK_BIN (menu_item));
2030 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2032 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2033 (gpointer) new_font_index))
2034 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2036 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2037 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2038 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2044 modest_msg_edit_window_set_zoom (ModestWindow *window,
2047 ModestMsgEditWindowPrivate *priv;
2048 ModestWindowPrivate *parent_priv;
2049 GtkRadioAction *zoom_radio_action;
2051 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2053 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2054 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2055 priv->zoom_level = zoom;
2056 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2058 /* Zoom level menu options should be updated with the current zoom level */
2059 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2060 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2061 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2062 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2063 /* FIXME: Not availible before Gtk 2.10 */
2065 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2070 modest_msg_edit_window_get_zoom (ModestWindow *window)
2072 ModestMsgEditWindowPrivate *priv;
2074 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2076 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2077 return priv->zoom_level;
2081 zoom_allowed (ModestMsgEditWindow *window)
2085 focus = gtk_window_get_focus (GTK_WINDOW (window));
2086 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2090 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2092 ModestWindowPrivate *parent_priv;
2093 GtkRadioAction *zoom_radio_action;
2094 GSList *group, *node;
2096 /* First we check if the text view is focused. If not, zooming is not allowed */
2097 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2098 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2102 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2103 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2104 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2106 group = gtk_radio_action_get_group (zoom_radio_action);
2108 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2109 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2113 for (node = group; node != NULL; node = g_slist_next (node)) {
2114 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2115 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2123 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2125 ModestWindowPrivate *parent_priv;
2126 GtkRadioAction *zoom_radio_action;
2127 GSList *group, *node;
2129 /* First we check if the text view is focused. If not, zooming is not allowed */
2130 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2131 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2135 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2136 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2137 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2139 group = gtk_radio_action_get_group (zoom_radio_action);
2141 for (node = group; node != NULL; node = g_slist_next (node)) {
2142 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2143 if (node->next != NULL) {
2144 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2147 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2155 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2157 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2158 ModestWindowPrivate *parent_priv;
2159 ModestWindowMgr *mgr;
2160 gboolean is_fullscreen;
2161 GtkAction *fs_toggle_action;
2164 mgr = modest_runtime_get_window_mgr ();
2165 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2167 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2169 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2170 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2171 if (is_fullscreen != active)
2172 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2180 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2183 ModestMsgEditWindowPrivate *priv = NULL;
2184 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2186 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2187 if (!priv->update_caption_visibility)
2190 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2192 gtk_widget_show (priv->cc_caption);
2194 gtk_widget_hide (priv->cc_caption);
2196 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2200 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2203 ModestMsgEditWindowPrivate *priv = NULL;
2204 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2206 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2207 if (!priv->update_caption_visibility)
2210 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2212 gtk_widget_show (priv->bcc_caption);
2214 gtk_widget_hide (priv->bcc_caption);
2216 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2220 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2221 ModestRecptEditor *editor)
2223 ModestMsgEditWindowPrivate *priv;
2225 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2226 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2227 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2229 if (editor == NULL) {
2230 GtkWidget *view_focus;
2231 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2233 /* This code should be kept in sync with ModestRecptEditor. The
2234 textview inside the recpt editor is the one that really gets the
2235 focus. As it's inside a scrolled window, and this one inside the
2236 hbox recpt editor inherits from, we'll need to go up in the
2237 hierarchy to know if the text view is part of the recpt editor
2238 or if it's a different text entry */
2240 if (gtk_widget_get_parent (view_focus)) {
2241 GtkWidget *first_parent;
2243 first_parent = gtk_widget_get_parent (view_focus);
2244 if (gtk_widget_get_parent (first_parent) &&
2245 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2246 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2251 editor = MODEST_RECPT_EDITOR (priv->to_field);
2255 modest_address_book_select_addresses (editor);
2260 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2262 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2264 modest_msg_edit_window_open_addressbook (window, NULL);
2268 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2269 gboolean show_toolbar)
2271 ModestWindowPrivate *parent_priv;
2272 const gchar *action_name;
2275 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2276 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2278 /* We can not just use the code of
2279 modest_msg_edit_window_setup_toolbar because it has a
2280 mixture of both initialization and creation code. */
2282 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2284 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2286 /* Update also the actions (to update the toggles in the
2287 menus), we have to do it manually because some other window
2288 of the same time could have changed it (remember that the
2289 toolbar fullscreen mode is shared by all the windows of the
2291 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2292 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2294 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2296 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2297 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2303 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2304 TnyHeaderFlags priority_flags)
2306 ModestMsgEditWindowPrivate *priv;
2307 ModestWindowPrivate *parent_priv;
2309 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2311 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2312 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2313 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2315 if (priv->priority_flags != priority_flags) {
2316 GtkAction *priority_action = NULL;
2318 priv->priority_flags = priority_flags;
2320 switch (priority_flags) {
2321 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2322 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2323 gtk_widget_show (priv->priority_icon);
2324 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2325 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2327 case TNY_HEADER_FLAG_LOW_PRIORITY:
2328 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2329 gtk_widget_show (priv->priority_icon);
2330 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2331 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2334 gtk_widget_hide (priv->priority_icon);
2335 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2336 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2339 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2340 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2345 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2348 ModestMsgEditWindowPrivate *priv;
2349 ModestWindowPrivate *parent_priv;
2350 gint current_format;
2352 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2354 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2355 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2357 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2358 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2360 if (current_format != file_format) {
2361 switch (file_format) {
2362 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2363 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2365 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2369 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2370 response = gtk_dialog_run (GTK_DIALOG (dialog));
2371 gtk_widget_destroy (dialog);
2372 if (response == GTK_RESPONSE_OK) {
2373 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2375 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2376 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2381 update_dimmed (window);
2386 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2389 ModestMsgEditWindowPrivate *priv;
2390 WPTextBufferFormat oldfmt, fmt;
2391 gint old_position = 0;
2395 GdkColor *color = NULL;
2396 gboolean bold, bold_set, italic, italic_set;
2397 gboolean underline, underline_set;
2398 gboolean strikethrough, strikethrough_set;
2399 gboolean position_set;
2400 gboolean font_size_set, font_set, color_set;
2403 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2404 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2406 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2408 /* First we get the currently selected font information */
2409 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2410 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2412 switch (oldfmt.text_position) {
2413 case TEXT_POSITION_NORMAL:
2416 case TEXT_POSITION_SUPERSCRIPT:
2424 g_object_set (G_OBJECT (dialog),
2425 "bold", oldfmt.bold != FALSE,
2426 "bold-set", !oldfmt.cs.bold,
2427 "underline", oldfmt.underline != FALSE,
2428 "underline-set", !oldfmt.cs.underline,
2429 "italic", oldfmt.italic != FALSE,
2430 "italic-set", !oldfmt.cs.italic,
2431 "strikethrough", oldfmt.strikethrough != FALSE,
2432 "strikethrough-set", !oldfmt.cs.strikethrough,
2433 "color", &oldfmt.color,
2434 "color-set", !oldfmt.cs.color,
2435 "size", wp_font_size[oldfmt.font_size],
2436 "size-set", !oldfmt.cs.font_size,
2437 "position", old_position,
2438 "position-set", !oldfmt.cs.text_position,
2439 "family", wp_get_font_name (oldfmt.font),
2440 "family-set", !oldfmt.cs.font,
2443 gtk_widget_show_all (dialog);
2444 response = gtk_dialog_run (GTK_DIALOG (dialog));
2445 if (response == GTK_RESPONSE_OK) {
2447 g_object_get( dialog,
2449 "bold-set", &bold_set,
2450 "underline", &underline,
2451 "underline-set", &underline_set,
2453 "italic-set", &italic_set,
2454 "strikethrough", &strikethrough,
2455 "strikethrough-set", &strikethrough_set,
2457 "color-set", &color_set,
2459 "size-set", &font_size_set,
2460 "family", &font_name,
2461 "family-set", &font_set,
2462 "position", &position,
2463 "position-set", &position_set,
2468 if (response == GTK_RESPONSE_OK) {
2469 memset(&fmt, 0, sizeof(fmt));
2475 fmt.italic = italic;
2476 fmt.cs.italic = TRUE;
2478 if (underline_set) {
2479 fmt.underline = underline;
2480 fmt.cs.underline = TRUE;
2482 if (strikethrough_set) {
2483 fmt.strikethrough = strikethrough;
2484 fmt.cs.strikethrough = TRUE;
2489 ? TEXT_POSITION_NORMAL
2490 : ( ( position == 1 )
2491 ? TEXT_POSITION_SUPERSCRIPT
2492 : TEXT_POSITION_SUBSCRIPT );
2493 fmt.cs.text_position = TRUE;
2497 fmt.cs.color = TRUE;
2500 fmt.font = wp_get_font_index(font_name,
2505 if (font_size_set) {
2506 fmt.font_size = wp_get_font_size_index(
2507 font_size, DEFAULT_FONT_SIZE);
2508 fmt.cs.font_size = TRUE;
2510 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2512 gtk_widget_destroy (dialog);
2514 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2518 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2520 ModestMsgEditWindowPrivate *priv;
2522 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2523 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2525 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2527 update_dimmed (window);
2532 modest_msg_edit_window_redo (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_redo (WP_TEXT_BUFFER (priv->text_buffer));
2541 update_dimmed (window);
2546 update_dimmed (ModestMsgEditWindow *window)
2548 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2549 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2553 gboolean editor_focused;
2555 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2556 editor_focused = gtk_widget_is_focus (priv->msg_body);
2558 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2559 gtk_action_set_sensitive (action, rich_text && editor_focused);
2560 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2561 /* gtk_action_set_sensitive (action, rich_text && editor_focused); */
2562 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2563 gtk_action_set_sensitive (action, rich_text && editor_focused);
2564 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2565 gtk_action_set_sensitive (action, rich_text && editor_focused);
2566 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2567 gtk_action_set_sensitive (action, rich_text && editor_focused);
2568 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2569 gtk_action_set_sensitive (action, rich_text && editor_focused);
2570 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2571 gtk_action_set_sensitive (action, rich_text && editor_focused);
2572 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2573 gtk_action_set_sensitive (action, rich_text && editor_focused);
2574 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2575 gtk_action_set_sensitive (action, rich_text && editor_focused);
2576 widget = priv->font_color_button;
2577 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2578 widget = priv->font_size_toolitem;
2579 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2580 widget = priv->font_face_toolitem;
2581 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2585 setup_insensitive_handlers (ModestMsgEditWindow *window)
2587 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2588 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2591 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2592 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2593 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2594 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2595 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2596 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2597 widget = priv->font_color_button;
2598 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2599 widget = priv->font_size_toolitem;
2600 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2601 widget = priv->font_face_toolitem;
2602 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2607 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2609 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2612 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2613 gtk_action_set_sensitive (action, can_undo);
2617 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2619 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2622 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/RedoMenu");
2623 gtk_action_set_sensitive (action, can_redo);
2627 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2630 GtkTextIter match_start, match_end;
2632 if (image_id == NULL)
2635 gtk_text_buffer_get_start_iter (buffer, &iter);
2637 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2638 GSList *tags = gtk_text_iter_get_tags (&match_start);
2640 for (node = tags; node != NULL; node = g_slist_next (node)) {
2641 GtkTextTag *tag = (GtkTextTag *) node->data;
2642 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2643 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2644 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2646 offset = gtk_text_iter_get_offset (&match_start);
2647 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2648 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2652 gtk_text_iter_forward_char (&iter);
2657 message_is_empty (ModestMsgEditWindow *window)
2659 ModestMsgEditWindowPrivate *priv = NULL;
2661 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2662 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2664 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2665 * so we can ignore markup.
2667 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2670 count = gtk_text_buffer_get_char_count (buf);
2676 msg_body_focus (GtkWidget *focus,
2677 GdkEventFocus *event,
2681 update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2686 recpt_field_changed (GtkTextBuffer *buffer,
2687 ModestMsgEditWindow *editor)
2689 update_send_dimming (editor);
2693 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2695 update_send_dimming (editor);
2699 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2701 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2702 const gchar *subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2703 if (message_is_empty(editor) || (subject == NULL || subject[0] == '\0')) {
2704 hildon_banner_show_information (NULL, NULL, _("mcen_ib_subject_or_body_not_modified"));
2706 hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2711 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2713 gboolean rich_text, editor_focused;
2715 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2716 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2717 editor_focused = gtk_widget_is_focus (priv->msg_body);
2720 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2721 else if (!editor_focused)
2722 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2726 reset_modified (ModestMsgEditWindow *editor)
2728 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2729 GtkTextBuffer *buffer;
2731 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2732 gtk_text_buffer_set_modified (buffer, FALSE);
2733 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2734 gtk_text_buffer_set_modified (buffer, FALSE);
2735 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2736 gtk_text_buffer_set_modified (buffer, FALSE);
2737 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2741 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2743 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2744 GtkTextBuffer *buffer;
2746 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2747 if (gtk_text_buffer_get_modified (buffer))
2749 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2750 if (gtk_text_buffer_get_modified (buffer))
2752 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2753 if (gtk_text_buffer_get_modified (buffer))
2755 if (gtk_text_buffer_get_modified (priv->text_buffer))
2765 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2767 ModestMsgEditWindowPrivate *priv = NULL;
2769 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2770 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2772 /* check if there's no recipient added */
2773 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2774 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2775 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2776 /* no recipient contents, then select contacts */
2777 modest_msg_edit_window_open_addressbook (window, NULL);
2781 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2782 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2785 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2786 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2789 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2790 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2794 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2795 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2796 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2803 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2804 ModestMsgEditWindow *window)
2806 modest_msg_edit_window_offer_attach_file (window);
2810 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2812 ModestMsgEditWindow *window)
2814 if (!GTK_WIDGET_VISIBLE (window))
2817 update_remove_attachment_dimming (window);
2818 update_copy_cut_dimming (window);
2819 update_paste_dimming (window);
2823 update_window_title (ModestMsgEditWindow *window)
2825 ModestMsgEditWindowPrivate *priv = NULL;
2826 const gchar *subject;
2828 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2829 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2830 if (subject == NULL || subject[0] == '\0')
2831 subject = _("mail_va_new_email");
2833 gtk_window_set_title (GTK_WINDOW (window), subject);
2838 subject_field_changed (GtkEditable *editable,
2839 ModestMsgEditWindow *window)
2841 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2842 update_window_title (window);
2843 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2844 update_send_dimming (window);
2848 subject_field_insert_text (GtkEditable *editable,
2850 gint new_text_length,
2852 ModestMsgEditWindow *window)
2854 GString *result = g_string_new ("");
2856 gint result_len = 0;
2858 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2859 gunichar c = g_utf8_get_char_validated (current, 8);
2860 /* Invalid unichar, stop */
2866 result = g_string_append_unichar (result, c);
2870 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2871 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2874 /* Prevent endless recursion */
2875 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2876 g_signal_emit_by_name (editable, "insert-text",
2877 (gpointer) result->str, (gpointer) result->len,
2878 (gpointer) position, (gpointer) window);
2879 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2883 g_string_free (result, TRUE);
2887 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2890 ModestMsgEditWindowPrivate *priv = NULL;
2892 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2893 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2895 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2898 gtk_widget_show_all (priv->find_toolbar);
2899 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2901 gtk_widget_hide_all (priv->find_toolbar);
2902 gtk_widget_grab_focus (priv->msg_body);
2908 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2910 GtkTextIter *match_start,
2911 GtkTextIter *match_end)
2913 GtkTextIter end_iter;
2914 gchar *str_casefold;
2917 gchar *range_casefold;
2920 gboolean result = FALSE;
2927 gtk_text_iter_forward_to_end (&end_iter);
2929 str_casefold = g_utf8_casefold (str, -1);
2930 str_chars_n = strlen (str);
2932 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2933 range_casefold = g_utf8_casefold (range_text, -1);
2934 range_chars_n = strlen (range_casefold);
2936 if (range_chars_n < str_chars_n) {
2937 g_free (str_casefold);
2938 g_free (range_text);
2939 g_free (range_casefold);
2943 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2944 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2945 if (!g_utf8_collate (range_subtext, str_casefold)) {
2946 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2948 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2949 match_start, match_end, NULL);
2950 g_free (found_text);
2952 g_free (range_subtext);
2956 g_free (str_casefold);
2957 g_free (range_text);
2958 g_free (range_casefold);
2965 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2966 ModestMsgEditWindow *window)
2968 gchar *current_search = NULL;
2969 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2971 GtkTextIter selection_start, selection_end;
2972 GtkTextIter match_start, match_end;
2973 gboolean continue_search = FALSE;
2975 if (message_is_empty (window)) {
2976 g_free (priv->last_search);
2977 priv->last_search = NULL;
2978 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
2982 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
2983 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2984 g_free (current_search);
2985 g_free (priv->last_search);
2986 priv->last_search = NULL;
2987 /* Information banner about empty search */
2988 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
2992 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
2993 continue_search = TRUE;
2995 g_free (priv->last_search);
2996 priv->last_search = g_strdup (current_search);
2999 if (continue_search) {
3000 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3001 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3002 &match_start, &match_end);
3004 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3006 GtkTextIter buffer_start;
3007 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3008 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3009 &match_start, &match_end);
3011 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3014 /* Mark as selected the string found in search */
3016 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3017 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3019 g_free (priv->last_search);
3020 priv->last_search = NULL;
3022 g_free (current_search);
3026 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3027 ModestMsgEditWindow *window)
3029 GtkToggleAction *toggle;
3030 ModestWindowPrivate *parent_priv;
3031 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3033 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3034 gtk_toggle_action_set_active (toggle, FALSE);
3038 update_remove_attachment_dimming (ModestMsgEditWindow *window)
3040 ModestWindowPrivate *parent_priv;
3041 ModestMsgEditWindowPrivate *priv;
3043 GList *selected_attachments = NULL;
3044 gint n_att_selected = 0;
3046 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3047 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3049 selected_attachments = modest_attachments_view_get_selection (
3050 MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
3051 n_att_selected = g_list_length (selected_attachments);
3052 g_list_free (selected_attachments);
3054 action = gtk_ui_manager_get_action (
3055 parent_priv->ui_manager,
3056 "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
3057 gtk_action_set_sensitive (action, n_att_selected == 1);
3061 update_copy_cut_dimming (ModestMsgEditWindow *window)
3063 ModestWindowPrivate *parent_priv = NULL;
3064 ModestMsgEditWindowPrivate *priv = NULL;
3065 GtkAction *action = NULL;
3066 gboolean has_selection = FALSE;
3067 GtkWidget *focused = NULL;
3069 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3070 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3071 focused = gtk_window_get_focus (GTK_WINDOW (window));
3073 if (GTK_IS_TEXT_VIEW (focused)) {
3074 GtkTextBuffer *buffer = NULL;
3075 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
3076 has_selection = gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (buffer));
3077 } else if (GTK_IS_EDITABLE (focused)) {
3078 has_selection = gtk_editable_get_selection_bounds (GTK_EDITABLE (focused), NULL, NULL);
3081 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
3082 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3083 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
3084 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3089 update_paste_dimming (ModestMsgEditWindow *window)
3091 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3092 GtkAction *action = NULL;
3093 GtkClipboard *clipboard = NULL;
3094 ModestEmailClipboard *e_clipboard;
3098 focused = gtk_window_get_focus (GTK_WINDOW (window));
3100 e_clipboard = modest_runtime_get_email_clipboard ();
3101 if (!modest_email_clipboard_cleared (e_clipboard)) {
3104 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3105 active = gtk_clipboard_wait_is_text_available (clipboard);
3109 if (MODEST_IS_ATTACHMENTS_VIEW (focused))
3113 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
3114 gtk_action_set_sensitive (action, active);
3119 update_select_all_dimming (ModestMsgEditWindow *window)
3122 gboolean dimmed = FALSE;
3124 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3126 focused = gtk_window_get_focus (GTK_WINDOW (window));
3127 if (GTK_IS_ENTRY (focused)) {
3128 const gchar *current_text;
3129 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
3130 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
3131 } else if (GTK_IS_TEXT_VIEW (focused)) {
3132 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
3133 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
3134 } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
3137 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
3138 gtk_action_set_sensitive (action, !dimmed);
3142 update_zoom_dimming (ModestMsgEditWindow *window)
3145 gboolean dimmed = FALSE;
3147 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3149 focused = gtk_window_get_focus (GTK_WINDOW (window));
3150 dimmed = ! WP_IS_TEXT_VIEW (focused);
3151 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
3152 gtk_action_set_sensitive (action, !dimmed);
3156 update_send_dimming (ModestMsgEditWindow *window)
3158 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3159 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3160 GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
3161 const gchar *subject;
3162 gboolean dim = FALSE;
3165 to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
3166 cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
3167 bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
3168 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3170 dim = ((gtk_text_buffer_get_char_count (to_buffer) +
3171 gtk_text_buffer_get_char_count (cc_buffer) +
3172 gtk_text_buffer_get_char_count (bcc_buffer)) == 0)
3173 || (subject == NULL || subject[0] == '\0')
3174 || message_is_empty(window);
3176 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
3177 gtk_action_set_sensitive (action, !dim);
3178 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
3179 gtk_action_set_sensitive (action, !dim);
3183 edit_menu_activated (GtkAction *action,
3186 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3188 update_select_all_dimming (window);
3189 update_copy_cut_dimming (window);
3190 update_paste_dimming (window);
3193 view_menu_activated (GtkAction *action,
3196 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3198 update_zoom_dimming (window);
3202 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3204 ModestMsgEditWindowPrivate *priv;
3206 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3211 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3214 ModestMsgEditWindowPrivate *priv;
3216 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3222 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3225 ModestMsgEditWindowPrivate *priv;
3226 TnyHeader *header = NULL;
3228 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3229 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3231 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3232 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3234 if (priv->draft_msg != NULL) {
3235 header = tny_msg_get_header (priv->draft_msg);
3236 if (TNY_IS_HEADER (header)) {
3237 modest_window_mgr_unregister_header (mgr, header);
3239 g_object_unref (priv->draft_msg);
3242 if (draft != NULL) {
3243 g_object_ref (draft);
3244 header = tny_msg_get_header (draft);
3245 if (TNY_IS_HEADER (header))
3246 modest_window_mgr_register_header (mgr, header);
3247 if (priv->msg_uid) {
3248 g_free (priv->msg_uid);
3249 priv->msg_uid = NULL;
3251 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3254 priv->draft_msg = draft;
3258 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3259 GtkTextIter *start, GtkTextIter *end,
3262 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3263 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3266 if (tag == NULL+13) return;
3267 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3268 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3269 replace_with_attachments (window, priv->attachments);
3274 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3277 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3279 g_return_if_fail (TNY_IS_MIME_PART (part));
3280 priv->attachments = g_list_prepend (priv->attachments, part);
3281 g_object_ref (part);
3282 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3283 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3284 gtk_widget_show_all (priv->attachments_caption);
3285 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3289 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3291 ModestMsgEditWindowPrivate *priv;
3293 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3294 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3296 return priv->msg_uid;