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 recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
94 static void send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
95 static void style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
96 static void setup_insensitive_handlers (ModestMsgEditWindow *editor);
97 static void reset_modified (ModestMsgEditWindow *editor);
99 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
100 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
101 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
102 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
103 GtkTextIter *start, GtkTextIter *end,
105 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
106 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
107 static void subject_field_insert_text (GtkEditable *editable,
109 gint new_text_length,
111 ModestMsgEditWindow *window);
112 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
114 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
116 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
118 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
119 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
120 GdkEventWindowState *event,
122 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
123 ModestRecptEditor *editor);
124 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
125 ModestMsgEditWindow *window);
127 /* ModestWindow methods implementation */
128 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
129 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
130 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
131 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
132 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
133 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
134 gboolean show_toolbar);
135 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
137 ModestMsgEditWindow *window);
138 static void update_window_title (ModestMsgEditWindow *window);
139 static void update_dimmed (ModestMsgEditWindow *window);
140 static void update_paste_dimming (ModestMsgEditWindow *window);
141 static void update_select_all_dimming (ModestMsgEditWindow *window);
142 static void update_zoom_dimming (ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
148 ModestMsgEditWindow *window);
149 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
151 GtkTextIter *match_start,
152 GtkTextIter *match_end);
154 static void DEBUG_BUFFER (WPTextBuffer *buffer)
159 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
160 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
161 while (!gtk_text_iter_is_end (&iter)) {
162 GString *output = g_string_new ("");
163 GSList *toggled_tags;
166 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
167 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
168 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
169 GtkTextTag *tag = (GtkTextTag *) node->data;
171 g_object_get (G_OBJECT (tag), "name", &name, NULL);
172 output = g_string_append (output, name);
173 g_string_append (output, " ");
175 output = g_string_append (output, "] OPENED [ ");
176 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
177 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
178 GtkTextTag *tag = (GtkTextTag *) node->data;
180 g_object_get (G_OBJECT (tag), "name", &name, NULL);
181 output = g_string_append (output, name);
182 g_string_append (output, " ");
184 output = g_string_append (output, "]\n");
185 g_message ("%s", output->str);
186 g_string_free (output, TRUE);
187 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
189 g_message ("END BUFFER");
194 /* static gboolean */
195 /* on_key_pressed (GtkWidget *self, */
196 /* GdkEventKey *event, */
197 /* gpointer user_data); */
199 static void edit_menu_activated (GtkAction *action,
201 static void view_menu_activated (GtkAction *action,
204 /* list my signals */
211 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
212 struct _ModestMsgEditWindowPrivate {
214 GtkWidget *header_box;
216 ModestPairList *from_field_protos;
217 GtkWidget *from_field;
221 GtkWidget *bcc_field;
222 GtkWidget *subject_field;
223 GtkWidget *attachments_view;
224 GtkWidget *priority_icon;
225 GtkWidget *add_attachment_button;
227 GtkWidget *cc_caption;
228 GtkWidget *bcc_caption;
229 gboolean update_caption_visibility;
230 GtkWidget *attachments_caption;
232 GtkTextBuffer *text_buffer;
234 GtkWidget *font_size_toolitem;
235 GtkWidget *font_face_toolitem;
236 GtkWidget *font_color_button;
237 GSList *font_items_group;
238 GtkWidget *font_tool_button_label;
239 GSList *size_items_group;
240 GtkWidget *size_tool_button_label;
242 GtkWidget *find_toolbar;
246 GtkWidget *scroll_area;
247 gint last_vadj_upper;
252 TnyHeaderFlags priority_flags;
256 gulong clipboard_change_handler_id;
265 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
266 MODEST_TYPE_MSG_EDIT_WINDOW, \
267 ModestMsgEditWindowPrivate))
269 static GtkWindowClass *parent_class = NULL;
271 /* uncomment the following if you have defined any signals */
272 /* static guint signals[LAST_SIGNAL] = {0}; */
275 modest_msg_edit_window_get_type (void)
277 static GType my_type = 0;
279 static const GTypeInfo my_info = {
280 sizeof(ModestMsgEditWindowClass),
281 NULL, /* base init */
282 NULL, /* base finalize */
283 (GClassInitFunc) modest_msg_edit_window_class_init,
284 NULL, /* class finalize */
285 NULL, /* class data */
286 sizeof(ModestMsgEditWindow),
288 (GInstanceInitFunc) modest_msg_edit_window_init,
291 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
292 "ModestMsgEditWindow",
295 wp_text_buffer_library_init ();
301 save_state (ModestWindow *self)
303 modest_widget_memory_save (modest_runtime_get_conf(),
304 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
309 restore_settings (ModestMsgEditWindow *self)
311 modest_widget_memory_restore (modest_runtime_get_conf(),
312 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
317 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
319 GObjectClass *gobject_class;
320 ModestWindowClass *modest_window_class;
321 gobject_class = (GObjectClass*) klass;
322 modest_window_class = (ModestWindowClass*) klass;
324 parent_class = g_type_class_peek_parent (klass);
325 gobject_class->finalize = modest_msg_edit_window_finalize;
327 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
328 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
329 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
330 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
331 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
332 modest_window_class->save_state_func = save_state;
333 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
335 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
339 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
341 ModestMsgEditWindowPrivate *priv;
342 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
344 priv->msg_body = NULL;
345 priv->from_field = NULL;
346 priv->to_field = NULL;
347 priv->cc_field = NULL;
348 priv->bcc_field = NULL;
349 priv->subject_field = NULL;
350 priv->attachments = NULL;
352 priv->zoom_level = 1.0;
354 priv->cc_caption = NULL;
355 priv->bcc_caption = NULL;
356 priv->update_caption_visibility = FALSE;
358 priv->priority_flags = 0;
360 priv->find_toolbar = NULL;
361 priv->last_search = NULL;
363 priv->draft_msg = NULL;
364 priv->outbox_msg = NULL;
365 priv->msg_uid = NULL;
366 priv->clipboard_change_handler_id = 0;
369 priv->last_vadj_upper = 0;
373 /* FIXME: this is a dup from the one in gtk/ */
376 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
378 static ModestPairList*
379 get_transports (void)
381 GSList *transports = NULL;
383 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
384 GSList *accounts = modest_account_mgr_account_names (account_mgr,
385 TRUE /* only enabled accounts. */);
387 GSList *cursor = accounts;
389 gchar *account_name = cursor->data;
390 gchar *from_string = NULL;
392 from_string = modest_account_mgr_get_from_string (account_mgr,
396 if (from_string && account_name) {
397 gchar *name = account_name;
398 ModestPair *pair = modest_pair_new ((gpointer) name,
399 (gpointer) from_string , TRUE);
400 transports = g_slist_prepend (transports, pair);
403 cursor = cursor->next;
405 g_slist_free (accounts); /* only free the accounts, not the elements,
406 * because they are used in the pairlist */
410 void vadj_changed (GtkAdjustment *adj,
411 ModestMsgEditWindow *window)
413 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
415 GdkRectangle rectangle, cursor_rectangle;
416 GtkTextIter position;
420 /* We detect if cursor is visible using the full height, not only the center. This
422 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
423 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
425 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
426 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
428 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
429 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
431 if (gtk_widget_is_focus (priv->msg_body) &&
433 if (priv->last_vadj_upper != adj->upper) {
436 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
437 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
438 insert, 0.1, FALSE, 0.0, 0.0);
441 priv->last_vadj_upper = adj->upper;
446 init_window (ModestMsgEditWindow *obj)
448 GtkWidget *from_caption, *to_caption, *subject_caption;
449 GtkWidget *main_vbox;
450 ModestMsgEditWindowPrivate *priv;
452 GtkSizeGroup *size_group;
454 GtkWidget *subject_box;
455 GtkWidget *attachment_icon;
456 GtkWidget *window_box;
457 #if (GTK_MINOR_VERSION >= 10)
458 GdkAtom deserialize_type;
460 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
462 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
464 /* Note: This ModestPairList* must exist for as long as the combo
465 * that uses it, because the ModestComboBox uses the ID opaquely,
466 * so it can't know how to manage its memory. */
467 priv->from_field_protos = get_transports ();
469 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
471 priv->to_field = modest_recpt_editor_new ();
472 priv->cc_field = modest_recpt_editor_new ();
473 priv->bcc_field = modest_recpt_editor_new ();
474 subject_box = gtk_hbox_new (FALSE, 0);
475 priv->priority_icon = gtk_image_new ();
476 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
477 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
478 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
479 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
480 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
481 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
482 priv->add_attachment_button = gtk_button_new ();
483 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
484 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
485 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
486 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
487 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
488 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
489 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
490 priv->attachments_view = modest_attachments_view_new (NULL);
492 priv->header_box = gtk_vbox_new (FALSE, 0);
494 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
495 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
496 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
497 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
498 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
499 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
500 g_object_unref (size_group);
502 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
503 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
504 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
505 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
506 gtk_size_group_add_widget (size_group, priv->subject_field);
507 gtk_size_group_add_widget (size_group, priv->attachments_view);
508 g_object_unref (size_group);
510 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
511 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
512 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
513 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
514 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
515 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
516 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
519 priv->msg_body = wp_text_view_new ();
520 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
521 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
522 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
523 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
524 #if (GTK_MINOR_VERSION >= 10)
525 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
526 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
528 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
529 deserialize_type, TRUE);
531 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
533 priv->find_toolbar = hildon_find_toolbar_new (NULL);
534 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
536 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
538 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
539 G_CALLBACK (text_buffer_refresh_attributes), obj);
540 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
541 G_CALLBACK (text_buffer_can_undo), obj);
542 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
543 G_CALLBACK (text_buffer_can_redo), obj);
544 g_signal_connect (G_OBJECT (obj), "window-state-event",
545 G_CALLBACK (modest_msg_edit_window_window_state_event),
547 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
548 G_CALLBACK (text_buffer_apply_tag), obj);
549 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
550 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
551 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
552 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
553 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
554 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
556 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
557 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
559 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
560 G_CALLBACK (msg_body_focus), obj);
561 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
562 G_CALLBACK (msg_body_focus), obj);
563 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
564 "changed", G_CALLBACK (recpt_field_changed), obj);
565 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
566 "changed", G_CALLBACK (recpt_field_changed), obj);
567 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
568 "changed", G_CALLBACK (recpt_field_changed), obj);
569 recpt_field_changed (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)), MODEST_MSG_EDIT_WINDOW (obj));
570 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
571 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
573 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
574 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
576 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
577 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
578 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
579 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
581 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
583 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
584 frame = gtk_frame_new (NULL);
585 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
587 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
588 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
589 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
591 G_CALLBACK (vadj_changed),
593 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
595 window_box = gtk_vbox_new (FALSE, 0);
596 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
597 gtk_container_add (GTK_CONTAINER(obj), window_box);
598 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
599 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
601 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
602 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
607 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
609 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
611 if (g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
612 priv->clipboard_change_handler_id))
613 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
614 priv->clipboard_change_handler_id);
618 modest_msg_edit_window_finalize (GObject *obj)
620 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
622 /* Sanity check: shouldn't be needed, the window mgr should
623 call this function before */
624 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
626 if (priv->draft_msg != NULL) {
627 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
628 if (TNY_IS_HEADER (header)) {
629 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
630 modest_window_mgr_unregister_header (mgr, header);
632 g_object_unref (priv->draft_msg);
633 priv->draft_msg = NULL;
635 if (priv->outbox_msg != NULL) {
636 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
637 if (TNY_IS_HEADER (header)) {
638 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
639 modest_window_mgr_unregister_header (mgr, header);
641 g_object_unref (priv->outbox_msg);
642 priv->outbox_msg = NULL;
644 if (priv->msg_uid != NULL) {
645 g_free (priv->msg_uid);
646 priv->msg_uid = NULL;
649 /* This had to stay alive for as long as the combobox that used it: */
650 modest_pair_list_free (priv->from_field_protos);
652 G_OBJECT_CLASS(parent_class)->finalize (obj);
656 menubar_to_menu (GtkUIManager *ui_manager)
658 GtkWidget *main_menu;
662 /* Create new main menu */
663 main_menu = gtk_menu_new();
665 /* Get the menubar from the UI manager */
666 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
668 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
672 menu = GTK_WIDGET (iter->data);
673 gtk_widget_reparent(menu, main_menu);
675 iter = g_list_next (iter);
681 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
683 GdkPixbufLoader *loader;
686 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
691 tny_stream_reset (TNY_STREAM (stream));
692 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
693 unsigned char read_buffer[128];
695 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
696 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
700 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
701 g_object_ref (pixbuf);
702 gdk_pixbuf_loader_close (loader, NULL);
703 g_object_unref (loader);
705 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
706 GdkPixbuf *new_pixbuf;
708 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
709 gdk_pixbuf_get_width (pixbuf);
710 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
711 g_object_unref (pixbuf);
719 replace_with_attachments (ModestMsgEditWindow *self, GList *attachments)
721 ModestMsgEditWindowPrivate *priv;
724 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
726 for (node = attachments; node != NULL; node = g_list_next (node)) {
727 TnyMimePart *part = (TnyMimePart *) node->data;
728 const gchar *cid = tny_mime_part_get_content_id (part);
729 const gchar *mime_type = tny_mime_part_get_content_type (part);
730 if ((cid != NULL)&&(mime_type != NULL)) {
731 TnyStream *stream = tny_mime_part_get_stream (part);
732 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
733 g_object_unref (stream);
735 if (pixbuf != NULL) {
736 /* wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf); */
737 g_object_unref (pixbuf);
744 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
747 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
749 for (node = attachments; node != NULL; node = g_list_next (node)) {
750 TnyMimePart *part = (TnyMimePart *) node->data;
751 const gchar *cid = tny_mime_part_get_content_id (part);
753 char *invalid = NULL;
754 gint int_cid = strtol (cid, &invalid, 10);
755 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
756 priv->last_cid = int_cid;
764 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
767 const gchar *to, *cc, *bcc, *subject;
769 ModestMsgEditWindowPrivate *priv;
771 TnyHeaderFlags priority_flags;
772 TnyFolder *msg_folder;
773 gboolean is_html = FALSE;
775 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
776 g_return_if_fail (TNY_IS_MSG (msg));
778 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
780 header = tny_msg_get_header (msg);
781 to = tny_header_get_to (header);
782 cc = tny_header_get_cc (header);
783 bcc = tny_header_get_bcc (header);
784 subject = tny_header_get_subject (header);
785 priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
788 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
790 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
791 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
792 gtk_widget_show (priv->cc_caption);
793 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
794 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
795 gtk_widget_hide (priv->cc_caption);
798 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
799 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
800 gtk_widget_show (priv->bcc_caption);
801 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
802 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
803 gtk_widget_hide (priv->bcc_caption);
806 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
807 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
810 update_window_title (self);
812 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
813 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
815 if ((body == NULL)||(body[0] == '\0')) {
817 body = modest_text_utils_convert_to_html ("");
820 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
821 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
824 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
827 if (preserve_is_rich && !is_html) {
828 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
829 /* Get the default format required from configuration */
830 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
831 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
834 /* Set the default focus depending on having already a To: field or not */
835 if ((!to)||(*to == '\0')) {
836 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
838 gtk_widget_grab_focus (priv->msg_body);
841 /* TODO: lower priority, select in the From: combo to the
842 value that comes from msg <- not sure, should it be
845 /* Add attachments to the view */
846 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
847 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
848 if (priv->attachments == NULL) {
849 gtk_widget_hide (priv->attachments_caption);
851 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
852 gtk_widget_show_all (priv->attachments_caption);
853 replace_with_attachments (self, priv->attachments);
855 update_last_cid (self, priv->attachments);
857 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
859 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
860 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
862 reset_modified (self);
864 update_dimmed (self);
865 text_buffer_can_undo (priv->text_buffer, FALSE, self);
866 text_buffer_can_redo (priv->text_buffer, FALSE, self);
869 g_free (priv->msg_uid);
870 priv->msg_uid = NULL;
873 /* we should set a reference to the incoming message if it is a draft */
874 msg_folder = tny_msg_get_folder (msg);
876 if (modest_tny_folder_is_local_folder (msg_folder)) {
877 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
878 if (type == TNY_FOLDER_TYPE_DRAFTS)
879 priv->draft_msg = g_object_ref(msg);
880 if (type == TNY_FOLDER_TYPE_OUTBOX)
881 priv->outbox_msg = g_object_ref(msg);
882 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
884 g_object_unref (msg_folder);
889 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
892 GList *item_children, *node;
893 GtkWidget *bin_child;
895 bin_child = gtk_bin_get_child (GTK_BIN(item));
897 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
899 for (node = item_children; node != NULL; node = g_list_next (node)) {
900 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
901 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
904 g_list_free (item_children);
908 menu_tool_button_dont_expand (GtkMenuToolButton *item)
911 GList *item_children, *node;
913 box = gtk_bin_get_child (GTK_BIN (item));
914 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
915 item_children = gtk_container_get_children (GTK_CONTAINER (box));
917 for (node = item_children; node != NULL; node = g_list_next (node)) {
918 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
919 if (GTK_IS_TOGGLE_BUTTON (node->data))
920 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
921 else if (GTK_IS_BUTTON (node->data))
922 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
924 g_list_free (item_children);
929 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
931 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
932 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
933 GtkWidget *placeholder;
934 GtkWidget *tool_item;
939 GtkWidget *sizes_menu;
940 GtkWidget *fonts_menu;
941 GSList *radio_group = NULL;
946 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
947 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
949 /* should we hide the toolbar? */
950 if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
951 gtk_widget_hide (parent_priv->toolbar);
953 /* Font color placeholder */
954 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
955 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
958 tool_item = GTK_WIDGET (gtk_tool_item_new ());
959 priv->font_color_button = hildon_color_button_new ();
960 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
961 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
962 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
963 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
964 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
965 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
966 g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
968 /* Font size and face placeholder */
969 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
970 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
972 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
973 priv->size_tool_button_label = gtk_label_new (NULL);
974 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
975 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
976 size_text,"</span>", NULL);
977 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
979 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
980 sizes_menu = gtk_menu_new ();
981 priv->size_items_group = NULL;
983 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
984 GtkWidget *size_menu_item;
986 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
987 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
988 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
989 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
990 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
991 gtk_widget_show (size_menu_item);
993 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
997 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
998 GtkWidget *item = (GtkWidget *) node->data;
999 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1003 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1004 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1005 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1006 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1007 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1008 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1009 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1010 priv->font_size_toolitem = tool_item;
1013 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1014 priv->font_tool_button_label = gtk_label_new (NULL);
1015 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1016 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1018 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1019 fonts_menu = gtk_menu_new ();
1020 priv->font_items_group = NULL;
1022 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1023 GtkWidget *font_menu_item;
1024 GtkWidget *child_label;
1026 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1027 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1028 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1029 wp_get_font_name (font_index), "</span>", NULL);
1030 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1033 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1034 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1035 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1036 gtk_widget_show (font_menu_item);
1038 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1041 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1042 GtkWidget *item = (GtkWidget *) node->data;
1043 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1046 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1047 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1048 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1049 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1050 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1051 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1052 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1053 priv->font_face_toolitem = tool_item;
1055 /* Set expand and homogeneous for remaining items */
1056 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1057 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1058 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1059 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1060 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1061 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1062 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1063 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1064 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1072 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1075 ModestWindowPrivate *parent_priv;
1076 ModestMsgEditWindowPrivate *priv;
1077 GtkActionGroup *action_group;
1078 GError *error = NULL;
1079 GdkPixbuf *window_icon = NULL;
1082 gboolean prefer_formatted;
1084 ModestPair *account_pair = NULL;
1086 g_return_val_if_fail (msg, NULL);
1087 g_return_val_if_fail (account_name, NULL);
1089 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1091 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1092 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1094 parent_priv->ui_manager = gtk_ui_manager_new();
1095 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1096 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1098 /* Add common actions */
1099 gtk_action_group_add_actions (action_group,
1100 modest_msg_edit_action_entries,
1101 G_N_ELEMENTS (modest_msg_edit_action_entries),
1103 gtk_action_group_add_toggle_actions (action_group,
1104 modest_msg_edit_toggle_action_entries,
1105 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1107 gtk_action_group_add_radio_actions (action_group,
1108 modest_msg_edit_alignment_radio_action_entries,
1109 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1111 G_CALLBACK (modest_ui_actions_on_change_justify),
1113 gtk_action_group_add_radio_actions (action_group,
1114 modest_msg_edit_zoom_action_entries,
1115 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1117 G_CALLBACK (modest_ui_actions_on_change_zoom),
1119 gtk_action_group_add_radio_actions (action_group,
1120 modest_msg_edit_priority_action_entries,
1121 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1123 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1125 gtk_action_group_add_radio_actions (action_group,
1126 modest_msg_edit_file_format_action_entries,
1127 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1128 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1129 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1131 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1132 g_object_unref (action_group);
1134 /* Load the UI definition */
1135 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1137 if (error != NULL) {
1138 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1139 g_clear_error (&error);
1142 /* Add accelerators */
1143 gtk_window_add_accel_group (GTK_WINDOW (obj),
1144 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1147 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1148 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1151 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1153 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1155 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1157 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1158 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1160 setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
1162 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1163 if (account_pair != NULL)
1164 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1166 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1168 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1170 /* Set window icon */
1171 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1173 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1174 g_object_unref (window_icon);
1177 /* Dim at start clipboard actions */
1178 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1179 gtk_action_set_sensitive (action, FALSE);
1180 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1181 gtk_action_set_sensitive (action, FALSE);
1182 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1183 gtk_action_set_sensitive (action, FALSE);
1185 /* Update select all */
1186 update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1187 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
1188 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
1189 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
1190 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
1192 /* set initial state of cc and bcc */
1193 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1194 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1195 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1196 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1197 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1198 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1200 /* Setup the file format */
1201 conf = modest_runtime_get_conf ();
1202 prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
1204 g_clear_error (&error);
1205 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
1207 file_format = (prefer_formatted) ?
1208 MODEST_FILE_FORMAT_FORMATTED_TEXT :
1209 MODEST_FILE_FORMAT_PLAIN_TEXT;
1210 modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
1212 update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1213 priv->update_caption_visibility = TRUE;
1215 reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1217 return (ModestWindow*) obj;
1221 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1223 GString **string_buffer = (GString **) user_data;
1225 *string_buffer = g_string_append (*string_buffer, buffer);
1231 * @result: A new string which should be freed with g_free().
1234 get_formatted_data (ModestMsgEditWindow *edit_window)
1236 ModestMsgEditWindowPrivate *priv;
1237 GString *string_buffer = g_string_new ("");
1239 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1241 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1243 return g_string_free (string_buffer, FALSE);
1248 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1251 const gchar *account_name;
1252 ModestMsgEditWindowPrivate *priv;
1254 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1256 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1258 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1259 g_return_val_if_fail (account_name, NULL);
1262 /* don't free these (except from) */
1263 data = g_slice_new0 (MsgData);
1264 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1266 data->account_name = g_strdup (account_name);
1267 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1268 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1269 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1270 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1271 if (priv->draft_msg) {
1272 data->draft_msg = g_object_ref (priv->draft_msg);
1273 } else if (priv->outbox_msg) {
1274 data->draft_msg = g_object_ref (priv->outbox_msg);
1276 data->draft_msg = NULL;
1279 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1281 gtk_text_buffer_get_bounds (buf, &b, &e);
1282 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1284 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1285 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1287 data->html_body = NULL;
1289 /* deep-copy the data */
1290 GList *cursor = priv->attachments;
1291 data->attachments = NULL;
1293 if (!(TNY_IS_MIME_PART(cursor->data))) {
1294 g_warning ("strange data in attachment list");
1295 cursor = g_list_next (cursor);
1298 data->attachments = g_list_append (data->attachments,
1299 g_object_ref (cursor->data));
1300 cursor = g_list_next (cursor);
1303 data->priority_flags = priv->priority_flags;
1310 unref_gobject (GObject *obj, gpointer data)
1312 if (!G_IS_OBJECT(obj))
1314 g_object_unref (obj);
1318 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1321 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1329 g_free (data->subject);
1330 g_free (data->plain_body);
1331 g_free (data->html_body);
1332 g_free (data->account_name);
1334 if (data->draft_msg != NULL) {
1335 g_object_unref (data->draft_msg);
1336 data->draft_msg = NULL;
1339 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1340 g_list_free (data->attachments);
1342 g_slice_free (MsgData, data);
1346 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1349 ModestMsgEditWindowPrivate *priv = NULL;
1350 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1352 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1354 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1356 return MODEST_MSG_EDIT_FORMAT_HTML;
1358 return MODEST_MSG_EDIT_FORMAT_TEXT;
1362 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1363 ModestMsgEditFormat format)
1365 ModestMsgEditWindowPrivate *priv;
1367 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1368 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1371 case MODEST_MSG_EDIT_FORMAT_HTML:
1372 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1374 case MODEST_MSG_EDIT_FORMAT_TEXT:
1375 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1378 g_return_if_reached ();
1382 ModestMsgEditFormatState *
1383 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1385 ModestMsgEditFormatState *format_state = NULL;
1386 ModestMsgEditWindowPrivate *priv;
1387 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1389 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1390 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1392 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1394 format_state = g_new0 (ModestMsgEditFormatState, 1);
1395 format_state->bold = buffer_format->bold&0x1;
1396 format_state->italics = buffer_format->italic&0x1;
1397 format_state->bullet = buffer_format->bullet&0x1;
1398 format_state->color = buffer_format->color;
1399 format_state->font_size = buffer_format->font_size;
1400 format_state->font_family = wp_get_font_name (buffer_format->font);
1401 format_state->justification = buffer_format->justification;
1402 g_free (buffer_format);
1404 return format_state;
1409 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1410 const ModestMsgEditFormatState *format_state)
1412 ModestMsgEditWindowPrivate *priv;
1413 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1414 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1415 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1416 g_return_if_fail (format_state != NULL);
1418 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1419 gtk_widget_grab_focus (priv->msg_body);
1420 buffer_format->bold = (format_state->bold != FALSE);
1421 buffer_format->italic = (format_state->italics != FALSE);
1422 buffer_format->color = format_state->color;
1423 buffer_format->font_size = format_state->font_size;
1424 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1425 buffer_format->justification = format_state->justification;
1426 buffer_format->bullet = format_state->bullet;
1428 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1430 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1431 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1432 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1433 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1434 buffer_format->cs.font = (buffer_format->font != current_format->font);
1435 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1436 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1438 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1439 if (buffer_format->cs.bold) {
1440 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1442 if (buffer_format->cs.italic) {
1443 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1445 if (buffer_format->cs.color) {
1446 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1448 if (buffer_format->cs.font_size) {
1449 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1451 if (buffer_format->cs.justification) {
1452 switch (buffer_format->justification) {
1453 case GTK_JUSTIFY_LEFT:
1454 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1456 case GTK_JUSTIFY_CENTER:
1457 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1459 case GTK_JUSTIFY_RIGHT:
1460 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1467 if (buffer_format->cs.font) {
1468 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1470 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1471 if (buffer_format->cs.bullet) {
1472 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1474 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1476 g_free (current_format);
1481 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1483 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1485 ModestWindowPrivate *parent_priv;
1486 ModestMsgEditWindowPrivate *priv;
1487 GtkWidget *new_size_menuitem;
1488 GtkWidget *new_font_menuitem;
1490 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1491 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1493 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1494 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1495 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1496 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1498 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1499 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1500 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1503 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1505 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1506 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1508 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1509 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1511 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
1512 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet);
1514 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1515 G_CALLBACK (modest_msg_edit_window_color_button_change),
1517 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1518 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1519 G_CALLBACK (modest_msg_edit_window_color_button_change),
1522 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1523 buffer_format->font_size))->data);
1524 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1528 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1529 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1530 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1532 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1533 G_CALLBACK (modest_msg_edit_window_size_change),
1535 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1536 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1537 G_CALLBACK (modest_msg_edit_window_size_change),
1541 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1542 buffer_format->font))->data);
1543 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1547 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1548 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1549 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1551 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1552 G_CALLBACK (modest_msg_edit_window_font_change),
1554 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1555 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1556 G_CALLBACK (modest_msg_edit_window_font_change),
1560 g_free (buffer_format);
1566 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1569 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1570 ModestMsgEditWindowPrivate *priv;
1571 GtkWidget *dialog = NULL;
1573 const GdkColor *new_color = NULL;
1575 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1576 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1578 #ifdef MODEST_HILDON_VERSION_0
1579 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1580 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1582 dialog = hildon_color_chooser_new ();
1583 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1584 #endif /*MODEST_HILDON_VERSION_0*/
1585 g_free (buffer_format);
1587 response = gtk_dialog_run (GTK_DIALOG (dialog));
1589 case GTK_RESPONSE_OK: {
1590 #ifdef MODEST_HILDON_VERSION_0
1591 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1594 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1596 #endif /*MODEST_HILDON_VERSION_0*/
1603 gtk_widget_destroy (dialog);
1605 if (new_color != NULL)
1606 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1611 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1614 ModestMsgEditWindowPrivate *priv;
1615 GtkWidget *dialog = NULL;
1617 GdkColor *old_color = NULL;
1618 const GdkColor *new_color = NULL;
1620 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1621 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1623 #ifdef MODEST_HILDON_VERSION_0
1624 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1625 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1627 dialog = hildon_color_chooser_new ();
1628 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1629 #endif /*MODEST_HILDON_VERSION_9*/
1631 response = gtk_dialog_run (GTK_DIALOG (dialog));
1633 case GTK_RESPONSE_OK: {
1634 #ifdef MODEST_HILDON_VERSION_0
1635 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1638 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1640 #endif /*MODEST_HILDON_VERSION_0*/
1646 gtk_widget_destroy (dialog);
1648 if (new_color != NULL)
1649 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1653 static TnyStream* create_stream_for_uri (const gchar* uri)
1658 TnyStream *result = NULL;
1660 GnomeVFSHandle *handle = NULL;
1661 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1662 if (test == GNOME_VFS_OK) {
1663 /* Create the tinymail stream: */
1664 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1665 result = TNY_STREAM (tny_vfs_stream_new (handle));
1672 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1675 ModestMsgEditWindowPrivate *priv;
1676 GtkWidget *dialog = NULL;
1678 GSList *uris = NULL;
1679 GSList *uri_node = NULL;
1681 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1683 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1684 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1685 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1687 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1689 response = gtk_dialog_run (GTK_DIALOG (dialog));
1691 case GTK_RESPONSE_OK:
1692 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1697 gtk_widget_destroy (dialog);
1699 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1701 GnomeVFSHandle *handle = NULL;
1702 GnomeVFSResult result;
1703 GtkTextIter position;
1704 GtkTextMark *insert_mark;
1706 uri = (const gchar *) uri_node->data;
1707 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1708 if (result == GNOME_VFS_OK) {
1710 GnomeVFSFileInfo info;
1711 gchar *filename, *basename, *escaped_filename;
1712 TnyMimePart *mime_part;
1714 const gchar *mime_type = NULL;
1715 GnomeVFSURI *vfs_uri;
1717 vfs_uri = gnome_vfs_uri_new (uri);
1719 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1720 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1721 g_free (escaped_filename);
1722 gnome_vfs_uri_unref (vfs_uri);
1724 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1725 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1727 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1729 mime_part = tny_platform_factory_new_mime_part
1730 (modest_runtime_get_platform_factory ());
1732 TnyStream *stream = create_stream_for_uri (uri);
1733 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1735 content_id = g_strdup_printf ("%d", priv->last_cid);
1736 tny_mime_part_set_content_id (mime_part, content_id);
1737 g_free (content_id);
1740 basename = g_path_get_basename (filename);
1741 tny_mime_part_set_filename (mime_part, basename);
1744 pixbuf = pixbuf_from_stream (stream, mime_type);
1746 if (pixbuf != NULL) {
1747 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1748 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1749 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1752 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1753 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1755 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1756 gtk_widget_show_all (priv->attachments_caption);
1757 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1767 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1770 ModestMsgEditWindowPrivate *priv;
1771 GtkWidget *dialog = NULL;
1773 GSList *uris = NULL;
1776 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1778 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1779 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1780 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1782 response = gtk_dialog_run (GTK_DIALOG (dialog));
1784 case GTK_RESPONSE_OK:
1785 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1790 gtk_widget_destroy (dialog);
1792 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1793 const gchar *uri = (const gchar *) uri_node->data;
1794 modest_msg_edit_window_attach_file_one (window, uri);
1796 g_slist_foreach (uris, (GFunc) g_free, NULL);
1797 g_slist_free (uris);
1801 modest_msg_edit_window_attach_file_one (
1802 ModestMsgEditWindow *window,
1805 g_return_if_fail (window);
1806 g_return_if_fail (uri);
1808 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1811 GnomeVFSHandle *handle = NULL;
1812 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1813 if (result == GNOME_VFS_OK) {
1814 TnyMimePart *mime_part;
1816 const gchar *mime_type = NULL;
1818 gchar *escaped_filename;
1821 GnomeVFSFileInfo info;
1822 GnomeVFSURI *vfs_uri;
1824 vfs_uri = gnome_vfs_uri_new (uri);
1827 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1828 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1829 g_free (escaped_filename);
1830 gnome_vfs_uri_unref (vfs_uri);
1832 if (gnome_vfs_get_file_info (uri,
1834 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1835 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1837 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1838 mime_part = tny_platform_factory_new_mime_part
1839 (modest_runtime_get_platform_factory ());
1840 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1842 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1844 content_id = g_strdup_printf ("%d", priv->last_cid);
1845 tny_mime_part_set_content_id (mime_part, content_id);
1846 g_free (content_id);
1849 basename = g_path_get_basename (filename);
1850 tny_mime_part_set_filename (mime_part, basename);
1853 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1854 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1856 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1857 gtk_widget_show_all (priv->attachments_caption);
1858 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1864 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1867 ModestMsgEditWindowPrivate *priv;
1868 gboolean clean_list = FALSE;
1870 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1871 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1873 if (att_list == NULL) {
1874 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1878 if (att_list == NULL) {
1879 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1881 GtkWidget *confirmation_dialog = NULL;
1882 gboolean dialog_response;
1884 gchar *message = NULL;
1885 const gchar *filename = NULL;
1887 if (att_list->next == NULL) {
1888 filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1892 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1893 att_list->next == NULL), filename);
1894 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1896 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1897 gtk_widget_destroy (confirmation_dialog);
1898 if (!dialog_response) {
1900 g_list_free (att_list);
1903 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1905 for (node = att_list; node != NULL; node = g_list_next (node)) {
1906 TnyMimePart *mime_part = (TnyMimePart *) node->data;
1907 const gchar *att_id;
1908 priv->attachments = g_list_remove (priv->attachments, mime_part);
1910 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1912 if (priv->attachments == NULL)
1913 gtk_widget_hide (priv->attachments_caption);
1914 att_id = tny_mime_part_get_content_id (mime_part);
1916 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1918 g_object_unref (mime_part);
1919 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1924 g_list_free (att_list);
1928 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1931 ModestMsgEditWindowPrivate *priv;
1932 GdkColor *new_color;
1933 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1935 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1936 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1939 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1941 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1943 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1945 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1950 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1953 ModestMsgEditWindowPrivate *priv;
1954 gint new_size_index;
1955 ModestMsgEditWindow *window;
1958 window = MODEST_MSG_EDIT_WINDOW (userdata);
1959 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1960 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1962 if (gtk_check_menu_item_get_active (menu_item)) {
1964 WPTextBufferFormat format;
1966 memset (&format, 0, sizeof (format));
1967 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
1969 label = gtk_bin_get_child (GTK_BIN (menu_item));
1971 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1972 format.cs.font_size = TRUE;
1973 format.cs.text_position = TRUE;
1974 format.cs.font = TRUE;
1975 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1976 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
1978 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1979 (gpointer) wp_get_font_size_index (new_size_index, 12)))
1980 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1982 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1983 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1984 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1990 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1993 ModestMsgEditWindowPrivate *priv;
1994 gint new_font_index;
1995 ModestMsgEditWindow *window;
1998 window = MODEST_MSG_EDIT_WINDOW (userdata);
1999 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2000 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2002 if (gtk_check_menu_item_get_active (menu_item)) {
2005 label = gtk_bin_get_child (GTK_BIN (menu_item));
2007 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2009 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2010 (gpointer) new_font_index))
2011 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2013 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2014 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2015 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2021 modest_msg_edit_window_set_zoom (ModestWindow *window,
2024 ModestMsgEditWindowPrivate *priv;
2025 ModestWindowPrivate *parent_priv;
2026 GtkRadioAction *zoom_radio_action;
2028 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2030 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2031 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2032 priv->zoom_level = zoom;
2033 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2035 /* Zoom level menu options should be updated with the current zoom level */
2036 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2037 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2038 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2039 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2040 /* FIXME: Not availible before Gtk 2.10 */
2042 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2047 modest_msg_edit_window_get_zoom (ModestWindow *window)
2049 ModestMsgEditWindowPrivate *priv;
2051 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2053 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2054 return priv->zoom_level;
2058 zoom_allowed (ModestMsgEditWindow *window)
2062 focus = gtk_window_get_focus (GTK_WINDOW (window));
2063 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2067 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2069 ModestWindowPrivate *parent_priv;
2070 GtkRadioAction *zoom_radio_action;
2071 GSList *group, *node;
2073 /* First we check if the text view is focused. If not, zooming is not allowed */
2074 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2075 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2079 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2080 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2081 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2083 group = gtk_radio_action_get_group (zoom_radio_action);
2085 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2086 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2090 for (node = group; node != NULL; node = g_slist_next (node)) {
2091 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2092 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2100 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2102 ModestWindowPrivate *parent_priv;
2103 GtkRadioAction *zoom_radio_action;
2104 GSList *group, *node;
2106 /* First we check if the text view is focused. If not, zooming is not allowed */
2107 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2108 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2112 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2113 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2114 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2116 group = gtk_radio_action_get_group (zoom_radio_action);
2118 for (node = group; node != NULL; node = g_slist_next (node)) {
2119 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2120 if (node->next != NULL) {
2121 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2124 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2132 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2134 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2135 ModestWindowPrivate *parent_priv;
2136 ModestWindowMgr *mgr;
2137 gboolean is_fullscreen;
2138 GtkAction *fs_toggle_action;
2141 mgr = modest_runtime_get_window_mgr ();
2142 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2144 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2146 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2147 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2148 if (is_fullscreen != active)
2149 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2157 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
2159 ModestWindowPrivate *parent_priv;
2160 GtkAction *fs_toggle_action;
2163 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2165 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2166 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
2167 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
2171 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2174 ModestMsgEditWindowPrivate *priv = NULL;
2175 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2177 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2178 if (!priv->update_caption_visibility)
2181 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2183 gtk_widget_show (priv->cc_caption);
2185 gtk_widget_hide (priv->cc_caption);
2187 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2191 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2194 ModestMsgEditWindowPrivate *priv = NULL;
2195 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2197 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2198 if (!priv->update_caption_visibility)
2201 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2203 gtk_widget_show (priv->bcc_caption);
2205 gtk_widget_hide (priv->bcc_caption);
2207 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2211 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2212 ModestRecptEditor *editor)
2214 ModestMsgEditWindowPrivate *priv;
2216 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2217 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2218 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2220 if (editor == NULL) {
2221 GtkWidget *view_focus;
2222 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2224 /* This code should be kept in sync with ModestRecptEditor. The
2225 textview inside the recpt editor is the one that really gets the
2226 focus. As it's inside a scrolled window, and this one inside the
2227 hbox recpt editor inherits from, we'll need to go up in the
2228 hierarchy to know if the text view is part of the recpt editor
2229 or if it's a different text entry */
2231 if (gtk_widget_get_parent (view_focus)) {
2232 GtkWidget *first_parent;
2234 first_parent = gtk_widget_get_parent (view_focus);
2235 if (gtk_widget_get_parent (first_parent) &&
2236 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2237 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2242 editor = MODEST_RECPT_EDITOR (priv->to_field);
2246 modest_address_book_select_addresses (editor);
2251 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2253 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2255 modest_msg_edit_window_open_addressbook (window, NULL);
2259 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2260 gboolean show_toolbar)
2262 ModestWindowPrivate *parent_priv;
2264 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2265 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2267 /* FIXME: we can not just use the code of
2268 modest_msg_edit_window_setup_toolbar because it has a
2269 mixture of both initialization and creation code. */
2272 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2274 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2278 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2279 TnyHeaderFlags priority_flags)
2281 ModestMsgEditWindowPrivate *priv;
2282 ModestWindowPrivate *parent_priv;
2284 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2286 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2287 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2288 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2290 if (priv->priority_flags != priority_flags) {
2291 GtkAction *priority_action = NULL;
2293 priv->priority_flags = priority_flags;
2295 switch (priority_flags) {
2296 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2297 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2298 gtk_widget_show (priv->priority_icon);
2299 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2300 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2302 case TNY_HEADER_FLAG_LOW_PRIORITY:
2303 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2304 gtk_widget_show (priv->priority_icon);
2305 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2306 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2309 gtk_widget_hide (priv->priority_icon);
2310 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2311 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2314 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2315 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2320 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2323 ModestMsgEditWindowPrivate *priv;
2324 ModestWindowPrivate *parent_priv;
2325 gint current_format;
2327 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2329 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2330 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2332 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2333 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2335 if (current_format != file_format) {
2336 switch (file_format) {
2337 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2338 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2340 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2344 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2345 response = gtk_dialog_run (GTK_DIALOG (dialog));
2346 gtk_widget_destroy (dialog);
2347 if (response == GTK_RESPONSE_OK) {
2348 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2350 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2351 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2356 update_dimmed (window);
2361 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2364 ModestMsgEditWindowPrivate *priv;
2365 WPTextBufferFormat oldfmt, fmt;
2366 gint old_position = 0;
2370 GdkColor *color = NULL;
2371 gboolean bold, bold_set, italic, italic_set;
2372 gboolean underline, underline_set;
2373 gboolean strikethrough, strikethrough_set;
2374 gboolean position_set;
2375 gboolean font_size_set, font_set, color_set;
2378 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2379 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2381 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2383 /* First we get the currently selected font information */
2384 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2385 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2387 switch (oldfmt.text_position) {
2388 case TEXT_POSITION_NORMAL:
2391 case TEXT_POSITION_SUPERSCRIPT:
2399 g_object_set (G_OBJECT (dialog),
2400 "bold", oldfmt.bold != FALSE,
2401 "bold-set", !oldfmt.cs.bold,
2402 "underline", oldfmt.underline != FALSE,
2403 "underline-set", !oldfmt.cs.underline,
2404 "italic", oldfmt.italic != FALSE,
2405 "italic-set", !oldfmt.cs.italic,
2406 "strikethrough", oldfmt.strikethrough != FALSE,
2407 "strikethrough-set", !oldfmt.cs.strikethrough,
2408 "color", &oldfmt.color,
2409 "color-set", !oldfmt.cs.color,
2410 "size", wp_font_size[oldfmt.font_size],
2411 "size-set", !oldfmt.cs.font_size,
2412 "position", old_position,
2413 "position-set", !oldfmt.cs.text_position,
2414 "family", wp_get_font_name (oldfmt.font),
2415 "family-set", !oldfmt.cs.font,
2418 gtk_widget_show_all (dialog);
2419 response = gtk_dialog_run (GTK_DIALOG (dialog));
2420 if (response == GTK_RESPONSE_OK) {
2422 g_object_get( dialog,
2424 "bold-set", &bold_set,
2425 "underline", &underline,
2426 "underline-set", &underline_set,
2428 "italic-set", &italic_set,
2429 "strikethrough", &strikethrough,
2430 "strikethrough-set", &strikethrough_set,
2432 "color-set", &color_set,
2434 "size-set", &font_size_set,
2435 "family", &font_name,
2436 "family-set", &font_set,
2437 "position", &position,
2438 "position-set", &position_set,
2443 if (response == GTK_RESPONSE_OK) {
2444 memset(&fmt, 0, sizeof(fmt));
2450 fmt.italic = italic;
2451 fmt.cs.italic = TRUE;
2453 if (underline_set) {
2454 fmt.underline = underline;
2455 fmt.cs.underline = TRUE;
2457 if (strikethrough_set) {
2458 fmt.strikethrough = strikethrough;
2459 fmt.cs.strikethrough = TRUE;
2464 ? TEXT_POSITION_NORMAL
2465 : ( ( position == 1 )
2466 ? TEXT_POSITION_SUPERSCRIPT
2467 : TEXT_POSITION_SUBSCRIPT );
2468 fmt.cs.text_position = TRUE;
2472 fmt.cs.color = TRUE;
2475 fmt.font = wp_get_font_index(font_name,
2480 if (font_size_set) {
2481 fmt.font_size = wp_get_font_size_index(
2482 font_size, DEFAULT_FONT_SIZE);
2483 fmt.cs.font_size = TRUE;
2485 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2487 gtk_widget_destroy (dialog);
2489 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2493 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2495 ModestMsgEditWindowPrivate *priv;
2497 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2498 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2500 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2502 update_dimmed (window);
2507 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2509 ModestMsgEditWindowPrivate *priv;
2511 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2512 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2514 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2516 update_dimmed (window);
2521 update_dimmed (ModestMsgEditWindow *window)
2523 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2524 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2528 gboolean editor_focused;
2530 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2531 editor_focused = gtk_widget_is_focus (priv->msg_body);
2533 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2534 gtk_action_set_sensitive (action, rich_text && editor_focused);
2535 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2536 gtk_action_set_sensitive (action, rich_text && editor_focused);
2537 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2538 gtk_action_set_sensitive (action, rich_text && editor_focused);
2539 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2540 gtk_action_set_sensitive (action, rich_text && editor_focused);
2541 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2542 gtk_action_set_sensitive (action, rich_text && editor_focused);
2543 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2544 gtk_action_set_sensitive (action, rich_text && editor_focused);
2545 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2546 gtk_action_set_sensitive (action, rich_text && editor_focused);
2547 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2548 gtk_action_set_sensitive (action, rich_text && editor_focused);
2549 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2550 gtk_action_set_sensitive (action, rich_text && editor_focused);
2551 widget = priv->font_color_button;
2552 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2553 widget = priv->font_size_toolitem;
2554 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2555 widget = priv->font_face_toolitem;
2556 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2560 setup_insensitive_handlers (ModestMsgEditWindow *window)
2562 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2563 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2566 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2567 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2568 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2569 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2570 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2571 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2572 widget = priv->font_color_button;
2573 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2574 widget = priv->font_size_toolitem;
2575 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2576 widget = priv->font_face_toolitem;
2577 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2582 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2584 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2587 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2588 gtk_action_set_sensitive (action, can_undo);
2592 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2594 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2597 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/RedoMenu");
2598 gtk_action_set_sensitive (action, can_redo);
2602 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2605 GtkTextIter match_start, match_end;
2607 if (image_id == NULL)
2610 gtk_text_buffer_get_start_iter (buffer, &iter);
2612 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2613 GSList *tags = gtk_text_iter_get_tags (&match_start);
2615 for (node = tags; node != NULL; node = g_slist_next (node)) {
2616 GtkTextTag *tag = (GtkTextTag *) node->data;
2617 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2618 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2619 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2621 offset = gtk_text_iter_get_offset (&match_start);
2622 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2623 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2627 gtk_text_iter_forward_char (&iter);
2632 msg_body_focus (GtkWidget *focus,
2633 GdkEventFocus *event,
2637 update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2642 recpt_field_changed (GtkTextBuffer *buffer,
2643 ModestMsgEditWindow *editor)
2645 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (editor);
2646 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2647 GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
2648 gboolean dim = FALSE;
2651 to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
2652 cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
2653 bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
2655 dim = ((gtk_text_buffer_get_char_count (to_buffer) +
2656 gtk_text_buffer_get_char_count (cc_buffer) +
2657 gtk_text_buffer_get_char_count (bcc_buffer)) == 0);
2659 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2660 gtk_action_set_sensitive (action, !dim);
2661 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2662 gtk_action_set_sensitive (action, !dim);
2666 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2668 hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2672 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2674 gboolean rich_text, editor_focused;
2676 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2677 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2678 editor_focused = gtk_widget_is_focus (priv->msg_body);
2681 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2682 else if (!editor_focused)
2683 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2687 reset_modified (ModestMsgEditWindow *editor)
2689 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2690 GtkTextBuffer *buffer;
2692 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2693 gtk_text_buffer_set_modified (buffer, FALSE);
2694 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2695 gtk_text_buffer_set_modified (buffer, FALSE);
2696 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2697 gtk_text_buffer_set_modified (buffer, FALSE);
2698 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2702 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2704 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2705 GtkTextBuffer *buffer;
2707 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2708 if (gtk_text_buffer_get_modified (buffer))
2710 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2711 if (gtk_text_buffer_get_modified (buffer))
2713 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2714 if (gtk_text_buffer_get_modified (buffer))
2716 if (gtk_text_buffer_get_modified (priv->text_buffer))
2723 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2725 ModestMsgEditWindowPrivate *priv = NULL;
2727 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2728 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2730 /* check if there's no recipient added */
2731 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2732 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2733 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2734 /* no recipient contents, then select contacts */
2735 modest_msg_edit_window_open_addressbook (window, NULL);
2739 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook))
2741 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook))
2743 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook))
2746 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2753 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2754 ModestMsgEditWindow *window)
2756 modest_msg_edit_window_offer_attach_file (window);
2760 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2762 ModestMsgEditWindow *window)
2764 ModestWindowPrivate *parent_priv;
2765 ModestMsgEditWindowPrivate *priv;
2767 gboolean has_selection;
2769 GList *selected_attachments = NULL;
2770 gint n_att_selected = 0;
2772 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2773 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2775 if (!GTK_WIDGET_VISIBLE (window))
2777 has_selection = gtk_clipboard_wait_for_targets (clipboard, NULL, NULL);
2778 focused = gtk_window_get_focus (GTK_WINDOW (window));
2780 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
2781 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2782 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
2783 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2785 selected_attachments = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2786 n_att_selected = g_list_length (selected_attachments);
2787 g_list_free (selected_attachments);
2789 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
2790 gtk_action_set_sensitive (action, n_att_selected == 1);
2792 update_paste_dimming (window);
2796 update_window_title (ModestMsgEditWindow *window)
2798 ModestMsgEditWindowPrivate *priv = NULL;
2799 const gchar *subject;
2801 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2802 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2803 if (subject == NULL || subject[0] == '\0')
2804 subject = _("mail_va_new_email");
2806 gtk_window_set_title (GTK_WINDOW (window), subject);
2811 subject_field_changed (GtkEditable *editable,
2812 ModestMsgEditWindow *window)
2814 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2815 update_window_title (window);
2816 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2820 subject_field_insert_text (GtkEditable *editable,
2822 gint new_text_length,
2824 ModestMsgEditWindow *window)
2826 GString *result = g_string_new ("");
2828 gint result_len = 0;
2830 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2831 gunichar c = g_utf8_get_char_validated (current, 8);
2832 /* Invalid unichar, stop */
2838 result = g_string_append_unichar (result, c);
2842 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2843 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2845 g_signal_emit_by_name (editable, "insert-text",
2846 (gpointer) result->str, (gpointer) strlen (result->str),
2847 (gpointer) position, (gpointer) window);
2850 g_string_free (result, TRUE);
2854 message_is_empty (ModestMsgEditWindow *window)
2856 ModestMsgEditWindowPrivate *priv = NULL;
2858 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2859 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2861 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2862 * so we can ignore markup.
2864 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2867 count = gtk_text_buffer_get_char_count (buf);
2873 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2876 ModestMsgEditWindowPrivate *priv = NULL;
2878 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2879 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2881 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2884 gtk_widget_show_all (priv->find_toolbar);
2885 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2887 gtk_widget_hide_all (priv->find_toolbar);
2888 gtk_widget_grab_focus (priv->msg_body);
2894 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2896 GtkTextIter *match_start,
2897 GtkTextIter *match_end)
2899 GtkTextIter end_iter;
2900 gchar *str_casefold;
2903 gchar *range_casefold;
2906 gboolean result = FALSE;
2913 gtk_text_iter_forward_to_end (&end_iter);
2915 str_casefold = g_utf8_casefold (str, -1);
2916 str_chars_n = strlen (str);
2918 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2919 range_casefold = g_utf8_casefold (range_text, -1);
2920 range_chars_n = strlen (range_casefold);
2922 if (range_chars_n < str_chars_n) {
2923 g_free (str_casefold);
2924 g_free (range_text);
2925 g_free (range_casefold);
2929 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2930 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2931 if (!g_utf8_collate (range_subtext, str_casefold)) {
2932 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2934 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2935 match_start, match_end, NULL);
2936 g_free (found_text);
2938 g_free (range_subtext);
2942 g_free (str_casefold);
2943 g_free (range_text);
2944 g_free (range_casefold);
2951 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2952 ModestMsgEditWindow *window)
2954 gchar *current_search = NULL;
2955 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2957 GtkTextIter selection_start, selection_end;
2958 GtkTextIter match_start, match_end;
2959 gboolean continue_search = FALSE;
2961 if (message_is_empty (window)) {
2962 g_free (priv->last_search);
2963 priv->last_search = NULL;
2964 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
2968 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
2969 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2970 g_free (current_search);
2971 g_free (priv->last_search);
2972 priv->last_search = NULL;
2973 /* Information banner about empty search */
2974 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
2978 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
2979 continue_search = TRUE;
2981 g_free (priv->last_search);
2982 priv->last_search = g_strdup (current_search);
2985 if (continue_search) {
2986 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
2987 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
2988 &match_start, &match_end);
2990 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
2992 GtkTextIter buffer_start;
2993 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
2994 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
2995 &match_start, &match_end);
2997 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3000 /* Mark as selected the string found in search */
3002 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3003 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3005 g_free (priv->last_search);
3006 priv->last_search = NULL;
3008 g_free (current_search);
3012 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3013 ModestMsgEditWindow *window)
3015 GtkToggleAction *toggle;
3016 ModestWindowPrivate *parent_priv;
3017 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3019 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3020 gtk_toggle_action_set_active (toggle, FALSE);
3025 update_paste_dimming (ModestMsgEditWindow *window)
3027 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3028 GtkAction *action = NULL;
3029 GtkClipboard *clipboard = NULL;
3030 ModestEmailClipboard *e_clipboard;
3034 focused = gtk_window_get_focus (GTK_WINDOW (window));
3036 e_clipboard = modest_runtime_get_email_clipboard ();
3037 if (!modest_email_clipboard_cleared (e_clipboard)) {
3040 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3041 active = gtk_clipboard_wait_is_text_available (clipboard);
3045 if (MODEST_IS_ATTACHMENTS_VIEW (focused))
3049 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
3050 gtk_action_set_sensitive (action, active);
3055 update_select_all_dimming (ModestMsgEditWindow *window)
3058 gboolean dimmed = FALSE;
3060 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3062 focused = gtk_window_get_focus (GTK_WINDOW (window));
3063 if (GTK_IS_ENTRY (focused)) {
3064 const gchar *current_text;
3065 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
3066 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
3067 } else if (GTK_IS_TEXT_VIEW (focused)) {
3068 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
3069 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
3070 } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
3073 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
3074 gtk_action_set_sensitive (action, !dimmed);
3078 update_zoom_dimming (ModestMsgEditWindow *window)
3081 gboolean dimmed = FALSE;
3083 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3085 focused = gtk_window_get_focus (GTK_WINDOW (window));
3086 dimmed = ! WP_IS_TEXT_VIEW (focused);
3087 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
3088 gtk_action_set_sensitive (action, !dimmed);
3092 edit_menu_activated (GtkAction *action,
3095 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3097 update_select_all_dimming (window);
3098 update_paste_dimming (window);
3101 view_menu_activated (GtkAction *action,
3104 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3106 update_zoom_dimming (window);
3110 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3112 ModestMsgEditWindowPrivate *priv;
3114 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3119 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3122 ModestMsgEditWindowPrivate *priv;
3124 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3130 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3133 ModestMsgEditWindowPrivate *priv;
3134 TnyHeader *header = NULL;
3136 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3137 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3139 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3140 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3142 if (priv->draft_msg != NULL) {
3143 header = tny_msg_get_header (priv->draft_msg);
3144 if (TNY_IS_HEADER (header)) {
3145 modest_window_mgr_unregister_header (mgr, header);
3147 g_object_unref (priv->draft_msg);
3150 if (draft != NULL) {
3151 g_object_ref (draft);
3152 header = tny_msg_get_header (draft);
3153 if (TNY_IS_HEADER (header))
3154 modest_window_mgr_register_header (mgr, header);
3155 if (priv->msg_uid) {
3156 g_free (priv->msg_uid);
3157 priv->msg_uid = NULL;
3159 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3162 priv->draft_msg = draft;
3166 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3167 GtkTextIter *start, GtkTextIter *end,
3170 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3171 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3174 if (tag == NULL+13) return;
3175 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3176 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3177 replace_with_attachments (window, priv->attachments);
3182 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3185 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3187 g_return_if_fail (TNY_IS_MIME_PART (part));
3188 priv->attachments = g_list_prepend (priv->attachments, part);
3189 g_object_ref (part);
3190 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3191 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3192 gtk_widget_show_all (priv->attachments_caption);
3193 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3197 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3199 ModestMsgEditWindowPrivate *priv;
3201 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3202 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3204 return priv->msg_uid;