1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-address-book.h"
60 #include "modest-text-utils.h"
61 #include <tny-simple-list.h>
62 #include <wptextview.h>
63 #include <wptextbuffer.h>
64 #include "modest-scroll-area.h"
66 #include "modest-hildon-includes.h"
67 #ifdef MODEST_HAVE_HILDON0_WIDGETS
68 #include <hildon-widgets/hildon-color-chooser.h>
70 #include "widgets/modest-msg-edit-window-ui.h"
71 #ifdef MODEST_HAVE_HILDON0_WIDGETS
72 #include <libgnomevfs/gnome-vfs-mime-utils.h>
74 #include <libgnomevfs/gnome-vfs-mime.h>
76 #include "modest-maemo-utils.h"
79 #define DEFAULT_FONT_SIZE 3
80 #define DEFAULT_FONT 2
81 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
82 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
83 #define DEFAULT_MAIN_VBOX_SPACING 6
84 #define SUBJECT_MAX_LENGTH 1000
85 #define IMAGE_MAX_WIDTH 560
86 #define DEFAULT_FONT_SCALE 1.5
88 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
89 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
90 static void modest_msg_edit_window_finalize (GObject *obj);
92 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
93 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
94 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
95 static void send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
96 static void style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
97 static void setup_insensitive_handlers (ModestMsgEditWindow *editor);
98 static void reset_modified (ModestMsgEditWindow *editor);
100 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
101 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
102 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
103 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
104 GtkTextIter *start, GtkTextIter *end,
106 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
107 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
108 static void subject_field_insert_text (GtkEditable *editable,
110 gint new_text_length,
112 ModestMsgEditWindow *window);
113 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
115 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
117 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
119 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
120 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
121 GdkEventWindowState *event,
123 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
124 ModestRecptEditor *editor);
125 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
126 ModestMsgEditWindow *window);
128 /* ModestWindow methods implementation */
129 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
130 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
131 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
132 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
133 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
134 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
135 gboolean show_toolbar);
136 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
138 ModestMsgEditWindow *window);
139 static void update_window_title (ModestMsgEditWindow *window);
140 static void update_dimmed (ModestMsgEditWindow *window);
141 static void update_paste_dimming (ModestMsgEditWindow *window);
142 static void update_copy_cut_dimming (ModestMsgEditWindow *window);
143 static void update_select_all_dimming (ModestMsgEditWindow *window);
144 static void update_zoom_dimming (ModestMsgEditWindow *window);
145 static void update_send_dimming (ModestMsgEditWindow *window);
148 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
149 ModestMsgEditWindow *window);
150 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
151 ModestMsgEditWindow *window);
152 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
154 GtkTextIter *match_start,
155 GtkTextIter *match_end);
157 static void DEBUG_BUFFER (WPTextBuffer *buffer)
162 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
163 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
164 while (!gtk_text_iter_is_end (&iter)) {
165 GString *output = g_string_new ("");
166 GSList *toggled_tags;
169 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
170 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
171 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
172 GtkTextTag *tag = (GtkTextTag *) node->data;
174 g_object_get (G_OBJECT (tag), "name", &name, NULL);
175 output = g_string_append (output, name);
176 g_string_append (output, " ");
178 output = g_string_append (output, "] OPENED [ ");
179 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
180 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
181 GtkTextTag *tag = (GtkTextTag *) node->data;
183 g_object_get (G_OBJECT (tag), "name", &name, NULL);
184 output = g_string_append (output, name);
185 g_string_append (output, " ");
187 output = g_string_append (output, "]\n");
188 g_message ("%s", output->str);
189 g_string_free (output, TRUE);
190 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
192 g_message ("END BUFFER");
197 /* static gboolean */
198 /* on_key_pressed (GtkWidget *self, */
199 /* GdkEventKey *event, */
200 /* gpointer user_data); */
202 static void edit_menu_activated (GtkAction *action,
204 static void view_menu_activated (GtkAction *action,
207 /* list my signals */
214 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
215 struct _ModestMsgEditWindowPrivate {
217 GtkWidget *header_box;
219 ModestPairList *from_field_protos;
220 GtkWidget *from_field;
224 GtkWidget *bcc_field;
225 GtkWidget *subject_field;
226 GtkWidget *attachments_view;
227 GtkWidget *priority_icon;
228 GtkWidget *add_attachment_button;
230 GtkWidget *cc_caption;
231 GtkWidget *bcc_caption;
232 gboolean update_caption_visibility;
233 GtkWidget *attachments_caption;
235 GtkTextBuffer *text_buffer;
237 GtkWidget *font_size_toolitem;
238 GtkWidget *font_face_toolitem;
239 GtkWidget *font_color_button;
240 GSList *font_items_group;
241 GtkWidget *font_tool_button_label;
242 GSList *size_items_group;
243 GtkWidget *size_tool_button_label;
245 GtkWidget *find_toolbar;
249 GtkWidget *scroll_area;
250 gint last_vadj_upper;
255 TnyHeaderFlags priority_flags;
259 gulong clipboard_change_handler_id;
268 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
269 MODEST_TYPE_MSG_EDIT_WINDOW, \
270 ModestMsgEditWindowPrivate))
272 static GtkWindowClass *parent_class = NULL;
274 /* uncomment the following if you have defined any signals */
275 /* static guint signals[LAST_SIGNAL] = {0}; */
278 modest_msg_edit_window_get_type (void)
280 static GType my_type = 0;
282 static const GTypeInfo my_info = {
283 sizeof(ModestMsgEditWindowClass),
284 NULL, /* base init */
285 NULL, /* base finalize */
286 (GClassInitFunc) modest_msg_edit_window_class_init,
287 NULL, /* class finalize */
288 NULL, /* class data */
289 sizeof(ModestMsgEditWindow),
291 (GInstanceInitFunc) modest_msg_edit_window_init,
294 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
295 "ModestMsgEditWindow",
298 wp_text_buffer_library_init ();
304 save_state (ModestWindow *self)
306 modest_widget_memory_save (modest_runtime_get_conf(),
307 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
312 restore_settings (ModestMsgEditWindow *self)
314 modest_widget_memory_restore (modest_runtime_get_conf(),
315 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
320 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
322 GObjectClass *gobject_class;
323 ModestWindowClass *modest_window_class;
324 gobject_class = (GObjectClass*) klass;
325 modest_window_class = (ModestWindowClass*) klass;
327 parent_class = g_type_class_peek_parent (klass);
328 gobject_class->finalize = modest_msg_edit_window_finalize;
330 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
331 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
332 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
333 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
334 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
335 modest_window_class->save_state_func = save_state;
336 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
338 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
342 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
344 ModestMsgEditWindowPrivate *priv;
345 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
347 priv->msg_body = NULL;
348 priv->from_field = NULL;
349 priv->to_field = NULL;
350 priv->cc_field = NULL;
351 priv->bcc_field = NULL;
352 priv->subject_field = NULL;
353 priv->attachments = NULL;
355 priv->zoom_level = 1.0;
357 priv->cc_caption = NULL;
358 priv->bcc_caption = NULL;
359 priv->update_caption_visibility = FALSE;
361 priv->priority_flags = 0;
363 priv->find_toolbar = NULL;
364 priv->last_search = NULL;
366 priv->draft_msg = NULL;
367 priv->outbox_msg = NULL;
368 priv->msg_uid = NULL;
369 priv->clipboard_change_handler_id = 0;
372 priv->last_vadj_upper = 0;
376 /* FIXME: this is a dup from the one in gtk/ */
379 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
381 static ModestPairList*
382 get_transports (void)
384 GSList *transports = NULL;
386 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
387 GSList *accounts = modest_account_mgr_account_names (account_mgr,
388 TRUE /* only enabled accounts. */);
390 GSList *cursor = accounts;
392 gchar *account_name = cursor->data;
393 gchar *from_string = NULL;
395 from_string = modest_account_mgr_get_from_string (account_mgr,
399 if (from_string && account_name) {
400 gchar *name = account_name;
401 ModestPair *pair = modest_pair_new ((gpointer) name,
402 (gpointer) from_string , TRUE);
403 transports = g_slist_prepend (transports, pair);
406 cursor = cursor->next;
408 g_slist_free (accounts); /* only free the accounts, not the elements,
409 * because they are used in the pairlist */
413 void vadj_changed (GtkAdjustment *adj,
414 ModestMsgEditWindow *window)
416 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
418 GdkRectangle rectangle, cursor_rectangle;
419 GtkTextIter position;
423 /* We detect if cursor is visible using the full height, not only the center. This
425 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
426 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
428 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
429 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
431 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
432 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
434 if (gtk_widget_is_focus (priv->msg_body) &&
436 if (priv->last_vadj_upper != adj->upper) {
439 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
440 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
441 insert, 0.1, FALSE, 0.0, 0.0);
444 priv->last_vadj_upper = adj->upper;
449 init_window (ModestMsgEditWindow *obj)
451 GtkWidget *from_caption, *to_caption, *subject_caption;
452 GtkWidget *main_vbox;
453 ModestMsgEditWindowPrivate *priv;
455 GtkSizeGroup *size_group;
457 GtkWidget *subject_box;
458 GtkWidget *attachment_icon;
459 GtkWidget *window_box;
460 #if (GTK_MINOR_VERSION >= 10)
461 GdkAtom deserialize_type;
463 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
465 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
467 /* Note: This ModestPairList* must exist for as long as the combo
468 * that uses it, because the ModestComboBox uses the ID opaquely,
469 * so it can't know how to manage its memory. */
470 priv->from_field_protos = get_transports ();
472 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
474 priv->to_field = modest_recpt_editor_new ();
475 priv->cc_field = modest_recpt_editor_new ();
476 priv->bcc_field = modest_recpt_editor_new ();
477 subject_box = gtk_hbox_new (FALSE, 0);
478 priv->priority_icon = gtk_image_new ();
479 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
480 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
481 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
482 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
483 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
484 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
485 priv->add_attachment_button = gtk_button_new ();
486 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
487 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
488 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
489 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
490 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
491 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
492 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
493 priv->attachments_view = modest_attachments_view_new (NULL);
495 priv->header_box = gtk_vbox_new (FALSE, 0);
497 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
498 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
499 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
500 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
501 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
502 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
503 g_object_unref (size_group);
505 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
506 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
507 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
508 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
509 gtk_size_group_add_widget (size_group, priv->subject_field);
510 gtk_size_group_add_widget (size_group, priv->attachments_view);
511 g_object_unref (size_group);
513 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
514 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
515 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
516 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
517 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
518 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
519 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
522 priv->msg_body = wp_text_view_new ();
523 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
524 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
525 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
526 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
527 #if (GTK_MINOR_VERSION >= 10)
528 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
529 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
531 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
532 deserialize_type, TRUE);
534 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
536 priv->find_toolbar = hildon_find_toolbar_new (NULL);
537 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
539 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
541 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
542 G_CALLBACK (text_buffer_refresh_attributes), obj);
543 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
544 G_CALLBACK (text_buffer_can_undo), obj);
545 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
546 G_CALLBACK (text_buffer_can_redo), obj);
547 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
548 G_CALLBACK (body_changed), obj);
549 g_signal_connect (G_OBJECT (obj), "window-state-event",
550 G_CALLBACK (modest_msg_edit_window_window_state_event),
552 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
553 G_CALLBACK (text_buffer_apply_tag), obj);
554 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
555 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
556 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
557 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
558 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
559 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
561 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
562 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
564 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
565 G_CALLBACK (msg_body_focus), obj);
566 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
567 G_CALLBACK (msg_body_focus), obj);
568 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
569 "changed", G_CALLBACK (recpt_field_changed), obj);
570 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
571 "changed", G_CALLBACK (recpt_field_changed), obj);
572 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
573 "changed", G_CALLBACK (recpt_field_changed), obj);
574 recpt_field_changed (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)), MODEST_MSG_EDIT_WINDOW (obj));
575 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
576 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
578 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
579 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
581 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
582 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
583 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
584 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
586 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
588 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
589 frame = gtk_frame_new (NULL);
590 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
592 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
593 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
594 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
596 G_CALLBACK (vadj_changed),
598 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
600 window_box = gtk_vbox_new (FALSE, 0);
601 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
602 gtk_container_add (GTK_CONTAINER(obj), window_box);
603 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
604 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
606 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
607 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
612 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
614 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
616 if (g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
617 priv->clipboard_change_handler_id))
618 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
619 priv->clipboard_change_handler_id);
623 modest_msg_edit_window_finalize (GObject *obj)
625 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
627 /* Sanity check: shouldn't be needed, the window mgr should
628 call this function before */
629 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
631 if (priv->draft_msg != NULL) {
632 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
633 if (TNY_IS_HEADER (header)) {
634 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
635 modest_window_mgr_unregister_header (mgr, header);
637 g_object_unref (priv->draft_msg);
638 priv->draft_msg = NULL;
640 if (priv->outbox_msg != NULL) {
641 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
642 if (TNY_IS_HEADER (header)) {
643 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
644 modest_window_mgr_unregister_header (mgr, header);
646 g_object_unref (priv->outbox_msg);
647 priv->outbox_msg = NULL;
649 if (priv->msg_uid != NULL) {
650 g_free (priv->msg_uid);
651 priv->msg_uid = NULL;
654 /* This had to stay alive for as long as the combobox that used it: */
655 modest_pair_list_free (priv->from_field_protos);
657 G_OBJECT_CLASS(parent_class)->finalize (obj);
661 menubar_to_menu (GtkUIManager *ui_manager)
663 GtkWidget *main_menu;
667 /* Create new main menu */
668 main_menu = gtk_menu_new();
670 /* Get the menubar from the UI manager */
671 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
673 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
677 menu = GTK_WIDGET (iter->data);
678 gtk_widget_reparent(menu, main_menu);
680 iter = g_list_next (iter);
686 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
688 GdkPixbufLoader *loader;
691 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
696 tny_stream_reset (TNY_STREAM (stream));
697 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
698 unsigned char read_buffer[128];
700 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
701 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
705 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
706 g_object_ref (pixbuf);
707 gdk_pixbuf_loader_close (loader, NULL);
708 g_object_unref (loader);
710 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
711 GdkPixbuf *new_pixbuf;
713 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
714 gdk_pixbuf_get_width (pixbuf);
715 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
716 g_object_unref (pixbuf);
724 replace_with_attachments (ModestMsgEditWindow *self, GList *attachments)
726 ModestMsgEditWindowPrivate *priv;
729 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
731 for (node = attachments; node != NULL; node = g_list_next (node)) {
732 TnyMimePart *part = (TnyMimePart *) node->data;
733 const gchar *cid = tny_mime_part_get_content_id (part);
734 const gchar *mime_type = tny_mime_part_get_content_type (part);
735 if ((cid != NULL)&&(mime_type != NULL)) {
736 TnyStream *stream = tny_mime_part_get_stream (part);
737 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
738 g_object_unref (stream);
740 if (pixbuf != NULL) {
741 /* wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf); */
742 g_object_unref (pixbuf);
749 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
752 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
754 for (node = attachments; node != NULL; node = g_list_next (node)) {
755 TnyMimePart *part = (TnyMimePart *) node->data;
756 const gchar *cid = tny_mime_part_get_content_id (part);
758 char *invalid = NULL;
759 gint int_cid = strtol (cid, &invalid, 10);
760 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
761 priv->last_cid = int_cid;
769 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
772 const gchar *to, *cc, *bcc, *subject;
774 ModestMsgEditWindowPrivate *priv;
776 TnyHeaderFlags priority_flags;
777 TnyFolder *msg_folder;
778 gboolean is_html = FALSE;
780 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
781 g_return_if_fail (TNY_IS_MSG (msg));
783 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
785 header = tny_msg_get_header (msg);
786 to = tny_header_get_to (header);
787 cc = tny_header_get_cc (header);
788 bcc = tny_header_get_bcc (header);
789 subject = tny_header_get_subject (header);
790 priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
793 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
795 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
796 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
797 gtk_widget_show (priv->cc_caption);
798 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
799 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
800 gtk_widget_hide (priv->cc_caption);
803 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
804 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
805 gtk_widget_show (priv->bcc_caption);
806 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
807 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
808 gtk_widget_hide (priv->bcc_caption);
811 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
812 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
815 update_window_title (self);
817 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
818 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
820 if ((body == NULL)||(body[0] == '\0')) {
822 body = modest_text_utils_convert_to_html ("");
825 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
826 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
829 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
832 if (preserve_is_rich && !is_html) {
833 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
834 /* Get the default format required from configuration */
835 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
836 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
839 /* Set the default focus depending on having already a To: field or not */
840 if ((!to)||(*to == '\0')) {
841 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
843 gtk_widget_grab_focus (priv->msg_body);
846 /* TODO: lower priority, select in the From: combo to the
847 value that comes from msg <- not sure, should it be
850 /* Add attachments to the view */
851 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
852 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
853 if (priv->attachments == NULL) {
854 gtk_widget_hide (priv->attachments_caption);
856 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
857 gtk_widget_show_all (priv->attachments_caption);
858 replace_with_attachments (self, priv->attachments);
860 update_last_cid (self, priv->attachments);
862 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
864 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
865 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
867 reset_modified (self);
869 update_dimmed (self);
870 text_buffer_can_undo (priv->text_buffer, FALSE, self);
871 text_buffer_can_redo (priv->text_buffer, FALSE, self);
874 g_free (priv->msg_uid);
875 priv->msg_uid = NULL;
878 /* we should set a reference to the incoming message if it is a draft */
879 msg_folder = tny_msg_get_folder (msg);
881 if (modest_tny_folder_is_local_folder (msg_folder)) {
882 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
883 if (type == TNY_FOLDER_TYPE_DRAFTS)
884 priv->draft_msg = g_object_ref(msg);
885 if (type == TNY_FOLDER_TYPE_OUTBOX)
886 priv->outbox_msg = g_object_ref(msg);
887 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
889 g_object_unref (msg_folder);
894 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
897 GList *item_children, *node;
898 GtkWidget *bin_child;
900 bin_child = gtk_bin_get_child (GTK_BIN(item));
902 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
904 for (node = item_children; node != NULL; node = g_list_next (node)) {
905 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
906 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
909 g_list_free (item_children);
913 menu_tool_button_dont_expand (GtkMenuToolButton *item)
916 GList *item_children, *node;
918 box = gtk_bin_get_child (GTK_BIN (item));
919 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
920 item_children = gtk_container_get_children (GTK_CONTAINER (box));
922 for (node = item_children; node != NULL; node = g_list_next (node)) {
923 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
924 if (GTK_IS_TOGGLE_BUTTON (node->data))
925 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
926 else if (GTK_IS_BUTTON (node->data))
927 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
929 g_list_free (item_children);
934 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
936 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
937 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
938 GtkWidget *placeholder;
939 GtkWidget *tool_item;
944 GtkWidget *sizes_menu;
945 GtkWidget *fonts_menu;
946 GSList *radio_group = NULL;
951 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
952 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
954 /* should we hide the toolbar? */
955 if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
956 gtk_widget_hide (parent_priv->toolbar);
958 /* Font color placeholder */
959 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
960 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
963 tool_item = GTK_WIDGET (gtk_tool_item_new ());
964 priv->font_color_button = hildon_color_button_new ();
965 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
966 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
967 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
968 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
969 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
970 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
971 g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
973 /* Font size and face placeholder */
974 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
975 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
977 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
978 priv->size_tool_button_label = gtk_label_new (NULL);
979 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
980 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
981 size_text,"</span>", NULL);
982 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
984 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
985 sizes_menu = gtk_menu_new ();
986 priv->size_items_group = NULL;
988 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
989 GtkWidget *size_menu_item;
991 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
992 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
993 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
994 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
995 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
996 gtk_widget_show (size_menu_item);
998 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1002 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1003 GtkWidget *item = (GtkWidget *) node->data;
1004 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1008 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1009 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1010 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1011 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1012 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1013 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1014 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1015 priv->font_size_toolitem = tool_item;
1018 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1019 priv->font_tool_button_label = gtk_label_new (NULL);
1020 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1021 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1023 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1024 fonts_menu = gtk_menu_new ();
1025 priv->font_items_group = NULL;
1027 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1028 GtkWidget *font_menu_item;
1029 GtkWidget *child_label;
1031 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1032 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1033 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1034 wp_get_font_name (font_index), "</span>", NULL);
1035 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1038 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1039 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1040 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1041 gtk_widget_show (font_menu_item);
1043 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1046 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1047 GtkWidget *item = (GtkWidget *) node->data;
1048 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1051 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1052 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1053 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1054 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1055 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1056 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1057 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1058 priv->font_face_toolitem = tool_item;
1060 /* Set expand and homogeneous for remaining items */
1061 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1062 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1063 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1064 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1065 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1066 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1067 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1068 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1069 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1077 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1080 ModestWindowPrivate *parent_priv;
1081 ModestMsgEditWindowPrivate *priv;
1082 GtkActionGroup *action_group;
1083 GError *error = NULL;
1084 GdkPixbuf *window_icon = NULL;
1087 gboolean prefer_formatted;
1089 ModestPair *account_pair = NULL;
1091 g_return_val_if_fail (msg, NULL);
1092 g_return_val_if_fail (account_name, NULL);
1094 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1096 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1097 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1099 parent_priv->ui_manager = gtk_ui_manager_new();
1100 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1101 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1103 /* Add common actions */
1104 gtk_action_group_add_actions (action_group,
1105 modest_msg_edit_action_entries,
1106 G_N_ELEMENTS (modest_msg_edit_action_entries),
1108 gtk_action_group_add_toggle_actions (action_group,
1109 modest_msg_edit_toggle_action_entries,
1110 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1112 gtk_action_group_add_radio_actions (action_group,
1113 modest_msg_edit_alignment_radio_action_entries,
1114 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1116 G_CALLBACK (modest_ui_actions_on_change_justify),
1118 gtk_action_group_add_radio_actions (action_group,
1119 modest_msg_edit_zoom_action_entries,
1120 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1122 G_CALLBACK (modest_ui_actions_on_change_zoom),
1124 gtk_action_group_add_radio_actions (action_group,
1125 modest_msg_edit_priority_action_entries,
1126 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1128 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1130 gtk_action_group_add_radio_actions (action_group,
1131 modest_msg_edit_file_format_action_entries,
1132 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1133 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1134 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1136 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1137 g_object_unref (action_group);
1139 /* Load the UI definition */
1140 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1142 if (error != NULL) {
1143 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1144 g_clear_error (&error);
1147 /* Add accelerators */
1148 gtk_window_add_accel_group (GTK_WINDOW (obj),
1149 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1152 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1153 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1156 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1158 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1160 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1162 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1163 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1165 setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
1167 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1168 if (account_pair != NULL)
1169 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1171 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1173 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1175 /* Set window icon */
1176 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1178 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1179 g_object_unref (window_icon);
1182 /* Dim at start clipboard actions */
1183 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1184 gtk_action_set_sensitive (action, FALSE);
1185 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1186 gtk_action_set_sensitive (action, FALSE);
1187 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1188 gtk_action_set_sensitive (action, FALSE);
1190 /* Update select all */
1191 update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1192 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
1193 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
1194 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
1195 g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
1197 /* set initial state of cc and bcc */
1198 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1199 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1200 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1201 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1202 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1203 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1205 /* Setup the file format */
1206 conf = modest_runtime_get_conf ();
1207 prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
1209 g_clear_error (&error);
1210 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
1212 file_format = (prefer_formatted) ?
1213 MODEST_FILE_FORMAT_FORMATTED_TEXT :
1214 MODEST_FILE_FORMAT_PLAIN_TEXT;
1215 modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
1217 update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1218 priv->update_caption_visibility = TRUE;
1220 reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1222 return (ModestWindow*) obj;
1226 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1228 GString **string_buffer = (GString **) user_data;
1230 *string_buffer = g_string_append (*string_buffer, buffer);
1236 * @result: A new string which should be freed with g_free().
1239 get_formatted_data (ModestMsgEditWindow *edit_window)
1241 ModestMsgEditWindowPrivate *priv;
1242 GString *string_buffer = g_string_new ("");
1244 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1246 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1248 return g_string_free (string_buffer, FALSE);
1253 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1256 const gchar *account_name;
1257 ModestMsgEditWindowPrivate *priv;
1259 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1261 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1263 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1264 g_return_val_if_fail (account_name, NULL);
1267 /* don't free these (except from) */
1268 data = g_slice_new0 (MsgData);
1269 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1271 data->account_name = g_strdup (account_name);
1272 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1273 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1274 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1275 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1276 if (priv->draft_msg) {
1277 data->draft_msg = g_object_ref (priv->draft_msg);
1278 } else if (priv->outbox_msg) {
1279 data->draft_msg = g_object_ref (priv->outbox_msg);
1281 data->draft_msg = NULL;
1284 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1286 gtk_text_buffer_get_bounds (buf, &b, &e);
1287 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1289 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1290 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1292 data->html_body = NULL;
1294 /* deep-copy the data */
1295 GList *cursor = priv->attachments;
1296 data->attachments = NULL;
1298 if (!(TNY_IS_MIME_PART(cursor->data))) {
1299 g_warning ("strange data in attachment list");
1300 cursor = g_list_next (cursor);
1303 data->attachments = g_list_append (data->attachments,
1304 g_object_ref (cursor->data));
1305 cursor = g_list_next (cursor);
1308 data->priority_flags = priv->priority_flags;
1315 unref_gobject (GObject *obj, gpointer data)
1317 if (!G_IS_OBJECT(obj))
1319 g_object_unref (obj);
1323 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1326 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1334 g_free (data->subject);
1335 g_free (data->plain_body);
1336 g_free (data->html_body);
1337 g_free (data->account_name);
1339 if (data->draft_msg != NULL) {
1340 g_object_unref (data->draft_msg);
1341 data->draft_msg = NULL;
1344 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1345 g_list_free (data->attachments);
1347 g_slice_free (MsgData, data);
1351 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1354 ModestMsgEditWindowPrivate *priv = NULL;
1355 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1357 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1359 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1361 return MODEST_MSG_EDIT_FORMAT_HTML;
1363 return MODEST_MSG_EDIT_FORMAT_TEXT;
1367 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1368 ModestMsgEditFormat format)
1370 ModestMsgEditWindowPrivate *priv;
1372 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1373 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1376 case MODEST_MSG_EDIT_FORMAT_HTML:
1377 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1379 case MODEST_MSG_EDIT_FORMAT_TEXT:
1380 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1383 g_return_if_reached ();
1387 ModestMsgEditFormatState *
1388 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1390 ModestMsgEditFormatState *format_state = NULL;
1391 ModestMsgEditWindowPrivate *priv;
1392 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1394 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1395 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1397 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1399 format_state = g_new0 (ModestMsgEditFormatState, 1);
1400 format_state->bold = buffer_format->bold&0x1;
1401 format_state->italics = buffer_format->italic&0x1;
1402 format_state->bullet = buffer_format->bullet&0x1;
1403 format_state->color = buffer_format->color;
1404 format_state->font_size = buffer_format->font_size;
1405 format_state->font_family = wp_get_font_name (buffer_format->font);
1406 format_state->justification = buffer_format->justification;
1407 g_free (buffer_format);
1409 return format_state;
1414 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1415 const ModestMsgEditFormatState *format_state)
1417 ModestMsgEditWindowPrivate *priv;
1418 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1419 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1420 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1421 g_return_if_fail (format_state != NULL);
1423 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1424 gtk_widget_grab_focus (priv->msg_body);
1425 buffer_format->bold = (format_state->bold != FALSE);
1426 buffer_format->italic = (format_state->italics != FALSE);
1427 buffer_format->color = format_state->color;
1428 buffer_format->font_size = format_state->font_size;
1429 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1430 buffer_format->justification = format_state->justification;
1431 buffer_format->bullet = format_state->bullet;
1433 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1435 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1436 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1437 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1438 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1439 buffer_format->cs.font = (buffer_format->font != current_format->font);
1440 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1441 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1443 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1444 if (buffer_format->cs.bold) {
1445 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1447 if (buffer_format->cs.italic) {
1448 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1450 if (buffer_format->cs.color) {
1451 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1453 if (buffer_format->cs.font_size) {
1454 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1456 if (buffer_format->cs.justification) {
1457 switch (buffer_format->justification) {
1458 case GTK_JUSTIFY_LEFT:
1459 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1461 case GTK_JUSTIFY_CENTER:
1462 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1464 case GTK_JUSTIFY_RIGHT:
1465 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1472 if (buffer_format->cs.font) {
1473 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1475 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1476 if (buffer_format->cs.bullet) {
1477 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1479 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1481 g_free (current_format);
1486 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1488 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1490 ModestWindowPrivate *parent_priv;
1491 ModestMsgEditWindowPrivate *priv;
1492 GtkWidget *new_size_menuitem;
1493 GtkWidget *new_font_menuitem;
1495 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1496 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1498 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1499 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1500 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1501 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1503 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1504 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1505 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1508 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1510 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1511 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1513 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1514 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1516 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1517 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1519 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1520 G_CALLBACK (modest_msg_edit_window_color_button_change),
1522 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1523 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1524 G_CALLBACK (modest_msg_edit_window_color_button_change),
1527 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1528 buffer_format->font_size))->data);
1529 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1533 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1534 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1535 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1537 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1538 G_CALLBACK (modest_msg_edit_window_size_change),
1540 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1541 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1542 G_CALLBACK (modest_msg_edit_window_size_change),
1546 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1547 buffer_format->font))->data);
1548 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1552 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1553 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1554 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1556 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1557 G_CALLBACK (modest_msg_edit_window_font_change),
1559 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1560 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1561 G_CALLBACK (modest_msg_edit_window_font_change),
1565 g_free (buffer_format);
1571 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1574 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1575 ModestMsgEditWindowPrivate *priv;
1576 GtkWidget *dialog = NULL;
1578 const GdkColor *new_color = NULL;
1580 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1581 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1583 #ifdef MODEST_HILDON_VERSION_0
1584 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1585 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1587 dialog = hildon_color_chooser_new ();
1588 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1589 #endif /*MODEST_HILDON_VERSION_0*/
1590 g_free (buffer_format);
1592 response = gtk_dialog_run (GTK_DIALOG (dialog));
1594 case GTK_RESPONSE_OK: {
1595 #ifdef MODEST_HILDON_VERSION_0
1596 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1599 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1601 #endif /*MODEST_HILDON_VERSION_0*/
1608 gtk_widget_destroy (dialog);
1610 if (new_color != NULL)
1611 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1616 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1619 ModestMsgEditWindowPrivate *priv;
1620 GtkWidget *dialog = NULL;
1622 GdkColor *old_color = NULL;
1623 const GdkColor *new_color = NULL;
1625 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1626 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1628 #ifdef MODEST_HILDON_VERSION_0
1629 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1630 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1632 dialog = hildon_color_chooser_new ();
1633 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1634 #endif /*MODEST_HILDON_VERSION_9*/
1636 response = gtk_dialog_run (GTK_DIALOG (dialog));
1638 case GTK_RESPONSE_OK: {
1639 #ifdef MODEST_HILDON_VERSION_0
1640 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1643 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1645 #endif /*MODEST_HILDON_VERSION_0*/
1651 gtk_widget_destroy (dialog);
1653 if (new_color != NULL)
1654 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1658 static TnyStream* create_stream_for_uri (const gchar* uri)
1663 TnyStream *result = NULL;
1665 GnomeVFSHandle *handle = NULL;
1666 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1667 if (test == GNOME_VFS_OK) {
1668 /* Create the tinymail stream: */
1669 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1670 result = TNY_STREAM (tny_vfs_stream_new (handle));
1677 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1680 ModestMsgEditWindowPrivate *priv;
1681 GtkWidget *dialog = NULL;
1683 GSList *uris = NULL;
1684 GSList *uri_node = NULL;
1686 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1688 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1689 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1690 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1692 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1694 response = gtk_dialog_run (GTK_DIALOG (dialog));
1696 case GTK_RESPONSE_OK:
1697 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1702 gtk_widget_destroy (dialog);
1704 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1706 GnomeVFSHandle *handle = NULL;
1707 GnomeVFSResult result;
1708 GtkTextIter position;
1709 GtkTextMark *insert_mark;
1711 uri = (const gchar *) uri_node->data;
1712 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1713 if (result == GNOME_VFS_OK) {
1715 GnomeVFSFileInfo info;
1716 gchar *filename, *basename, *escaped_filename;
1717 TnyMimePart *mime_part;
1719 const gchar *mime_type = NULL;
1720 GnomeVFSURI *vfs_uri;
1722 vfs_uri = gnome_vfs_uri_new (uri);
1724 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1725 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1726 g_free (escaped_filename);
1727 gnome_vfs_uri_unref (vfs_uri);
1729 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1730 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1732 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1734 mime_part = tny_platform_factory_new_mime_part
1735 (modest_runtime_get_platform_factory ());
1737 TnyStream *stream = create_stream_for_uri (uri);
1738 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1740 content_id = g_strdup_printf ("%d", priv->last_cid);
1741 tny_mime_part_set_content_id (mime_part, content_id);
1742 g_free (content_id);
1745 basename = g_path_get_basename (filename);
1746 tny_mime_part_set_filename (mime_part, basename);
1749 pixbuf = pixbuf_from_stream (stream, mime_type);
1751 if (pixbuf != NULL) {
1752 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1753 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1754 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1757 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1758 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1760 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1761 gtk_widget_show_all (priv->attachments_caption);
1762 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1772 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1775 ModestMsgEditWindowPrivate *priv;
1776 GtkWidget *dialog = NULL;
1778 GSList *uris = NULL;
1781 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1783 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1784 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1785 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1787 response = gtk_dialog_run (GTK_DIALOG (dialog));
1789 case GTK_RESPONSE_OK:
1790 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1795 gtk_widget_destroy (dialog);
1797 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1798 const gchar *uri = (const gchar *) uri_node->data;
1799 modest_msg_edit_window_attach_file_one (window, uri);
1801 g_slist_foreach (uris, (GFunc) g_free, NULL);
1802 g_slist_free (uris);
1806 modest_msg_edit_window_attach_file_one (
1807 ModestMsgEditWindow *window,
1810 g_return_if_fail (window);
1811 g_return_if_fail (uri);
1813 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1816 GnomeVFSHandle *handle = NULL;
1817 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1818 if (result == GNOME_VFS_OK) {
1819 TnyMimePart *mime_part;
1821 const gchar *mime_type = NULL;
1823 gchar *escaped_filename;
1826 GnomeVFSFileInfo info;
1827 GnomeVFSURI *vfs_uri;
1829 vfs_uri = gnome_vfs_uri_new (uri);
1832 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1833 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1834 g_free (escaped_filename);
1835 gnome_vfs_uri_unref (vfs_uri);
1837 if (gnome_vfs_get_file_info (uri,
1839 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1840 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1842 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1843 mime_part = tny_platform_factory_new_mime_part
1844 (modest_runtime_get_platform_factory ());
1845 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1847 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1849 content_id = g_strdup_printf ("%d", priv->last_cid);
1850 tny_mime_part_set_content_id (mime_part, content_id);
1851 g_free (content_id);
1854 basename = g_path_get_basename (filename);
1855 tny_mime_part_set_filename (mime_part, basename);
1858 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1859 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1861 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1862 gtk_widget_show_all (priv->attachments_caption);
1863 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1869 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1872 ModestMsgEditWindowPrivate *priv;
1873 gboolean clean_list = FALSE;
1875 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1876 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1878 if (att_list == NULL) {
1879 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1883 if (att_list == NULL) {
1884 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1886 GtkWidget *confirmation_dialog = NULL;
1887 gboolean dialog_response;
1889 gchar *message = NULL;
1890 const gchar *filename = NULL;
1892 if (att_list->next == NULL) {
1893 filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1897 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1898 att_list->next == NULL), filename);
1899 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1901 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1902 gtk_widget_destroy (confirmation_dialog);
1903 if (!dialog_response) {
1905 g_list_free (att_list);
1908 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1910 for (node = att_list; node != NULL; node = g_list_next (node)) {
1911 TnyMimePart *mime_part = (TnyMimePart *) node->data;
1912 const gchar *att_id;
1913 priv->attachments = g_list_remove (priv->attachments, mime_part);
1915 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1917 if (priv->attachments == NULL)
1918 gtk_widget_hide (priv->attachments_caption);
1919 att_id = tny_mime_part_get_content_id (mime_part);
1921 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1923 g_object_unref (mime_part);
1924 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1929 g_list_free (att_list);
1933 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1936 ModestMsgEditWindowPrivate *priv;
1937 GdkColor *new_color;
1938 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1940 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1941 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1944 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1946 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1948 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1950 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1955 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1958 ModestMsgEditWindowPrivate *priv;
1959 gint new_size_index;
1960 ModestMsgEditWindow *window;
1963 window = MODEST_MSG_EDIT_WINDOW (userdata);
1964 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1965 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1967 if (gtk_check_menu_item_get_active (menu_item)) {
1969 WPTextBufferFormat format;
1971 memset (&format, 0, sizeof (format));
1972 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
1974 label = gtk_bin_get_child (GTK_BIN (menu_item));
1976 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1977 format.cs.font_size = TRUE;
1978 format.cs.text_position = TRUE;
1979 format.cs.font = TRUE;
1980 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1981 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
1983 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1984 (gpointer) wp_get_font_size_index (new_size_index, 12)))
1985 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1987 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1988 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1989 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1995 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1998 ModestMsgEditWindowPrivate *priv;
1999 gint new_font_index;
2000 ModestMsgEditWindow *window;
2003 window = MODEST_MSG_EDIT_WINDOW (userdata);
2004 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2005 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2007 if (gtk_check_menu_item_get_active (menu_item)) {
2010 label = gtk_bin_get_child (GTK_BIN (menu_item));
2012 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2014 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2015 (gpointer) new_font_index))
2016 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2018 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2019 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2020 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2026 modest_msg_edit_window_set_zoom (ModestWindow *window,
2029 ModestMsgEditWindowPrivate *priv;
2030 ModestWindowPrivate *parent_priv;
2031 GtkRadioAction *zoom_radio_action;
2033 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2035 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2036 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2037 priv->zoom_level = zoom;
2038 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2040 /* Zoom level menu options should be updated with the current zoom level */
2041 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2042 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2043 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2044 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2045 /* FIXME: Not availible before Gtk 2.10 */
2047 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2052 modest_msg_edit_window_get_zoom (ModestWindow *window)
2054 ModestMsgEditWindowPrivate *priv;
2056 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2058 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2059 return priv->zoom_level;
2063 zoom_allowed (ModestMsgEditWindow *window)
2067 focus = gtk_window_get_focus (GTK_WINDOW (window));
2068 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2072 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2074 ModestWindowPrivate *parent_priv;
2075 GtkRadioAction *zoom_radio_action;
2076 GSList *group, *node;
2078 /* First we check if the text view is focused. If not, zooming is not allowed */
2079 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2080 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2084 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2085 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2086 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2088 group = gtk_radio_action_get_group (zoom_radio_action);
2090 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2091 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2095 for (node = group; node != NULL; node = g_slist_next (node)) {
2096 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2097 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2105 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2107 ModestWindowPrivate *parent_priv;
2108 GtkRadioAction *zoom_radio_action;
2109 GSList *group, *node;
2111 /* First we check if the text view is focused. If not, zooming is not allowed */
2112 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2113 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2117 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2118 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2119 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2121 group = gtk_radio_action_get_group (zoom_radio_action);
2123 for (node = group; node != NULL; node = g_slist_next (node)) {
2124 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2125 if (node->next != NULL) {
2126 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2129 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2137 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2139 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2140 ModestWindowPrivate *parent_priv;
2141 ModestWindowMgr *mgr;
2142 gboolean is_fullscreen;
2143 GtkAction *fs_toggle_action;
2146 mgr = modest_runtime_get_window_mgr ();
2147 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2149 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2151 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2152 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2153 if (is_fullscreen != active)
2154 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2162 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
2164 ModestWindowPrivate *parent_priv;
2165 GtkAction *fs_toggle_action;
2168 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2170 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2171 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
2172 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
2176 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2179 ModestMsgEditWindowPrivate *priv = NULL;
2180 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2182 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2183 if (!priv->update_caption_visibility)
2186 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2188 gtk_widget_show (priv->cc_caption);
2190 gtk_widget_hide (priv->cc_caption);
2192 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2196 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2199 ModestMsgEditWindowPrivate *priv = NULL;
2200 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2202 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2203 if (!priv->update_caption_visibility)
2206 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2208 gtk_widget_show (priv->bcc_caption);
2210 gtk_widget_hide (priv->bcc_caption);
2212 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2216 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2217 ModestRecptEditor *editor)
2219 ModestMsgEditWindowPrivate *priv;
2221 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2222 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2223 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2225 if (editor == NULL) {
2226 GtkWidget *view_focus;
2227 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2229 /* This code should be kept in sync with ModestRecptEditor. The
2230 textview inside the recpt editor is the one that really gets the
2231 focus. As it's inside a scrolled window, and this one inside the
2232 hbox recpt editor inherits from, we'll need to go up in the
2233 hierarchy to know if the text view is part of the recpt editor
2234 or if it's a different text entry */
2236 if (gtk_widget_get_parent (view_focus)) {
2237 GtkWidget *first_parent;
2239 first_parent = gtk_widget_get_parent (view_focus);
2240 if (gtk_widget_get_parent (first_parent) &&
2241 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2242 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2247 editor = MODEST_RECPT_EDITOR (priv->to_field);
2251 modest_address_book_select_addresses (editor);
2256 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2258 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2260 modest_msg_edit_window_open_addressbook (window, NULL);
2264 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2265 gboolean show_toolbar)
2267 ModestWindowPrivate *parent_priv;
2269 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2270 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2272 /* FIXME: we can not just use the code of
2273 modest_msg_edit_window_setup_toolbar because it has a
2274 mixture of both initialization and creation code. */
2277 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2279 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2283 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2284 TnyHeaderFlags priority_flags)
2286 ModestMsgEditWindowPrivate *priv;
2287 ModestWindowPrivate *parent_priv;
2289 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2291 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2292 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2293 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2295 if (priv->priority_flags != priority_flags) {
2296 GtkAction *priority_action = NULL;
2298 priv->priority_flags = priority_flags;
2300 switch (priority_flags) {
2301 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2302 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2303 gtk_widget_show (priv->priority_icon);
2304 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2305 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2307 case TNY_HEADER_FLAG_LOW_PRIORITY:
2308 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2309 gtk_widget_show (priv->priority_icon);
2310 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2311 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2314 gtk_widget_hide (priv->priority_icon);
2315 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2316 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2319 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2320 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2325 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2328 ModestMsgEditWindowPrivate *priv;
2329 ModestWindowPrivate *parent_priv;
2330 gint current_format;
2332 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2334 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2335 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2337 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2338 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2340 if (current_format != file_format) {
2341 switch (file_format) {
2342 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2343 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2345 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2349 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2350 response = gtk_dialog_run (GTK_DIALOG (dialog));
2351 gtk_widget_destroy (dialog);
2352 if (response == GTK_RESPONSE_OK) {
2353 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2355 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2356 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2361 update_dimmed (window);
2366 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2369 ModestMsgEditWindowPrivate *priv;
2370 WPTextBufferFormat oldfmt, fmt;
2371 gint old_position = 0;
2375 GdkColor *color = NULL;
2376 gboolean bold, bold_set, italic, italic_set;
2377 gboolean underline, underline_set;
2378 gboolean strikethrough, strikethrough_set;
2379 gboolean position_set;
2380 gboolean font_size_set, font_set, color_set;
2383 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2384 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2386 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2388 /* First we get the currently selected font information */
2389 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2390 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2392 switch (oldfmt.text_position) {
2393 case TEXT_POSITION_NORMAL:
2396 case TEXT_POSITION_SUPERSCRIPT:
2404 g_object_set (G_OBJECT (dialog),
2405 "bold", oldfmt.bold != FALSE,
2406 "bold-set", !oldfmt.cs.bold,
2407 "underline", oldfmt.underline != FALSE,
2408 "underline-set", !oldfmt.cs.underline,
2409 "italic", oldfmt.italic != FALSE,
2410 "italic-set", !oldfmt.cs.italic,
2411 "strikethrough", oldfmt.strikethrough != FALSE,
2412 "strikethrough-set", !oldfmt.cs.strikethrough,
2413 "color", &oldfmt.color,
2414 "color-set", !oldfmt.cs.color,
2415 "size", wp_font_size[oldfmt.font_size],
2416 "size-set", !oldfmt.cs.font_size,
2417 "position", old_position,
2418 "position-set", !oldfmt.cs.text_position,
2419 "family", wp_get_font_name (oldfmt.font),
2420 "family-set", !oldfmt.cs.font,
2423 gtk_widget_show_all (dialog);
2424 response = gtk_dialog_run (GTK_DIALOG (dialog));
2425 if (response == GTK_RESPONSE_OK) {
2427 g_object_get( dialog,
2429 "bold-set", &bold_set,
2430 "underline", &underline,
2431 "underline-set", &underline_set,
2433 "italic-set", &italic_set,
2434 "strikethrough", &strikethrough,
2435 "strikethrough-set", &strikethrough_set,
2437 "color-set", &color_set,
2439 "size-set", &font_size_set,
2440 "family", &font_name,
2441 "family-set", &font_set,
2442 "position", &position,
2443 "position-set", &position_set,
2448 if (response == GTK_RESPONSE_OK) {
2449 memset(&fmt, 0, sizeof(fmt));
2455 fmt.italic = italic;
2456 fmt.cs.italic = TRUE;
2458 if (underline_set) {
2459 fmt.underline = underline;
2460 fmt.cs.underline = TRUE;
2462 if (strikethrough_set) {
2463 fmt.strikethrough = strikethrough;
2464 fmt.cs.strikethrough = TRUE;
2469 ? TEXT_POSITION_NORMAL
2470 : ( ( position == 1 )
2471 ? TEXT_POSITION_SUPERSCRIPT
2472 : TEXT_POSITION_SUBSCRIPT );
2473 fmt.cs.text_position = TRUE;
2477 fmt.cs.color = TRUE;
2480 fmt.font = wp_get_font_index(font_name,
2485 if (font_size_set) {
2486 fmt.font_size = wp_get_font_size_index(
2487 font_size, DEFAULT_FONT_SIZE);
2488 fmt.cs.font_size = TRUE;
2490 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2492 gtk_widget_destroy (dialog);
2494 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2498 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2500 ModestMsgEditWindowPrivate *priv;
2502 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2503 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2505 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2507 update_dimmed (window);
2512 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2514 ModestMsgEditWindowPrivate *priv;
2516 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2517 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2519 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2521 update_dimmed (window);
2526 update_dimmed (ModestMsgEditWindow *window)
2528 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2529 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2533 gboolean editor_focused;
2535 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2536 editor_focused = gtk_widget_is_focus (priv->msg_body);
2538 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2539 gtk_action_set_sensitive (action, rich_text && editor_focused);
2540 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2541 /* gtk_action_set_sensitive (action, rich_text && editor_focused); */
2542 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2543 gtk_action_set_sensitive (action, rich_text && editor_focused);
2544 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2545 gtk_action_set_sensitive (action, rich_text && editor_focused);
2546 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2547 gtk_action_set_sensitive (action, rich_text && editor_focused);
2548 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2549 gtk_action_set_sensitive (action, rich_text && editor_focused);
2550 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2551 gtk_action_set_sensitive (action, rich_text && editor_focused);
2552 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2553 gtk_action_set_sensitive (action, rich_text && editor_focused);
2554 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2555 gtk_action_set_sensitive (action, rich_text && editor_focused);
2556 widget = priv->font_color_button;
2557 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2558 widget = priv->font_size_toolitem;
2559 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2560 widget = priv->font_face_toolitem;
2561 gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2565 setup_insensitive_handlers (ModestMsgEditWindow *window)
2567 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2568 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2571 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2572 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2573 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2574 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2575 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2576 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2577 widget = priv->font_color_button;
2578 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2579 widget = priv->font_size_toolitem;
2580 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2581 widget = priv->font_face_toolitem;
2582 g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2587 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2589 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2592 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2593 gtk_action_set_sensitive (action, can_undo);
2597 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2599 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2602 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/RedoMenu");
2603 gtk_action_set_sensitive (action, can_redo);
2607 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2610 GtkTextIter match_start, match_end;
2612 if (image_id == NULL)
2615 gtk_text_buffer_get_start_iter (buffer, &iter);
2617 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2618 GSList *tags = gtk_text_iter_get_tags (&match_start);
2620 for (node = tags; node != NULL; node = g_slist_next (node)) {
2621 GtkTextTag *tag = (GtkTextTag *) node->data;
2622 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2623 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2624 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2626 offset = gtk_text_iter_get_offset (&match_start);
2627 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2628 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2632 gtk_text_iter_forward_char (&iter);
2637 message_is_empty (ModestMsgEditWindow *window)
2639 ModestMsgEditWindowPrivate *priv = NULL;
2641 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2642 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2644 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2645 * so we can ignore markup.
2647 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2650 count = gtk_text_buffer_get_char_count (buf);
2656 msg_body_focus (GtkWidget *focus,
2657 GdkEventFocus *event,
2661 update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2666 recpt_field_changed (GtkTextBuffer *buffer,
2667 ModestMsgEditWindow *editor)
2669 update_send_dimming (editor);
2673 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2675 update_send_dimming (editor);
2679 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2681 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2682 const gchar *subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2683 if (message_is_empty(editor) || (subject == NULL || subject[0] == '\0')) {
2684 hildon_banner_show_information (NULL, NULL, _("mcen_ib_subject_or_body_not_modified"));
2686 hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2691 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2693 gboolean rich_text, editor_focused;
2695 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2696 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2697 editor_focused = gtk_widget_is_focus (priv->msg_body);
2700 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2701 else if (!editor_focused)
2702 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2706 reset_modified (ModestMsgEditWindow *editor)
2708 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2709 GtkTextBuffer *buffer;
2711 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2712 gtk_text_buffer_set_modified (buffer, FALSE);
2713 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2714 gtk_text_buffer_set_modified (buffer, FALSE);
2715 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2716 gtk_text_buffer_set_modified (buffer, FALSE);
2717 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2721 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2723 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2724 GtkTextBuffer *buffer;
2726 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2727 if (gtk_text_buffer_get_modified (buffer))
2729 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2730 if (gtk_text_buffer_get_modified (buffer))
2732 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2733 if (gtk_text_buffer_get_modified (buffer))
2735 if (gtk_text_buffer_get_modified (priv->text_buffer))
2745 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2747 ModestMsgEditWindowPrivate *priv = NULL;
2749 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2750 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2752 /* check if there's no recipient added */
2753 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2754 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2755 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2756 /* no recipient contents, then select contacts */
2757 modest_msg_edit_window_open_addressbook (window, NULL);
2761 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2762 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2765 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2766 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2769 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2770 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2774 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2775 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2776 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2783 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2784 ModestMsgEditWindow *window)
2786 modest_msg_edit_window_offer_attach_file (window);
2790 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2792 ModestMsgEditWindow *window)
2794 ModestWindowPrivate *parent_priv;
2795 ModestMsgEditWindowPrivate *priv;
2797 GList *selected_attachments = NULL;
2798 gint n_att_selected = 0;
2800 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2801 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2803 if (!GTK_WIDGET_VISIBLE (window))
2806 selected_attachments = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2807 n_att_selected = g_list_length (selected_attachments);
2808 g_list_free (selected_attachments);
2810 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
2811 gtk_action_set_sensitive (action, n_att_selected == 1);
2813 update_copy_cut_dimming (window);
2814 update_paste_dimming (window);
2818 update_window_title (ModestMsgEditWindow *window)
2820 ModestMsgEditWindowPrivate *priv = NULL;
2821 const gchar *subject;
2823 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2824 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2825 if (subject == NULL || subject[0] == '\0')
2826 subject = _("mail_va_new_email");
2828 gtk_window_set_title (GTK_WINDOW (window), subject);
2833 subject_field_changed (GtkEditable *editable,
2834 ModestMsgEditWindow *window)
2836 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2837 update_window_title (window);
2838 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2839 update_send_dimming (window);
2843 subject_field_insert_text (GtkEditable *editable,
2845 gint new_text_length,
2847 ModestMsgEditWindow *window)
2849 GString *result = g_string_new ("");
2851 gint result_len = 0;
2853 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2854 gunichar c = g_utf8_get_char_validated (current, 8);
2855 /* Invalid unichar, stop */
2861 result = g_string_append_unichar (result, c);
2865 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2866 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2868 g_signal_emit_by_name (editable, "insert-text",
2869 (gpointer) result->str, (gpointer) strlen (result->str),
2870 (gpointer) position, (gpointer) window);
2873 g_string_free (result, TRUE);
2877 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2880 ModestMsgEditWindowPrivate *priv = NULL;
2882 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2883 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2885 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2888 gtk_widget_show_all (priv->find_toolbar);
2889 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2891 gtk_widget_hide_all (priv->find_toolbar);
2892 gtk_widget_grab_focus (priv->msg_body);
2898 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2900 GtkTextIter *match_start,
2901 GtkTextIter *match_end)
2903 GtkTextIter end_iter;
2904 gchar *str_casefold;
2907 gchar *range_casefold;
2910 gboolean result = FALSE;
2917 gtk_text_iter_forward_to_end (&end_iter);
2919 str_casefold = g_utf8_casefold (str, -1);
2920 str_chars_n = strlen (str);
2922 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2923 range_casefold = g_utf8_casefold (range_text, -1);
2924 range_chars_n = strlen (range_casefold);
2926 if (range_chars_n < str_chars_n) {
2927 g_free (str_casefold);
2928 g_free (range_text);
2929 g_free (range_casefold);
2933 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2934 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2935 if (!g_utf8_collate (range_subtext, str_casefold)) {
2936 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2938 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2939 match_start, match_end, NULL);
2940 g_free (found_text);
2942 g_free (range_subtext);
2946 g_free (str_casefold);
2947 g_free (range_text);
2948 g_free (range_casefold);
2955 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2956 ModestMsgEditWindow *window)
2958 gchar *current_search = NULL;
2959 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2961 GtkTextIter selection_start, selection_end;
2962 GtkTextIter match_start, match_end;
2963 gboolean continue_search = FALSE;
2965 if (message_is_empty (window)) {
2966 g_free (priv->last_search);
2967 priv->last_search = NULL;
2968 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
2972 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
2973 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2974 g_free (current_search);
2975 g_free (priv->last_search);
2976 priv->last_search = NULL;
2977 /* Information banner about empty search */
2978 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
2982 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
2983 continue_search = TRUE;
2985 g_free (priv->last_search);
2986 priv->last_search = g_strdup (current_search);
2989 if (continue_search) {
2990 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
2991 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
2992 &match_start, &match_end);
2994 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
2996 GtkTextIter buffer_start;
2997 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
2998 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
2999 &match_start, &match_end);
3001 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3004 /* Mark as selected the string found in search */
3006 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3007 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3009 g_free (priv->last_search);
3010 priv->last_search = NULL;
3012 g_free (current_search);
3016 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3017 ModestMsgEditWindow *window)
3019 GtkToggleAction *toggle;
3020 ModestWindowPrivate *parent_priv;
3021 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3023 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3024 gtk_toggle_action_set_active (toggle, FALSE);
3029 update_copy_cut_dimming (ModestMsgEditWindow *window)
3031 ModestWindowPrivate *parent_priv = NULL;
3032 ModestMsgEditWindowPrivate *priv = NULL;
3033 GtkClipboard *clipboard = NULL;
3034 GtkAction *action = NULL;
3035 gboolean has_selection = FALSE;
3036 GtkWidget *focused = NULL;
3037 gchar *selection = NULL;
3039 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3040 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3041 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3042 focused = gtk_window_get_focus (GTK_WINDOW (window));
3044 has_selection = gtk_clipboard_wait_for_targets (clipboard, NULL, NULL);
3046 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
3047 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3048 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
3049 gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3051 if (selection != NULL)
3056 update_paste_dimming (ModestMsgEditWindow *window)
3058 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3059 GtkAction *action = NULL;
3060 GtkClipboard *clipboard = NULL;
3061 ModestEmailClipboard *e_clipboard;
3065 focused = gtk_window_get_focus (GTK_WINDOW (window));
3067 e_clipboard = modest_runtime_get_email_clipboard ();
3068 if (!modest_email_clipboard_cleared (e_clipboard)) {
3071 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3072 active = gtk_clipboard_wait_is_text_available (clipboard);
3076 if (MODEST_IS_ATTACHMENTS_VIEW (focused))
3080 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
3081 gtk_action_set_sensitive (action, active);
3086 update_select_all_dimming (ModestMsgEditWindow *window)
3089 gboolean dimmed = FALSE;
3091 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3093 focused = gtk_window_get_focus (GTK_WINDOW (window));
3094 if (GTK_IS_ENTRY (focused)) {
3095 const gchar *current_text;
3096 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
3097 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
3098 } else if (GTK_IS_TEXT_VIEW (focused)) {
3099 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
3100 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
3101 } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
3104 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
3105 gtk_action_set_sensitive (action, !dimmed);
3109 update_zoom_dimming (ModestMsgEditWindow *window)
3112 gboolean dimmed = FALSE;
3114 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3116 focused = gtk_window_get_focus (GTK_WINDOW (window));
3117 dimmed = ! WP_IS_TEXT_VIEW (focused);
3118 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
3119 gtk_action_set_sensitive (action, !dimmed);
3123 update_send_dimming (ModestMsgEditWindow *window)
3125 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3126 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3127 GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
3128 const gchar *subject;
3129 gboolean dim = FALSE;
3132 to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
3133 cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
3134 bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
3135 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3137 dim = ((gtk_text_buffer_get_char_count (to_buffer) +
3138 gtk_text_buffer_get_char_count (cc_buffer) +
3139 gtk_text_buffer_get_char_count (bcc_buffer)) == 0)
3140 || (subject == NULL || subject[0] == '\0')
3141 || message_is_empty(window);
3143 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
3144 gtk_action_set_sensitive (action, !dim);
3145 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
3146 gtk_action_set_sensitive (action, !dim);
3150 edit_menu_activated (GtkAction *action,
3153 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3155 update_select_all_dimming (window);
3156 update_copy_cut_dimming (window);
3157 update_paste_dimming (window);
3160 view_menu_activated (GtkAction *action,
3163 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3165 update_zoom_dimming (window);
3169 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3171 ModestMsgEditWindowPrivate *priv;
3173 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3178 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3181 ModestMsgEditWindowPrivate *priv;
3183 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3189 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3192 ModestMsgEditWindowPrivate *priv;
3193 TnyHeader *header = NULL;
3195 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3196 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3198 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3199 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3201 if (priv->draft_msg != NULL) {
3202 header = tny_msg_get_header (priv->draft_msg);
3203 if (TNY_IS_HEADER (header)) {
3204 modest_window_mgr_unregister_header (mgr, header);
3206 g_object_unref (priv->draft_msg);
3209 if (draft != NULL) {
3210 g_object_ref (draft);
3211 header = tny_msg_get_header (draft);
3212 if (TNY_IS_HEADER (header))
3213 modest_window_mgr_register_header (mgr, header);
3214 if (priv->msg_uid) {
3215 g_free (priv->msg_uid);
3216 priv->msg_uid = NULL;
3218 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3221 priv->draft_msg = draft;
3225 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3226 GtkTextIter *start, GtkTextIter *end,
3229 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3230 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3233 if (tag == NULL+13) return;
3234 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3235 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3236 replace_with_attachments (window, priv->attachments);
3241 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3244 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3246 g_return_if_fail (TNY_IS_MIME_PART (part));
3247 priv->attachments = g_list_prepend (priv->attachments, part);
3248 g_object_ref (part);
3249 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3250 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3251 gtk_widget_show_all (priv->attachments_caption);
3252 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3256 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3258 ModestMsgEditWindowPrivate *priv;
3260 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3261 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3263 return priv->msg_uid;