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-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include "modest-maemo-utils.h"
81 #define DEFAULT_FONT_SIZE 3
82 #define DEFAULT_FONT 2
83 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
84 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
85 #define DEFAULT_MAIN_VBOX_SPACING 6
86 #define SUBJECT_MAX_LENGTH 1000
87 #define IMAGE_MAX_WIDTH 560
88 #define DEFAULT_FONT_SCALE 1.5
90 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
91 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
92 static void modest_msg_edit_window_finalize (GObject *obj);
94 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
95 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
96 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
98 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
99 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
100 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
101 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
102 GtkTextIter *start, GtkTextIter *end,
104 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
105 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
106 static void subject_field_insert_text (GtkEditable *editable,
108 gint new_text_length,
110 ModestMsgEditWindow *window);
111 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
113 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
115 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
117 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
118 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
119 GdkEventWindowState *event,
121 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
122 ModestRecptEditor *editor);
123 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
124 ModestMsgEditWindow *window);
126 /* ModestWindow methods implementation */
127 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
128 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
129 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
130 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
131 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
132 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
133 gboolean show_toolbar);
134 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
136 ModestMsgEditWindow *window);
137 static void subject_field_move_cursor (GtkEntry *entry,
138 GtkMovementStep step,
142 static void update_window_title (ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
148 ModestMsgEditWindow *window);
149 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
151 GtkTextIter *match_start,
152 GtkTextIter *match_end);
154 static void remove_tags (WPTextBuffer *buffer);
156 static void on_account_removed (TnyAccountStore *account_store,
161 static void DEBUG_BUFFER (WPTextBuffer *buffer)
166 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
167 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
168 while (!gtk_text_iter_is_end (&iter)) {
169 GString *output = g_string_new ("");
170 GSList *toggled_tags;
173 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
174 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
175 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
176 GtkTextTag *tag = (GtkTextTag *) node->data;
178 g_object_get (G_OBJECT (tag), "name", &name, NULL);
179 output = g_string_append (output, name);
180 g_string_append (output, " ");
182 output = g_string_append (output, "] OPENED [ ");
183 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
184 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
185 GtkTextTag *tag = (GtkTextTag *) node->data;
187 g_object_get (G_OBJECT (tag), "name", &name, NULL);
188 output = g_string_append (output, name);
189 g_string_append (output, " ");
191 output = g_string_append (output, "]\n");
192 g_message ("%s", output->str);
193 g_string_free (output, TRUE);
194 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
196 g_message ("END BUFFER");
201 /* static gboolean */
202 /* on_key_pressed (GtkWidget *self, */
203 /* GdkEventKey *event, */
204 /* gpointer user_data); */
206 /* list my signals */
213 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
214 struct _ModestMsgEditWindowPrivate {
216 GtkWidget *header_box;
218 ModestPairList *from_field_protos;
219 GtkWidget *from_field;
223 GtkWidget *bcc_field;
224 GtkWidget *subject_field;
225 GtkWidget *attachments_view;
226 GtkWidget *priority_icon;
227 GtkWidget *add_attachment_button;
229 GtkWidget *cc_caption;
230 GtkWidget *bcc_caption;
231 gboolean update_caption_visibility;
232 GtkWidget *attachments_caption;
234 GtkTextBuffer *text_buffer;
236 GtkWidget *font_size_toolitem;
237 GtkWidget *font_face_toolitem;
238 GtkWidget *font_color_button;
239 GSList *font_items_group;
240 GtkWidget *font_tool_button_label;
241 GSList *size_items_group;
242 GtkWidget *size_tool_button_label;
244 GtkWidget *find_toolbar;
248 GtkWidget *scroll_area;
249 gint last_vadj_upper;
255 TnyHeaderFlags priority_flags;
259 gboolean can_undo, can_redo;
260 gulong clipboard_change_handler_id;
261 gulong default_clipboard_change_handler_id;
262 gulong account_removed_handler_id;
263 gchar *clipboard_text;
272 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
273 MODEST_TYPE_MSG_EDIT_WINDOW, \
274 ModestMsgEditWindowPrivate))
276 static GtkWindowClass *parent_class = NULL;
278 /* uncomment the following if you have defined any signals */
279 /* static guint signals[LAST_SIGNAL] = {0}; */
282 modest_msg_edit_window_get_type (void)
284 static GType my_type = 0;
286 static const GTypeInfo my_info = {
287 sizeof(ModestMsgEditWindowClass),
288 NULL, /* base init */
289 NULL, /* base finalize */
290 (GClassInitFunc) modest_msg_edit_window_class_init,
291 NULL, /* class finalize */
292 NULL, /* class data */
293 sizeof(ModestMsgEditWindow),
295 (GInstanceInitFunc) modest_msg_edit_window_init,
298 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
299 "ModestMsgEditWindow",
302 wp_text_buffer_library_init ();
308 save_state (ModestWindow *self)
310 modest_widget_memory_save (modest_runtime_get_conf(),
311 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
316 restore_settings (ModestMsgEditWindow *self)
318 modest_widget_memory_restore (modest_runtime_get_conf(),
319 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
324 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
326 GObjectClass *gobject_class;
327 ModestWindowClass *modest_window_class;
328 gobject_class = (GObjectClass*) klass;
329 modest_window_class = (ModestWindowClass*) klass;
331 parent_class = g_type_class_peek_parent (klass);
332 gobject_class->finalize = modest_msg_edit_window_finalize;
334 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
335 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
336 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
337 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
338 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
339 modest_window_class->save_state_func = save_state;
340 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
342 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
346 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
348 ModestMsgEditWindowPrivate *priv;
349 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
351 priv->msg_body = NULL;
352 priv->from_field = NULL;
353 priv->to_field = NULL;
354 priv->cc_field = NULL;
355 priv->bcc_field = NULL;
356 priv->subject_field = NULL;
357 priv->attachments = NULL;
360 priv->zoom_level = 1.0;
362 priv->cc_caption = NULL;
363 priv->bcc_caption = NULL;
364 priv->update_caption_visibility = FALSE;
366 priv->priority_flags = 0;
368 priv->find_toolbar = NULL;
369 priv->last_search = NULL;
371 priv->draft_msg = NULL;
372 priv->outbox_msg = NULL;
373 priv->msg_uid = NULL;
375 priv->can_undo = FALSE;
376 priv->can_redo = FALSE;
377 priv->clipboard_change_handler_id = 0;
378 priv->default_clipboard_change_handler_id = 0;
379 priv->account_removed_handler_id = 0;
380 priv->clipboard_text = NULL;
383 priv->last_vadj_upper = 0;
387 /* FIXME: this is a dup from the one in gtk/ */
390 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
392 static ModestPairList*
393 get_transports (void)
395 GSList *transports = NULL;
397 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
398 GSList *accounts = modest_account_mgr_account_names (account_mgr,
399 TRUE /* only enabled accounts. */);
401 GSList *cursor = accounts;
403 gchar *account_name = cursor->data;
404 gchar *from_string = NULL;
406 from_string = modest_account_mgr_get_from_string (account_mgr,
410 if (from_string && account_name) {
411 gchar *name = account_name;
412 ModestPair *pair = modest_pair_new ((gpointer) name,
413 (gpointer) from_string , TRUE);
414 transports = g_slist_prepend (transports, pair);
417 cursor = cursor->next;
419 g_slist_free (accounts); /* only free the accounts, not the elements,
420 * because they are used in the pairlist */
424 void vadj_changed (GtkAdjustment *adj,
425 ModestMsgEditWindow *window)
427 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
429 GdkRectangle rectangle, cursor_rectangle;
430 GtkTextIter position;
434 /* We detect if cursor is visible using the full height, not only the center. This
436 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
437 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
439 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
440 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
442 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
443 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
445 if (gtk_widget_is_focus (priv->msg_body) &&
447 if (priv->last_vadj_upper != adj->upper) {
450 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
451 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
452 insert, 0.1, FALSE, 0.0, 0.0);
455 priv->last_vadj_upper = adj->upper;
460 init_window (ModestMsgEditWindow *obj)
462 GtkWidget *from_caption, *to_caption, *subject_caption;
463 GtkWidget *main_vbox;
464 ModestMsgEditWindowPrivate *priv;
466 GtkSizeGroup *size_group;
468 GtkWidget *subject_box;
469 GtkWidget *attachment_icon;
470 GtkWidget *window_box;
471 #if (GTK_MINOR_VERSION >= 10)
472 GdkAtom deserialize_type;
474 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
476 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
478 /* Note: This ModestPairList* must exist for as long as the combo
479 * that uses it, because the ModestComboBox uses the ID opaquely,
480 * so it can't know how to manage its memory. */
481 priv->from_field_protos = get_transports ();
483 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
485 priv->to_field = modest_recpt_editor_new ();
486 priv->cc_field = modest_recpt_editor_new ();
487 priv->bcc_field = modest_recpt_editor_new ();
488 subject_box = gtk_hbox_new (FALSE, 0);
489 priv->priority_icon = gtk_image_new ();
490 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
491 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
492 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
493 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
494 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
495 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
496 priv->add_attachment_button = gtk_button_new ();
497 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
498 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
499 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
500 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
501 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
502 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
503 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
504 priv->attachments_view = modest_attachments_view_new (NULL);
506 priv->header_box = gtk_vbox_new (FALSE, 0);
508 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
509 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
510 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
511 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
512 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
513 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
514 g_object_unref (size_group);
516 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
517 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
518 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
519 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
520 gtk_size_group_add_widget (size_group, priv->subject_field);
521 gtk_size_group_add_widget (size_group, priv->attachments_view);
522 g_object_unref (size_group);
524 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
525 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
526 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
527 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
528 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
529 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
530 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
533 priv->msg_body = wp_text_view_new ();
534 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
535 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
536 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
537 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
538 #if (GTK_MINOR_VERSION >= 10)
539 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
540 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
542 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
543 deserialize_type, TRUE);
545 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
547 priv->find_toolbar = hildon_find_toolbar_new (NULL);
548 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
550 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
552 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
553 G_CALLBACK (text_buffer_refresh_attributes), obj);
554 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
555 G_CALLBACK (text_buffer_can_undo), obj);
556 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
557 G_CALLBACK (text_buffer_can_redo), obj);
558 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
559 G_CALLBACK (body_changed), obj);
560 g_signal_connect (G_OBJECT (obj), "window-state-event",
561 G_CALLBACK (modest_msg_edit_window_window_state_event),
563 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
564 G_CALLBACK (text_buffer_apply_tag), obj);
565 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
566 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
567 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
568 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
569 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
570 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
572 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
573 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
575 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
576 G_CALLBACK (msg_body_focus), obj);
577 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
578 G_CALLBACK (msg_body_focus), obj);
579 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
580 "changed", G_CALLBACK (recpt_field_changed), obj);
581 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
582 "changed", G_CALLBACK (recpt_field_changed), obj);
583 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
584 "changed", G_CALLBACK (recpt_field_changed), obj);
585 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
586 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
587 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
589 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
590 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
592 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
593 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
594 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
595 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
597 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
599 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
600 frame = gtk_frame_new (NULL);
601 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
603 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
604 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
605 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
607 G_CALLBACK (vadj_changed),
609 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
611 window_box = gtk_vbox_new (FALSE, 0);
612 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
613 gtk_container_add (GTK_CONTAINER(obj), window_box);
614 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
615 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
617 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
618 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
619 priv->default_clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
620 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
625 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
627 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
629 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
630 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
631 priv->clipboard_change_handler_id))
632 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
633 priv->clipboard_change_handler_id);
634 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
635 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
636 priv->default_clipboard_change_handler_id))
637 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
638 priv->default_clipboard_change_handler_id);
640 if (priv->account_removed_handler_id &&
641 g_signal_handler_is_connected (modest_runtime_get_account_store (),
642 priv->account_removed_handler_id))
643 g_signal_handler_disconnect(modest_runtime_get_account_store (),
644 priv->account_removed_handler_id);
648 modest_msg_edit_window_finalize (GObject *obj)
650 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
652 /* Sanity check: shouldn't be needed, the window mgr should
653 call this function before */
654 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
656 if (priv->clipboard_text != NULL) {
657 g_free (priv->clipboard_text);
658 priv->clipboard_text = NULL;
661 if (priv->draft_msg != NULL) {
662 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
663 if (TNY_IS_HEADER (header)) {
664 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
665 modest_window_mgr_unregister_header (mgr, header);
667 g_object_unref (priv->draft_msg);
668 priv->draft_msg = NULL;
670 if (priv->outbox_msg != NULL) {
671 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
672 if (TNY_IS_HEADER (header)) {
673 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
674 modest_window_mgr_unregister_header (mgr, header);
676 g_object_unref (priv->outbox_msg);
677 priv->outbox_msg = NULL;
679 if (priv->msg_uid != NULL) {
680 g_free (priv->msg_uid);
681 priv->msg_uid = NULL;
684 /* This had to stay alive for as long as the combobox that used it: */
685 modest_pair_list_free (priv->from_field_protos);
687 G_OBJECT_CLASS(parent_class)->finalize (obj);
691 menubar_to_menu (GtkUIManager *ui_manager)
693 GtkWidget *main_menu;
697 /* Create new main menu */
698 main_menu = gtk_menu_new();
700 /* Get the menubar from the UI manager */
701 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
703 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
707 menu = GTK_WIDGET (iter->data);
708 gtk_widget_reparent(menu, main_menu);
710 iter = g_list_next (iter);
716 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
718 GdkPixbufLoader *loader;
721 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
726 tny_stream_reset (TNY_STREAM (stream));
727 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
728 unsigned char read_buffer[128];
730 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
731 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
735 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
736 g_object_ref (pixbuf);
737 gdk_pixbuf_loader_close (loader, NULL);
738 g_object_unref (loader);
740 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
741 GdkPixbuf *new_pixbuf;
743 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
744 gdk_pixbuf_get_width (pixbuf);
745 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
746 g_object_unref (pixbuf);
754 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
756 ModestMsgEditWindowPrivate *priv;
759 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
761 for (node = attachments; node != NULL; node = g_list_next (node)) {
762 TnyMimePart *part = (TnyMimePart *) node->data;
763 const gchar *cid = tny_mime_part_get_content_id (part);
764 const gchar *mime_type = tny_mime_part_get_content_type (part);
765 if ((cid != NULL)&&(mime_type != NULL)) {
766 TnyStream *stream = tny_mime_part_get_stream (part);
767 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
768 g_object_unref (stream);
770 if (pixbuf != NULL) {
771 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
772 g_object_unref (pixbuf);
779 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
781 TnyMimePart *parent = NULL;
782 const gchar *content_type = NULL;
783 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
785 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
787 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
788 parent = g_object_ref (msg);
789 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
790 TnyList *parts = TNY_LIST (tny_simple_list_new ());
793 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
794 iter = tny_list_create_iterator (parts);
795 while (!tny_iterator_is_done (iter)) {
797 part = TNY_MIME_PART (tny_iterator_get_current (iter));
798 content_type = tny_mime_part_get_content_type (part);
799 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
803 g_object_unref (part);
805 tny_iterator_next (iter);
807 g_object_unref (iter);
808 g_object_unref (parts);
811 if (parent != NULL) {
812 TnyList *parts = TNY_LIST (tny_simple_list_new ());
815 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
816 iter = tny_list_create_iterator (parts);
817 while (!tny_iterator_is_done (iter)) {
819 part = TNY_MIME_PART (tny_iterator_get_current (iter));
820 content_type = tny_mime_part_get_content_type (part);
821 if (content_type && g_str_has_prefix (content_type, "image/")) {
822 priv->images = g_list_prepend (priv->images, part);
824 g_object_unref (part);
826 tny_iterator_next (iter);
828 g_object_unref (iter);
829 g_object_unref (parts);
830 g_object_unref (parent);
835 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
838 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
840 for (node = attachments; node != NULL; node = g_list_next (node)) {
841 TnyMimePart *part = (TnyMimePart *) node->data;
842 const gchar *cid = tny_mime_part_get_content_id (part);
844 char *invalid = NULL;
845 gint int_cid = strtol (cid, &invalid, 10);
846 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
847 priv->last_cid = int_cid;
855 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
858 const gchar *to, *cc, *bcc, *subject;
860 ModestMsgEditWindowPrivate *priv;
862 TnyHeaderFlags priority_flags;
863 TnyFolder *msg_folder;
864 gboolean is_html = FALSE;
866 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
867 g_return_if_fail (TNY_IS_MSG (msg));
869 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
871 header = tny_msg_get_header (msg);
872 to = tny_header_get_to (header);
873 cc = tny_header_get_cc (header);
874 bcc = tny_header_get_bcc (header);
875 subject = tny_header_get_subject (header);
876 priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
879 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
881 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
882 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
883 gtk_widget_show (priv->cc_caption);
884 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
885 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
886 gtk_widget_hide (priv->cc_caption);
889 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
890 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
891 gtk_widget_show (priv->bcc_caption);
892 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
893 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
894 gtk_widget_hide (priv->bcc_caption);
897 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
898 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
901 update_window_title (self);
903 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
904 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
906 if ((body == NULL)||(body[0] == '\0')) {
908 body = modest_text_utils_convert_to_html ("");
911 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
912 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
915 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
918 /* Add attachments to the view */
919 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
920 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
921 if (priv->attachments == NULL) {
922 gtk_widget_hide (priv->attachments_caption);
924 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
925 gtk_widget_show_all (priv->attachments_caption);
927 get_related_images (self, msg);
928 update_last_cid (self, priv->attachments);
929 update_last_cid (self, priv->images);
930 replace_with_images (self, priv->images);
932 if (preserve_is_rich && !is_html) {
933 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
934 /* Get the default format required from configuration */
935 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
936 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
939 /* Set the default focus depending on having already a To: field or not */
940 if ((!to)||(*to == '\0')) {
941 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
943 gtk_widget_grab_focus (priv->msg_body);
946 /* TODO: lower priority, select in the From: combo to the
947 value that comes from msg <- not sure, should it be
950 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
952 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
953 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
955 modest_msg_edit_window_reset_modified (self);
957 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
958 text_buffer_can_undo (priv->text_buffer, FALSE, self);
959 text_buffer_can_redo (priv->text_buffer, FALSE, self);
962 g_free (priv->msg_uid);
963 priv->msg_uid = NULL;
966 /* we should set a reference to the incoming message if it is a draft */
967 msg_folder = tny_msg_get_folder (msg);
969 if (modest_tny_folder_is_local_folder (msg_folder)) {
970 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
971 if (type == TNY_FOLDER_TYPE_DRAFTS)
972 priv->draft_msg = g_object_ref(msg);
973 if (type == TNY_FOLDER_TYPE_OUTBOX)
974 priv->outbox_msg = g_object_ref(msg);
975 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
977 g_object_unref (msg_folder);
982 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
985 GList *item_children, *node;
986 GtkWidget *bin_child;
988 bin_child = gtk_bin_get_child (GTK_BIN(item));
990 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
992 for (node = item_children; node != NULL; node = g_list_next (node)) {
993 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
994 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
997 g_list_free (item_children);
1001 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1004 GList *item_children, *node;
1006 box = gtk_bin_get_child (GTK_BIN (item));
1007 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1008 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1010 for (node = item_children; node != NULL; node = g_list_next (node)) {
1011 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1012 if (GTK_IS_TOGGLE_BUTTON (node->data))
1013 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1014 else if (GTK_IS_BUTTON (node->data))
1015 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1017 g_list_free (item_children);
1022 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1024 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1025 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1026 GtkWidget *placeholder;
1027 GtkWidget *tool_item;
1032 GtkWidget *sizes_menu;
1033 GtkWidget *fonts_menu;
1034 GSList *radio_group = NULL;
1035 GSList *node = NULL;
1039 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1040 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1042 /* Font color placeholder */
1043 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1044 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1047 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1048 priv->font_color_button = hildon_color_button_new ();
1049 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1050 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1051 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1052 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1053 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1054 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1055 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1057 G_CALLBACK (modest_msg_edit_window_color_button_change),
1060 /* Font size and face placeholder */
1061 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1062 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1064 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1065 priv->size_tool_button_label = gtk_label_new (NULL);
1066 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1067 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1068 size_text,"</span>", NULL);
1069 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1071 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1072 sizes_menu = gtk_menu_new ();
1073 priv->size_items_group = NULL;
1075 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1076 GtkWidget *size_menu_item;
1078 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1079 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1080 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1081 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1082 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1083 gtk_widget_show (size_menu_item);
1085 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1089 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1090 GtkWidget *item = (GtkWidget *) node->data;
1091 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1095 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1096 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1097 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1098 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1099 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1100 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1101 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1102 priv->font_size_toolitem = tool_item;
1105 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1106 priv->font_tool_button_label = gtk_label_new (NULL);
1107 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1108 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1110 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1111 fonts_menu = gtk_menu_new ();
1112 priv->font_items_group = NULL;
1114 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1115 GtkWidget *font_menu_item;
1116 GtkWidget *child_label;
1118 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1119 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1120 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1121 wp_get_font_name (font_index), "</span>", NULL);
1122 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1125 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1126 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1127 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1128 gtk_widget_show (font_menu_item);
1130 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1133 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1134 GtkWidget *item = (GtkWidget *) node->data;
1135 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1138 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1139 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1140 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1141 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1142 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1143 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1144 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1145 priv->font_face_toolitem = tool_item;
1147 /* Set expand and homogeneous for remaining items */
1148 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1149 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1150 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1151 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1152 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1153 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1154 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1155 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1156 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1158 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1159 will not show the tool items added to the placeholders) */
1160 gtk_widget_show_all (parent_priv->toolbar);
1162 /* Set the no show all *after* showing all items. We do not
1163 want the toolbar to be shown with a show all because it
1164 could go agains the gconf setting regarding showing or not
1165 the toolbar of the editor window */
1166 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1172 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1175 ModestWindowPrivate *parent_priv;
1176 ModestMsgEditWindowPrivate *priv;
1177 GtkActionGroup *action_group;
1178 GError *error = NULL;
1179 GdkPixbuf *window_icon = NULL;
1182 ModestPair *account_pair = NULL;
1183 ModestDimmingRulesGroup *menu_rules_group = NULL;
1184 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1185 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1187 g_return_val_if_fail (msg, NULL);
1188 g_return_val_if_fail (account_name, NULL);
1190 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1192 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1193 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1195 parent_priv->ui_manager = gtk_ui_manager_new();
1196 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1197 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1199 /* Add common actions */
1200 gtk_action_group_add_actions (action_group,
1201 modest_msg_edit_action_entries,
1202 G_N_ELEMENTS (modest_msg_edit_action_entries),
1204 gtk_action_group_add_toggle_actions (action_group,
1205 modest_msg_edit_toggle_action_entries,
1206 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1208 gtk_action_group_add_radio_actions (action_group,
1209 modest_msg_edit_alignment_radio_action_entries,
1210 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1212 G_CALLBACK (modest_ui_actions_on_change_justify),
1214 gtk_action_group_add_radio_actions (action_group,
1215 modest_msg_edit_zoom_action_entries,
1216 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1218 G_CALLBACK (modest_ui_actions_on_change_zoom),
1220 gtk_action_group_add_radio_actions (action_group,
1221 modest_msg_edit_priority_action_entries,
1222 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1224 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1226 gtk_action_group_add_radio_actions (action_group,
1227 modest_msg_edit_file_format_action_entries,
1228 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1229 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1230 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1232 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1233 g_object_unref (action_group);
1235 /* Load the UI definition */
1236 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1238 if (error != NULL) {
1239 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1240 g_clear_error (&error);
1243 /* Add accelerators */
1244 gtk_window_add_accel_group (GTK_WINDOW (obj),
1245 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1247 /* Menubar. Update the state of some toggles */
1248 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1249 conf = modest_runtime_get_conf ();
1250 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1251 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1252 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1253 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1254 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1255 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1256 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1257 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1259 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1262 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1264 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1266 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1268 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1269 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1271 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1272 if (account_pair != NULL)
1273 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1275 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1276 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1277 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1278 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1279 /* Add common dimming rules */
1280 modest_dimming_rules_group_add_rules (menu_rules_group,
1281 modest_msg_edit_window_menu_dimming_entries,
1282 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1283 MODEST_WINDOW (obj));
1284 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1285 modest_msg_edit_window_toolbar_dimming_entries,
1286 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1287 MODEST_WINDOW (obj));
1288 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1289 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1290 MODEST_WINDOW (obj));
1291 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1292 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1293 MODEST_WINDOW (obj));
1294 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1295 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1296 MODEST_WINDOW (obj));
1297 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1298 modest_msg_edit_window_clipboard_dimming_entries,
1299 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1300 MODEST_WINDOW (obj));
1301 /* Insert dimming rules group for this window */
1302 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1303 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1304 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1305 /* Checks the dimming rules */
1306 g_object_unref (menu_rules_group);
1307 g_object_unref (toolbar_rules_group);
1308 g_object_unref (clipboard_rules_group);
1310 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1312 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1314 /* Set window icon */
1315 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1317 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1318 g_object_unref (window_icon);
1321 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1322 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1324 /* Dim at start clipboard actions */
1325 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1326 gtk_action_set_sensitive (action, FALSE);
1327 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1328 gtk_action_set_sensitive (action, FALSE);
1329 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1330 gtk_action_set_sensitive (action, FALSE);
1332 /* set initial state of cc and bcc */
1333 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1334 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1335 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1336 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1337 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1338 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1340 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1341 priv->update_caption_visibility = TRUE;
1343 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1345 /* Track account-removed signal, this window should be closed
1346 in the case we're creating a mail associated to the account
1348 priv->account_removed_handler_id =
1349 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1351 G_CALLBACK(on_account_removed),
1354 return (ModestWindow*) obj;
1358 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1360 GString **string_buffer = (GString **) user_data;
1362 *string_buffer = g_string_append (*string_buffer, buffer);
1368 * @result: A new string which should be freed with g_free().
1371 get_formatted_data (ModestMsgEditWindow *edit_window)
1373 ModestMsgEditWindowPrivate *priv;
1374 GString *string_buffer = g_string_new ("");
1376 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1378 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1380 return g_string_free (string_buffer, FALSE);
1385 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1388 const gchar *account_name;
1389 ModestMsgEditWindowPrivate *priv;
1391 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1393 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1395 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1396 g_return_val_if_fail (account_name, NULL);
1399 /* don't free these (except from) */
1400 data = g_slice_new0 (MsgData);
1401 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1403 data->account_name = g_strdup (account_name);
1404 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1405 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1406 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1407 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1408 if (priv->draft_msg) {
1409 data->draft_msg = g_object_ref (priv->draft_msg);
1410 } else if (priv->outbox_msg) {
1411 data->draft_msg = g_object_ref (priv->outbox_msg);
1413 data->draft_msg = NULL;
1416 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1418 gtk_text_buffer_get_bounds (buf, &b, &e);
1419 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1421 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1422 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1424 data->html_body = NULL;
1426 /* deep-copy the data */
1427 GList *cursor = priv->attachments;
1428 data->attachments = NULL;
1430 if (!(TNY_IS_MIME_PART(cursor->data))) {
1431 g_warning ("strange data in attachment list");
1432 cursor = g_list_next (cursor);
1435 data->attachments = g_list_append (data->attachments,
1436 g_object_ref (cursor->data));
1437 cursor = g_list_next (cursor);
1440 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1441 cursor = priv->images;
1442 data->images = NULL;
1445 if (!(TNY_IS_MIME_PART(cursor->data))) {
1446 g_warning ("strange data in attachment list");
1447 cursor = g_list_next (cursor);
1450 cid = tny_mime_part_get_content_id (cursor->data);
1452 gchar *image_tag_id;
1453 GtkTextTag *image_tag;
1455 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1456 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1457 g_free (image_tag_id);
1459 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1461 ((gtk_text_iter_has_tag (&iter, image_tag))||
1462 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1463 data->images = g_list_append (data->images,
1464 g_object_ref (cursor->data));
1466 cursor = g_list_next (cursor);
1469 data->priority_flags = priv->priority_flags;
1476 unref_gobject (GObject *obj, gpointer data)
1478 if (!G_IS_OBJECT(obj))
1480 g_object_unref (obj);
1484 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1487 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1495 g_free (data->subject);
1496 g_free (data->plain_body);
1497 g_free (data->html_body);
1498 g_free (data->account_name);
1500 if (data->draft_msg != NULL) {
1501 g_object_unref (data->draft_msg);
1502 data->draft_msg = NULL;
1505 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1506 g_list_free (data->attachments);
1507 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1508 g_list_free (data->images);
1510 g_slice_free (MsgData, data);
1514 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1517 ModestMsgEditWindowPrivate *priv = NULL;
1518 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1520 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1522 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1524 return MODEST_MSG_EDIT_FORMAT_HTML;
1526 return MODEST_MSG_EDIT_FORMAT_TEXT;
1530 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1531 ModestMsgEditFormat format)
1533 ModestMsgEditWindowPrivate *priv;
1535 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1536 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1539 case MODEST_MSG_EDIT_FORMAT_HTML:
1540 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1542 case MODEST_MSG_EDIT_FORMAT_TEXT:
1543 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1546 g_return_if_reached ();
1550 ModestMsgEditFormatState *
1551 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1553 ModestMsgEditFormatState *format_state = NULL;
1554 ModestMsgEditWindowPrivate *priv;
1555 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1557 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1558 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1560 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1562 format_state = g_new0 (ModestMsgEditFormatState, 1);
1563 format_state->bold = buffer_format->bold&0x1;
1564 format_state->italics = buffer_format->italic&0x1;
1565 format_state->bullet = buffer_format->bullet&0x1;
1566 format_state->color = buffer_format->color;
1567 format_state->font_size = buffer_format->font_size;
1568 format_state->font_family = wp_get_font_name (buffer_format->font);
1569 format_state->justification = buffer_format->justification;
1570 g_free (buffer_format);
1572 return format_state;
1577 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1578 const ModestMsgEditFormatState *format_state)
1580 ModestMsgEditWindowPrivate *priv;
1581 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1582 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1583 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1584 g_return_if_fail (format_state != NULL);
1586 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1587 gtk_widget_grab_focus (priv->msg_body);
1588 buffer_format->bold = (format_state->bold != FALSE);
1589 buffer_format->italic = (format_state->italics != FALSE);
1590 buffer_format->color = format_state->color;
1591 buffer_format->font_size = format_state->font_size;
1592 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1593 buffer_format->justification = format_state->justification;
1594 buffer_format->bullet = format_state->bullet;
1596 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1598 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1599 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1600 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1601 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1602 buffer_format->cs.font = (buffer_format->font != current_format->font);
1603 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1604 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1606 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1607 if (buffer_format->cs.bold) {
1608 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1610 if (buffer_format->cs.italic) {
1611 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1613 if (buffer_format->cs.color) {
1614 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1616 if (buffer_format->cs.font_size) {
1617 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1619 if (buffer_format->cs.justification) {
1620 switch (buffer_format->justification) {
1621 case GTK_JUSTIFY_LEFT:
1622 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1624 case GTK_JUSTIFY_CENTER:
1625 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1627 case GTK_JUSTIFY_RIGHT:
1628 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1635 if (buffer_format->cs.font) {
1636 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1638 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1639 if (buffer_format->cs.bullet) {
1640 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1642 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1644 g_free (current_format);
1649 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1651 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1653 ModestWindowPrivate *parent_priv;
1654 ModestMsgEditWindowPrivate *priv;
1655 GtkWidget *new_size_menuitem;
1656 GtkWidget *new_font_menuitem;
1658 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1659 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1661 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1662 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1663 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1664 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1666 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1667 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1668 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1671 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1673 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1674 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1676 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1677 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1679 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1680 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1682 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1683 G_CALLBACK (modest_msg_edit_window_color_button_change),
1685 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1686 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1687 G_CALLBACK (modest_msg_edit_window_color_button_change),
1690 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1691 buffer_format->font_size))->data);
1692 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1696 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1697 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1698 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1700 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1701 G_CALLBACK (modest_msg_edit_window_size_change),
1703 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1704 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1705 G_CALLBACK (modest_msg_edit_window_size_change),
1709 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1710 buffer_format->font))->data);
1711 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1715 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1716 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1717 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1719 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1720 G_CALLBACK (modest_msg_edit_window_font_change),
1722 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1723 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1724 G_CALLBACK (modest_msg_edit_window_font_change),
1728 g_free (buffer_format);
1734 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1737 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1738 ModestMsgEditWindowPrivate *priv;
1739 GtkWidget *dialog = NULL;
1741 const GdkColor *new_color = NULL;
1743 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1744 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1746 #ifdef MODEST_HILDON_VERSION_0
1747 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1748 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1750 dialog = hildon_color_chooser_new ();
1751 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1752 #endif /*MODEST_HILDON_VERSION_0*/
1753 g_free (buffer_format);
1755 response = gtk_dialog_run (GTK_DIALOG (dialog));
1757 case GTK_RESPONSE_OK: {
1758 #ifdef MODEST_HILDON_VERSION_0
1759 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1762 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1764 #endif /*MODEST_HILDON_VERSION_0*/
1771 gtk_widget_destroy (dialog);
1773 if (new_color != NULL)
1774 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1779 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1782 ModestMsgEditWindowPrivate *priv;
1783 GtkWidget *dialog = NULL;
1785 GdkColor *old_color = NULL;
1786 const GdkColor *new_color = NULL;
1788 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1789 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1791 #ifdef MODEST_HILDON_VERSION_0
1792 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1793 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1795 dialog = hildon_color_chooser_new ();
1796 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1797 #endif /*MODEST_HILDON_VERSION_9*/
1799 response = gtk_dialog_run (GTK_DIALOG (dialog));
1801 case GTK_RESPONSE_OK: {
1802 #ifdef MODEST_HILDON_VERSION_0
1803 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1806 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1808 #endif /*MODEST_HILDON_VERSION_0*/
1814 gtk_widget_destroy (dialog);
1816 if (new_color != NULL)
1817 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1821 static TnyStream* create_stream_for_uri (const gchar* uri)
1826 TnyStream *result = NULL;
1828 GnomeVFSHandle *handle = NULL;
1829 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1830 if (test == GNOME_VFS_OK) {
1831 /* Create the tinymail stream: */
1832 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1833 result = TNY_STREAM (tny_vfs_stream_new (handle));
1840 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1843 ModestMsgEditWindowPrivate *priv;
1844 GtkWidget *dialog = NULL;
1846 GSList *uris = NULL;
1847 GSList *uri_node = NULL;
1849 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1851 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1852 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1853 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1855 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1857 response = gtk_dialog_run (GTK_DIALOG (dialog));
1859 case GTK_RESPONSE_OK:
1860 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1865 gtk_widget_destroy (dialog);
1867 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1869 GnomeVFSHandle *handle = NULL;
1870 GnomeVFSResult result;
1871 GtkTextIter position;
1872 GtkTextMark *insert_mark;
1874 uri = (const gchar *) uri_node->data;
1875 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1876 if (result == GNOME_VFS_OK) {
1878 GnomeVFSFileInfo info;
1879 gchar *filename, *basename, *escaped_filename;
1880 TnyMimePart *mime_part;
1882 const gchar *mime_type = NULL;
1883 GnomeVFSURI *vfs_uri;
1885 vfs_uri = gnome_vfs_uri_new (uri);
1887 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1888 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1889 g_free (escaped_filename);
1890 gnome_vfs_uri_unref (vfs_uri);
1892 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1893 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1895 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1897 mime_part = tny_platform_factory_new_mime_part
1898 (modest_runtime_get_platform_factory ());
1900 TnyStream *stream = create_stream_for_uri (uri);
1901 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1903 content_id = g_strdup_printf ("%d", priv->last_cid);
1904 tny_mime_part_set_content_id (mime_part, content_id);
1905 g_free (content_id);
1908 basename = g_path_get_basename (filename);
1909 tny_mime_part_set_filename (mime_part, basename);
1912 pixbuf = pixbuf_from_stream (stream, mime_type);
1914 if (pixbuf != NULL) {
1915 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1916 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1917 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1920 priv->images = g_list_prepend (priv->images, mime_part);
1921 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1931 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1934 ModestMsgEditWindowPrivate *priv;
1935 GtkWidget *dialog = NULL;
1937 GSList *uris = NULL;
1940 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1942 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1943 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1944 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1946 response = gtk_dialog_run (GTK_DIALOG (dialog));
1948 case GTK_RESPONSE_OK:
1949 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1954 gtk_widget_destroy (dialog);
1956 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1957 const gchar *uri = (const gchar *) uri_node->data;
1958 modest_msg_edit_window_attach_file_one (window, uri);
1960 g_slist_foreach (uris, (GFunc) g_free, NULL);
1961 g_slist_free (uris);
1965 modest_msg_edit_window_attach_file_one (
1966 ModestMsgEditWindow *window,
1969 g_return_if_fail (window);
1970 g_return_if_fail (uri);
1972 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1975 GnomeVFSHandle *handle = NULL;
1976 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1977 if (result == GNOME_VFS_OK) {
1978 TnyMimePart *mime_part;
1980 const gchar *mime_type = NULL;
1982 gchar *escaped_filename;
1985 GnomeVFSFileInfo info;
1986 GnomeVFSURI *vfs_uri;
1988 vfs_uri = gnome_vfs_uri_new (uri);
1991 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1992 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1993 g_free (escaped_filename);
1994 gnome_vfs_uri_unref (vfs_uri);
1996 if (gnome_vfs_get_file_info (uri,
1998 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1999 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2001 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2002 mime_part = tny_platform_factory_new_mime_part
2003 (modest_runtime_get_platform_factory ());
2004 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2006 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2008 content_id = g_strdup_printf ("%d", priv->last_cid);
2009 tny_mime_part_set_content_id (mime_part, content_id);
2010 g_free (content_id);
2013 basename = g_path_get_basename (filename);
2014 tny_mime_part_set_filename (mime_part, basename);
2017 priv->attachments = g_list_prepend (priv->attachments, mime_part);
2018 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2020 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2021 gtk_widget_show_all (priv->attachments_caption);
2022 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2028 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2031 ModestMsgEditWindowPrivate *priv;
2032 gboolean clean_list = FALSE;
2034 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2035 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2037 if (att_list == NULL) {
2038 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2042 if (att_list == NULL) {
2043 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2045 GtkWidget *confirmation_dialog = NULL;
2046 gboolean dialog_response;
2048 gchar *message = NULL;
2049 gchar *filename = NULL;
2051 if (att_list->next == NULL) {
2052 if (TNY_IS_MSG (att_list->data)) {
2053 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2055 filename = g_strdup (tny_header_get_subject (header));
2056 g_object_unref (header);
2058 if (filename == NULL) {
2059 filename = g_strdup (_("mail_va_no_subject"));
2062 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2065 filename = g_strdup ("");
2067 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2068 att_list->next == NULL), filename);
2070 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2072 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2073 gtk_widget_destroy (confirmation_dialog);
2074 if (!dialog_response) {
2076 g_list_free (att_list);
2079 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2081 for (node = att_list; node != NULL; node = g_list_next (node)) {
2082 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2083 const gchar *att_id;
2084 priv->attachments = g_list_remove (priv->attachments, mime_part);
2086 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2088 if (priv->attachments == NULL)
2089 gtk_widget_hide (priv->attachments_caption);
2090 att_id = tny_mime_part_get_content_id (mime_part);
2092 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2094 g_object_unref (mime_part);
2095 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2100 g_list_free (att_list);
2104 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2107 ModestMsgEditWindowPrivate *priv;
2108 GdkColor *new_color;
2109 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2111 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2112 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2115 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2117 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2119 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2121 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2126 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2129 ModestMsgEditWindowPrivate *priv;
2130 gint new_size_index;
2131 ModestMsgEditWindow *window;
2134 window = MODEST_MSG_EDIT_WINDOW (userdata);
2135 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2136 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2138 if (gtk_check_menu_item_get_active (menu_item)) {
2140 WPTextBufferFormat format;
2142 memset (&format, 0, sizeof (format));
2143 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2145 label = gtk_bin_get_child (GTK_BIN (menu_item));
2147 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2148 format.cs.font_size = TRUE;
2149 format.cs.text_position = TRUE;
2150 format.cs.font = TRUE;
2151 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2152 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2154 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2155 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2156 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2158 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2159 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2160 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2166 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2169 ModestMsgEditWindowPrivate *priv;
2170 gint new_font_index;
2171 ModestMsgEditWindow *window;
2174 window = MODEST_MSG_EDIT_WINDOW (userdata);
2175 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2176 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2178 if (gtk_check_menu_item_get_active (menu_item)) {
2181 label = gtk_bin_get_child (GTK_BIN (menu_item));
2183 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2185 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2186 (gpointer) new_font_index))
2187 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2189 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2190 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2191 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2197 modest_msg_edit_window_set_zoom (ModestWindow *window,
2200 ModestMsgEditWindowPrivate *priv;
2201 ModestWindowPrivate *parent_priv;
2202 GtkRadioAction *zoom_radio_action;
2204 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2206 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2207 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2208 priv->zoom_level = zoom;
2209 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2211 /* Zoom level menu options should be updated with the current zoom level */
2212 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2213 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2214 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2215 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2216 /* FIXME: Not availible before Gtk 2.10 */
2218 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2223 modest_msg_edit_window_get_zoom (ModestWindow *window)
2225 ModestMsgEditWindowPrivate *priv;
2227 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2229 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2230 return priv->zoom_level;
2234 zoom_allowed (ModestMsgEditWindow *window)
2238 focus = gtk_window_get_focus (GTK_WINDOW (window));
2239 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2243 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2245 ModestWindowPrivate *parent_priv;
2246 GtkRadioAction *zoom_radio_action;
2247 GSList *group, *node;
2249 /* First we check if the text view is focused. If not, zooming is not allowed */
2250 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2251 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2255 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2256 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2257 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2259 group = gtk_radio_action_get_group (zoom_radio_action);
2261 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2262 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2266 for (node = group; node != NULL; node = g_slist_next (node)) {
2267 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2268 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2276 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2278 ModestWindowPrivate *parent_priv;
2279 GtkRadioAction *zoom_radio_action;
2280 GSList *group, *node;
2282 /* First we check if the text view is focused. If not, zooming is not allowed */
2283 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2284 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2288 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2289 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2290 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2292 group = gtk_radio_action_get_group (zoom_radio_action);
2294 for (node = group; node != NULL; node = g_slist_next (node)) {
2295 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2296 if (node->next != NULL) {
2297 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2300 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2308 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2310 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2311 ModestWindowPrivate *parent_priv;
2312 ModestWindowMgr *mgr;
2313 gboolean is_fullscreen;
2314 GtkAction *fs_toggle_action;
2317 mgr = modest_runtime_get_window_mgr ();
2318 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2320 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2322 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2323 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2324 if (is_fullscreen != active)
2325 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2333 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2336 ModestMsgEditWindowPrivate *priv = NULL;
2337 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2339 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2340 if (!priv->update_caption_visibility)
2343 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2345 gtk_widget_show (priv->cc_caption);
2347 gtk_widget_hide (priv->cc_caption);
2349 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2353 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2356 ModestMsgEditWindowPrivate *priv = NULL;
2357 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2359 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2360 if (!priv->update_caption_visibility)
2363 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2365 gtk_widget_show (priv->bcc_caption);
2367 gtk_widget_hide (priv->bcc_caption);
2369 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2373 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2374 ModestRecptEditor *editor)
2376 ModestMsgEditWindowPrivate *priv;
2378 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2379 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2380 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2382 if (editor == NULL) {
2383 GtkWidget *view_focus;
2384 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2386 /* This code should be kept in sync with ModestRecptEditor. The
2387 textview inside the recpt editor is the one that really gets the
2388 focus. As it's inside a scrolled window, and this one inside the
2389 hbox recpt editor inherits from, we'll need to go up in the
2390 hierarchy to know if the text view is part of the recpt editor
2391 or if it's a different text entry */
2393 if (gtk_widget_get_parent (view_focus)) {
2394 GtkWidget *first_parent;
2396 first_parent = gtk_widget_get_parent (view_focus);
2397 if (gtk_widget_get_parent (first_parent) &&
2398 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2399 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2404 editor = MODEST_RECPT_EDITOR (priv->to_field);
2408 modest_address_book_select_addresses (editor);
2413 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2415 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2417 modest_msg_edit_window_open_addressbook (window, NULL);
2421 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2422 gboolean show_toolbar)
2424 ModestWindowPrivate *parent_priv;
2425 const gchar *action_name;
2428 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2429 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2431 /* We can not just use the code of
2432 modest_msg_edit_window_setup_toolbar because it has a
2433 mixture of both initialization and creation code. */
2435 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2437 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2439 /* Update also the actions (to update the toggles in the
2440 menus), we have to do it manually because some other window
2441 of the same time could have changed it (remember that the
2442 toolbar fullscreen mode is shared by all the windows of the
2444 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2445 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2447 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2449 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2450 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2456 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2457 TnyHeaderFlags priority_flags)
2459 ModestMsgEditWindowPrivate *priv;
2460 ModestWindowPrivate *parent_priv;
2462 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2464 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2465 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2466 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2468 if (priv->priority_flags != priority_flags) {
2469 GtkAction *priority_action = NULL;
2471 priv->priority_flags = priority_flags;
2473 switch (priority_flags) {
2474 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2475 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2476 gtk_widget_show (priv->priority_icon);
2477 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2478 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2480 case TNY_HEADER_FLAG_LOW_PRIORITY:
2481 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2482 gtk_widget_show (priv->priority_icon);
2483 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2484 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2487 gtk_widget_hide (priv->priority_icon);
2488 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2489 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2492 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2493 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2498 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2501 ModestMsgEditWindowPrivate *priv;
2502 ModestWindowPrivate *parent_priv;
2503 gint current_format;
2505 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2507 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2508 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2510 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2511 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2513 if (current_format != file_format) {
2514 switch (file_format) {
2515 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2516 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2517 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2519 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2523 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2524 response = gtk_dialog_run (GTK_DIALOG (dialog));
2525 gtk_widget_destroy (dialog);
2526 if (response == GTK_RESPONSE_OK) {
2527 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2529 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2530 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2535 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2540 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2543 ModestMsgEditWindowPrivate *priv;
2544 WPTextBufferFormat oldfmt, fmt;
2545 gint old_position = 0;
2549 GdkColor *color = NULL;
2550 gboolean bold, bold_set, italic, italic_set;
2551 gboolean underline, underline_set;
2552 gboolean strikethrough, strikethrough_set;
2553 gboolean position_set;
2554 gboolean font_size_set, font_set, color_set;
2557 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2558 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2560 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2562 /* First we get the currently selected font information */
2563 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2564 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2566 switch (oldfmt.text_position) {
2567 case TEXT_POSITION_NORMAL:
2570 case TEXT_POSITION_SUPERSCRIPT:
2578 g_object_set (G_OBJECT (dialog),
2579 "bold", oldfmt.bold != FALSE,
2580 "bold-set", !oldfmt.cs.bold,
2581 "underline", oldfmt.underline != FALSE,
2582 "underline-set", !oldfmt.cs.underline,
2583 "italic", oldfmt.italic != FALSE,
2584 "italic-set", !oldfmt.cs.italic,
2585 "strikethrough", oldfmt.strikethrough != FALSE,
2586 "strikethrough-set", !oldfmt.cs.strikethrough,
2587 "color", &oldfmt.color,
2588 "color-set", !oldfmt.cs.color,
2589 "size", wp_font_size[oldfmt.font_size],
2590 "size-set", !oldfmt.cs.font_size,
2591 "position", old_position,
2592 "position-set", !oldfmt.cs.text_position,
2593 "family", wp_get_font_name (oldfmt.font),
2594 "family-set", !oldfmt.cs.font,
2597 gtk_widget_show_all (dialog);
2598 response = gtk_dialog_run (GTK_DIALOG (dialog));
2599 if (response == GTK_RESPONSE_OK) {
2601 g_object_get( dialog,
2603 "bold-set", &bold_set,
2604 "underline", &underline,
2605 "underline-set", &underline_set,
2607 "italic-set", &italic_set,
2608 "strikethrough", &strikethrough,
2609 "strikethrough-set", &strikethrough_set,
2611 "color-set", &color_set,
2613 "size-set", &font_size_set,
2614 "family", &font_name,
2615 "family-set", &font_set,
2616 "position", &position,
2617 "position-set", &position_set,
2622 if (response == GTK_RESPONSE_OK) {
2623 memset(&fmt, 0, sizeof(fmt));
2629 fmt.italic = italic;
2630 fmt.cs.italic = TRUE;
2632 if (underline_set) {
2633 fmt.underline = underline;
2634 fmt.cs.underline = TRUE;
2636 if (strikethrough_set) {
2637 fmt.strikethrough = strikethrough;
2638 fmt.cs.strikethrough = TRUE;
2643 ? TEXT_POSITION_NORMAL
2644 : ( ( position == 1 )
2645 ? TEXT_POSITION_SUPERSCRIPT
2646 : TEXT_POSITION_SUBSCRIPT );
2647 fmt.cs.text_position = TRUE;
2651 fmt.cs.color = TRUE;
2654 fmt.font = wp_get_font_index(font_name,
2659 if (font_size_set) {
2660 fmt.font_size = wp_get_font_size_index(
2661 font_size, DEFAULT_FONT_SIZE);
2662 fmt.cs.font_size = TRUE;
2664 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2665 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2667 gtk_widget_destroy (dialog);
2669 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2673 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2675 ModestMsgEditWindowPrivate *priv;
2677 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2678 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2680 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2682 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2687 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2689 ModestMsgEditWindowPrivate *priv;
2691 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2692 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2694 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2696 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2701 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2703 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2705 priv->can_undo = can_undo;
2709 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2711 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2713 priv->can_redo = can_redo;
2717 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2719 ModestMsgEditWindowPrivate *priv;
2720 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2721 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2723 return priv->can_undo;
2727 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2729 ModestMsgEditWindowPrivate *priv;
2730 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2731 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2733 return priv->can_redo;
2738 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2741 GtkTextIter match_start, match_end;
2743 if (image_id == NULL)
2746 gtk_text_buffer_get_start_iter (buffer, &iter);
2748 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2749 GSList *tags = gtk_text_iter_get_tags (&match_start);
2751 for (node = tags; node != NULL; node = g_slist_next (node)) {
2752 GtkTextTag *tag = (GtkTextTag *) node->data;
2753 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2754 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2755 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2757 offset = gtk_text_iter_get_offset (&match_start);
2758 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2759 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2763 gtk_text_iter_forward_char (&iter);
2768 message_is_empty (ModestMsgEditWindow *window)
2770 ModestMsgEditWindowPrivate *priv = NULL;
2772 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2773 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2775 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2776 * so we can ignore markup.
2778 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2781 count = gtk_text_buffer_get_char_count (buf);
2787 msg_body_focus (GtkWidget *focus,
2788 GdkEventFocus *event,
2792 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2797 recpt_field_changed (GtkTextBuffer *buffer,
2798 ModestMsgEditWindow *editor)
2800 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2804 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2806 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2810 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2812 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2813 GtkTextBuffer *buffer;
2815 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2816 gtk_text_buffer_set_modified (buffer, FALSE);
2817 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2818 gtk_text_buffer_set_modified (buffer, FALSE);
2819 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2820 gtk_text_buffer_set_modified (buffer, FALSE);
2821 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2825 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2827 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2828 GtkTextBuffer *buffer;
2830 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2831 if (gtk_text_buffer_get_modified (buffer))
2833 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2834 if (gtk_text_buffer_get_modified (buffer))
2836 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2837 if (gtk_text_buffer_get_modified (buffer))
2839 if (gtk_text_buffer_get_modified (priv->text_buffer))
2849 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2851 ModestMsgEditWindowPrivate *priv = NULL;
2853 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2854 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2856 /* check if there's no recipient added */
2857 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2858 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2859 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2860 /* no recipient contents, then select contacts */
2861 modest_msg_edit_window_open_addressbook (window, NULL);
2865 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2866 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2869 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2870 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2873 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2874 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2878 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2879 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2880 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2887 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2888 ModestMsgEditWindow *window)
2890 modest_msg_edit_window_offer_attach_file (window);
2894 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2896 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2898 return priv->clipboard_text;
2902 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2904 ModestMsgEditWindow *window)
2906 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2907 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2909 if (!GTK_WIDGET_VISIBLE (window))
2912 text = gtk_clipboard_wait_for_text (selection_clipboard);
2914 if (priv->clipboard_text != NULL) {
2915 g_free (priv->clipboard_text);
2917 priv->clipboard_text = text;
2919 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2922 subject_field_move_cursor (GtkEntry *entry,
2923 GtkMovementStep step,
2928 if (!GTK_WIDGET_VISIBLE (window))
2931 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2935 update_window_title (ModestMsgEditWindow *window)
2937 ModestMsgEditWindowPrivate *priv = NULL;
2938 const gchar *subject;
2940 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2941 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2942 if (subject == NULL || subject[0] == '\0')
2943 subject = _("mail_va_new_email");
2945 gtk_window_set_title (GTK_WINDOW (window), subject);
2950 subject_field_changed (GtkEditable *editable,
2951 ModestMsgEditWindow *window)
2953 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2954 update_window_title (window);
2955 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2956 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2960 subject_field_insert_text (GtkEditable *editable,
2962 gint new_text_length,
2964 ModestMsgEditWindow *window)
2966 GString *result = g_string_new ("");
2968 gint result_len = 0;
2969 const gchar *entry_text = NULL;
2972 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2973 old_length = g_utf8_strlen (entry_text, -1);
2975 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2976 gunichar c = g_utf8_get_char_validated (current, 8);
2977 /* Invalid unichar, stop */
2983 result = g_string_append_unichar (result, c);
2987 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2988 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2991 /* Prevent endless recursion */
2992 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2993 g_signal_emit_by_name (editable, "insert-text",
2994 (gpointer) result->str, (gpointer) result->len,
2995 (gpointer) position, (gpointer) window);
2996 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3000 if (result_len + old_length > 1000) {
3001 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3002 dgettext("hildon-common-strings",
3003 "ckdg_ib_maximum_characters_reached"));
3006 g_string_free (result, TRUE);
3010 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3013 ModestMsgEditWindowPrivate *priv = NULL;
3015 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3016 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3018 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3021 gtk_widget_show_all (priv->find_toolbar);
3022 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3024 gtk_widget_hide_all (priv->find_toolbar);
3025 gtk_widget_grab_focus (priv->msg_body);
3031 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3033 GtkTextIter *match_start,
3034 GtkTextIter *match_end)
3036 GtkTextIter end_iter;
3037 gchar *str_casefold;
3040 gchar *range_casefold;
3043 gboolean result = FALSE;
3050 gtk_text_iter_forward_to_end (&end_iter);
3052 str_casefold = g_utf8_casefold (str, -1);
3053 str_chars_n = strlen (str);
3055 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3056 range_casefold = g_utf8_casefold (range_text, -1);
3057 range_chars_n = strlen (range_casefold);
3059 if (range_chars_n < str_chars_n) {
3060 g_free (str_casefold);
3061 g_free (range_text);
3062 g_free (range_casefold);
3066 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3067 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3068 if (!g_utf8_collate (range_subtext, str_casefold)) {
3069 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3071 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3072 match_start, match_end, NULL);
3073 g_free (found_text);
3075 g_free (range_subtext);
3079 g_free (str_casefold);
3080 g_free (range_text);
3081 g_free (range_casefold);
3088 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3089 ModestMsgEditWindow *window)
3091 gchar *current_search = NULL;
3092 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3094 GtkTextIter selection_start, selection_end;
3095 GtkTextIter match_start, match_end;
3096 gboolean continue_search = FALSE;
3098 if (message_is_empty (window)) {
3099 g_free (priv->last_search);
3100 priv->last_search = NULL;
3101 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3105 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3106 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3107 g_free (current_search);
3108 g_free (priv->last_search);
3109 priv->last_search = NULL;
3110 /* Information banner about empty search */
3111 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3115 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3116 continue_search = TRUE;
3118 g_free (priv->last_search);
3119 priv->last_search = g_strdup (current_search);
3122 if (continue_search) {
3123 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3124 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3125 &match_start, &match_end);
3127 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3129 GtkTextIter buffer_start;
3130 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3131 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3132 &match_start, &match_end);
3134 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3137 /* Mark as selected the string found in search */
3139 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3140 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3142 g_free (priv->last_search);
3143 priv->last_search = NULL;
3145 g_free (current_search);
3149 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3150 ModestMsgEditWindow *window)
3152 GtkToggleAction *toggle;
3153 ModestWindowPrivate *parent_priv;
3154 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3156 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3157 gtk_toggle_action_set_active (toggle, FALSE);
3161 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3163 ModestMsgEditWindowPrivate *priv;
3165 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3170 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3173 ModestMsgEditWindowPrivate *priv;
3175 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3181 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3184 ModestMsgEditWindowPrivate *priv;
3185 TnyHeader *header = NULL;
3187 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3188 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3190 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3191 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3193 if (priv->draft_msg != NULL) {
3194 header = tny_msg_get_header (priv->draft_msg);
3195 if (TNY_IS_HEADER (header)) {
3196 modest_window_mgr_unregister_header (mgr, header);
3198 g_object_unref (priv->draft_msg);
3201 if (draft != NULL) {
3202 g_object_ref (draft);
3203 header = tny_msg_get_header (draft);
3204 if (TNY_IS_HEADER (header))
3205 modest_window_mgr_register_header (mgr, header);
3206 if (priv->msg_uid) {
3207 g_free (priv->msg_uid);
3208 priv->msg_uid = NULL;
3210 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3213 priv->draft_msg = draft;
3217 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3218 GtkTextIter *start, GtkTextIter *end,
3221 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3222 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3225 if (tag == NULL+13) return;
3226 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3227 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3228 replace_with_images (window, priv->images);
3233 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3236 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3238 g_return_if_fail (TNY_IS_MIME_PART (part));
3239 priv->attachments = g_list_prepend (priv->attachments, part);
3240 g_object_ref (part);
3241 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3242 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3243 gtk_widget_show_all (priv->attachments_caption);
3244 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3248 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3250 ModestMsgEditWindowPrivate *priv;
3252 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3253 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3255 return priv->msg_uid;
3259 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3260 ModestMsgEditWindowWidgetType widget_type)
3262 ModestMsgEditWindowPrivate *priv;
3264 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3265 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3267 switch (widget_type) {
3268 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3269 return priv->msg_body;
3271 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3272 return priv->to_field;
3274 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3275 return priv->cc_field;
3277 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3278 return priv->bcc_field;
3280 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3281 return priv->subject_field;
3283 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3284 return priv->attachments_view;
3292 remove_tags (WPTextBuffer *buffer)
3294 GtkTextIter start, end;
3296 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3297 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3299 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3303 on_account_removed (TnyAccountStore *account_store,
3304 TnyAccount *account,
3307 /* Do nothing if it's a store account, because we use the
3308 transport to send the messages */
3309 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3310 const gchar *parent_acc = NULL;
3311 const gchar *our_acc = NULL;
3313 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3314 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3315 /* Close this window if I'm showing a message of the removed account */
3316 if (strcmp (parent_acc, our_acc) == 0)
3317 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));