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_priority (header);
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_INVALID)
972 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
974 if (type == TNY_FOLDER_TYPE_DRAFTS)
975 priv->draft_msg = g_object_ref(msg);
976 if (type == TNY_FOLDER_TYPE_OUTBOX)
977 priv->outbox_msg = g_object_ref(msg);
978 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
980 g_object_unref (msg_folder);
985 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
988 GList *item_children, *node;
989 GtkWidget *bin_child;
991 bin_child = gtk_bin_get_child (GTK_BIN(item));
993 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
995 for (node = item_children; node != NULL; node = g_list_next (node)) {
996 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
997 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1000 g_list_free (item_children);
1004 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1007 GList *item_children, *node;
1009 box = gtk_bin_get_child (GTK_BIN (item));
1010 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1011 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1013 for (node = item_children; node != NULL; node = g_list_next (node)) {
1014 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1015 if (GTK_IS_TOGGLE_BUTTON (node->data))
1016 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1017 else if (GTK_IS_BUTTON (node->data))
1018 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1020 g_list_free (item_children);
1025 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1027 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1028 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1029 GtkWidget *placeholder;
1030 GtkWidget *tool_item;
1035 GtkWidget *sizes_menu;
1036 GtkWidget *fonts_menu;
1037 GSList *radio_group = NULL;
1038 GSList *node = NULL;
1042 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1043 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1045 /* Font color placeholder */
1046 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1047 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1050 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1051 priv->font_color_button = hildon_color_button_new ();
1052 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1053 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1054 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1055 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1056 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1057 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1058 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1060 G_CALLBACK (modest_msg_edit_window_color_button_change),
1063 /* Font size and face placeholder */
1064 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1065 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1067 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1068 priv->size_tool_button_label = gtk_label_new (NULL);
1069 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1070 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1071 size_text,"</span>", NULL);
1072 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1074 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1075 sizes_menu = gtk_menu_new ();
1076 priv->size_items_group = NULL;
1078 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1079 GtkWidget *size_menu_item;
1081 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1082 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1083 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1084 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1085 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1086 gtk_widget_show (size_menu_item);
1088 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1092 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1093 GtkWidget *item = (GtkWidget *) node->data;
1094 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1098 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1099 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1100 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1101 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1102 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1103 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1104 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1105 priv->font_size_toolitem = tool_item;
1108 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1109 priv->font_tool_button_label = gtk_label_new (NULL);
1110 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1111 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1113 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1114 fonts_menu = gtk_menu_new ();
1115 priv->font_items_group = NULL;
1117 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1118 GtkWidget *font_menu_item;
1119 GtkWidget *child_label;
1121 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1122 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1123 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1124 wp_get_font_name (font_index), "</span>", NULL);
1125 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1128 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1129 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1130 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1131 gtk_widget_show (font_menu_item);
1133 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1136 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1137 GtkWidget *item = (GtkWidget *) node->data;
1138 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1141 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1142 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1143 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1144 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1145 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1146 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1147 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1148 priv->font_face_toolitem = tool_item;
1150 /* Set expand and homogeneous for remaining items */
1151 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
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/ActionsBold");
1155 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1156 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1157 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1158 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1159 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1161 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1162 will not show the tool items added to the placeholders) */
1163 gtk_widget_show_all (parent_priv->toolbar);
1165 /* Set the no show all *after* showing all items. We do not
1166 want the toolbar to be shown with a show all because it
1167 could go agains the gconf setting regarding showing or not
1168 the toolbar of the editor window */
1169 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1175 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1178 ModestWindowPrivate *parent_priv;
1179 ModestMsgEditWindowPrivate *priv;
1180 GtkActionGroup *action_group;
1181 GError *error = NULL;
1182 GdkPixbuf *window_icon = NULL;
1185 ModestPair *account_pair = NULL;
1186 ModestDimmingRulesGroup *menu_rules_group = NULL;
1187 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1188 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1190 g_return_val_if_fail (msg, NULL);
1191 g_return_val_if_fail (account_name, NULL);
1193 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1195 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1196 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1198 parent_priv->ui_manager = gtk_ui_manager_new();
1199 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1200 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1202 /* Add common actions */
1203 gtk_action_group_add_actions (action_group,
1204 modest_msg_edit_action_entries,
1205 G_N_ELEMENTS (modest_msg_edit_action_entries),
1207 gtk_action_group_add_toggle_actions (action_group,
1208 modest_msg_edit_toggle_action_entries,
1209 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1211 gtk_action_group_add_radio_actions (action_group,
1212 modest_msg_edit_alignment_radio_action_entries,
1213 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1215 G_CALLBACK (modest_ui_actions_on_change_justify),
1217 gtk_action_group_add_radio_actions (action_group,
1218 modest_msg_edit_zoom_action_entries,
1219 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1221 G_CALLBACK (modest_ui_actions_on_change_zoom),
1223 gtk_action_group_add_radio_actions (action_group,
1224 modest_msg_edit_priority_action_entries,
1225 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1227 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1229 gtk_action_group_add_radio_actions (action_group,
1230 modest_msg_edit_file_format_action_entries,
1231 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1232 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1233 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1235 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1236 g_object_unref (action_group);
1238 /* Load the UI definition */
1239 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1241 if (error != NULL) {
1242 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1243 g_clear_error (&error);
1246 /* Add accelerators */
1247 gtk_window_add_accel_group (GTK_WINDOW (obj),
1248 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1250 /* Menubar. Update the state of some toggles */
1251 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1252 conf = modest_runtime_get_conf ();
1253 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1254 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1255 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1256 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1257 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1258 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1259 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1260 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1262 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1265 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1267 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1269 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1271 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1272 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1274 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1275 if (account_pair != NULL)
1276 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1278 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1279 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1280 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1281 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1282 /* Add common dimming rules */
1283 modest_dimming_rules_group_add_rules (menu_rules_group,
1284 modest_msg_edit_window_menu_dimming_entries,
1285 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1286 MODEST_WINDOW (obj));
1287 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1288 modest_msg_edit_window_toolbar_dimming_entries,
1289 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1290 MODEST_WINDOW (obj));
1291 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
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_size_toolitem,
1295 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1296 MODEST_WINDOW (obj));
1297 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1298 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1299 MODEST_WINDOW (obj));
1300 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1301 modest_msg_edit_window_clipboard_dimming_entries,
1302 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1303 MODEST_WINDOW (obj));
1304 /* Insert dimming rules group for this window */
1305 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1306 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1307 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1308 /* Checks the dimming rules */
1309 g_object_unref (menu_rules_group);
1310 g_object_unref (toolbar_rules_group);
1311 g_object_unref (clipboard_rules_group);
1313 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1315 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1317 /* Set window icon */
1318 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1320 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1321 g_object_unref (window_icon);
1324 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1325 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1327 /* Dim at start clipboard actions */
1328 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1329 gtk_action_set_sensitive (action, FALSE);
1330 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1331 gtk_action_set_sensitive (action, FALSE);
1332 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1333 gtk_action_set_sensitive (action, FALSE);
1335 /* set initial state of cc and bcc */
1336 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
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_CC, NULL));
1339 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1340 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1341 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1343 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1344 priv->update_caption_visibility = TRUE;
1346 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1348 /* Track account-removed signal, this window should be closed
1349 in the case we're creating a mail associated to the account
1351 priv->account_removed_handler_id =
1352 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1354 G_CALLBACK(on_account_removed),
1357 return (ModestWindow*) obj;
1361 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1363 GString **string_buffer = (GString **) user_data;
1365 *string_buffer = g_string_append (*string_buffer, buffer);
1371 * @result: A new string which should be freed with g_free().
1374 get_formatted_data (ModestMsgEditWindow *edit_window)
1376 ModestMsgEditWindowPrivate *priv;
1377 GString *string_buffer = g_string_new ("");
1379 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1381 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1383 return g_string_free (string_buffer, FALSE);
1388 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1391 const gchar *account_name;
1392 ModestMsgEditWindowPrivate *priv;
1394 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1396 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1398 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1399 g_return_val_if_fail (account_name, NULL);
1402 /* don't free these (except from) */
1403 data = g_slice_new0 (MsgData);
1404 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1406 data->account_name = g_strdup (account_name);
1407 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1408 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1409 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1410 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1411 if (priv->draft_msg) {
1412 data->draft_msg = g_object_ref (priv->draft_msg);
1413 } else if (priv->outbox_msg) {
1414 data->draft_msg = g_object_ref (priv->outbox_msg);
1416 data->draft_msg = NULL;
1419 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1421 gtk_text_buffer_get_bounds (buf, &b, &e);
1422 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1424 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1425 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1427 data->html_body = NULL;
1429 /* deep-copy the data */
1430 GList *cursor = priv->attachments;
1431 data->attachments = NULL;
1433 if (!(TNY_IS_MIME_PART(cursor->data))) {
1434 g_warning ("strange data in attachment list");
1435 cursor = g_list_next (cursor);
1438 data->attachments = g_list_append (data->attachments,
1439 g_object_ref (cursor->data));
1440 cursor = g_list_next (cursor);
1443 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1444 cursor = priv->images;
1445 data->images = NULL;
1448 if (!(TNY_IS_MIME_PART(cursor->data))) {
1449 g_warning ("strange data in attachment list");
1450 cursor = g_list_next (cursor);
1453 cid = tny_mime_part_get_content_id (cursor->data);
1455 gchar *image_tag_id;
1456 GtkTextTag *image_tag;
1458 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1459 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1460 g_free (image_tag_id);
1462 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1464 ((gtk_text_iter_has_tag (&iter, image_tag))||
1465 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1466 data->images = g_list_append (data->images,
1467 g_object_ref (cursor->data));
1469 cursor = g_list_next (cursor);
1472 data->priority_flags = priv->priority_flags;
1479 unref_gobject (GObject *obj, gpointer data)
1481 if (!G_IS_OBJECT(obj))
1483 g_object_unref (obj);
1487 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1490 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1498 g_free (data->subject);
1499 g_free (data->plain_body);
1500 g_free (data->html_body);
1501 g_free (data->account_name);
1503 if (data->draft_msg != NULL) {
1504 g_object_unref (data->draft_msg);
1505 data->draft_msg = NULL;
1508 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1509 g_list_free (data->attachments);
1510 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1511 g_list_free (data->images);
1513 g_slice_free (MsgData, data);
1517 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1520 ModestMsgEditWindowPrivate *priv = NULL;
1521 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1523 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1525 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1527 return MODEST_MSG_EDIT_FORMAT_HTML;
1529 return MODEST_MSG_EDIT_FORMAT_TEXT;
1533 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1534 ModestMsgEditFormat format)
1536 ModestMsgEditWindowPrivate *priv;
1538 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1539 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1542 case MODEST_MSG_EDIT_FORMAT_HTML:
1543 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1545 case MODEST_MSG_EDIT_FORMAT_TEXT:
1546 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1549 g_return_if_reached ();
1553 ModestMsgEditFormatState *
1554 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1556 ModestMsgEditFormatState *format_state = NULL;
1557 ModestMsgEditWindowPrivate *priv;
1558 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1560 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1561 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1563 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1565 format_state = g_new0 (ModestMsgEditFormatState, 1);
1566 format_state->bold = buffer_format->bold&0x1;
1567 format_state->italics = buffer_format->italic&0x1;
1568 format_state->bullet = buffer_format->bullet&0x1;
1569 format_state->color = buffer_format->color;
1570 format_state->font_size = buffer_format->font_size;
1571 format_state->font_family = wp_get_font_name (buffer_format->font);
1572 format_state->justification = buffer_format->justification;
1573 g_free (buffer_format);
1575 return format_state;
1580 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1581 const ModestMsgEditFormatState *format_state)
1583 ModestMsgEditWindowPrivate *priv;
1584 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1585 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1586 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1587 g_return_if_fail (format_state != NULL);
1589 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1590 gtk_widget_grab_focus (priv->msg_body);
1591 buffer_format->bold = (format_state->bold != FALSE);
1592 buffer_format->italic = (format_state->italics != FALSE);
1593 buffer_format->color = format_state->color;
1594 buffer_format->font_size = format_state->font_size;
1595 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1596 buffer_format->justification = format_state->justification;
1597 buffer_format->bullet = format_state->bullet;
1599 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1601 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1602 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1603 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1604 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1605 buffer_format->cs.font = (buffer_format->font != current_format->font);
1606 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1607 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1609 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1610 if (buffer_format->cs.bold) {
1611 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1613 if (buffer_format->cs.italic) {
1614 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1616 if (buffer_format->cs.color) {
1617 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1619 if (buffer_format->cs.font_size) {
1620 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1622 if (buffer_format->cs.justification) {
1623 switch (buffer_format->justification) {
1624 case GTK_JUSTIFY_LEFT:
1625 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1627 case GTK_JUSTIFY_CENTER:
1628 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1630 case GTK_JUSTIFY_RIGHT:
1631 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1638 if (buffer_format->cs.font) {
1639 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1641 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1642 if (buffer_format->cs.bullet) {
1643 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1645 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1647 g_free (current_format);
1652 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1654 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1656 ModestWindowPrivate *parent_priv;
1657 ModestMsgEditWindowPrivate *priv;
1658 GtkWidget *new_size_menuitem;
1659 GtkWidget *new_font_menuitem;
1661 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1662 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1664 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1665 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1666 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1667 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1669 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1670 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1671 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1674 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1676 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1677 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1679 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1680 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1682 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1683 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1685 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1686 G_CALLBACK (modest_msg_edit_window_color_button_change),
1688 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1689 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1690 G_CALLBACK (modest_msg_edit_window_color_button_change),
1693 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1694 buffer_format->font_size))->data);
1695 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1699 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1700 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1701 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1703 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1704 G_CALLBACK (modest_msg_edit_window_size_change),
1706 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1707 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1708 G_CALLBACK (modest_msg_edit_window_size_change),
1712 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1713 buffer_format->font))->data);
1714 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1718 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1719 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1720 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1722 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1723 G_CALLBACK (modest_msg_edit_window_font_change),
1725 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1726 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1727 G_CALLBACK (modest_msg_edit_window_font_change),
1731 g_free (buffer_format);
1735 #ifdef MODEST_HILDON_VERSION_0
1737 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1740 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1741 ModestMsgEditWindowPrivate *priv;
1742 GtkWidget *dialog = NULL;
1744 GdkColor *new_color = NULL;
1746 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1747 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1749 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1750 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1751 g_free (buffer_format);
1753 response = gtk_dialog_run (GTK_DIALOG (dialog));
1755 case GTK_RESPONSE_OK: {
1756 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1762 gtk_widget_destroy (dialog);
1764 if (new_color != NULL) {
1765 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1766 /* FIXME: free new_color here? */
1771 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1774 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1775 ModestMsgEditWindowPrivate *priv;
1776 GtkWidget *dialog = NULL;
1778 const GdkColor *new_color = NULL;
1781 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1782 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1784 dialog = hildon_color_chooser_new ();
1785 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1786 g_free (buffer_format);
1788 response = gtk_dialog_run (GTK_DIALOG (dialog));
1790 case GTK_RESPONSE_OK: {
1791 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1799 gtk_widget_destroy (dialog);
1800 if (new_color != NULL)
1801 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1802 (gpointer) new_color);
1805 #endif /*!MODEST_HILDON_VERSION_0*/
1808 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1811 ModestMsgEditWindowPrivate *priv;
1812 GtkWidget *dialog = NULL;
1814 GdkColor *old_color = NULL;
1815 const GdkColor *new_color = NULL;
1817 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1818 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1820 #ifdef MODEST_HILDON_VERSION_0
1821 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1822 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1824 dialog = hildon_color_chooser_new ();
1825 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1826 #endif /*MODEST_HILDON_VERSION_9*/
1828 response = gtk_dialog_run (GTK_DIALOG (dialog));
1830 case GTK_RESPONSE_OK: {
1831 #ifdef MODEST_HILDON_VERSION_0
1832 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1835 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1837 #endif /*MODEST_HILDON_VERSION_0*/
1843 gtk_widget_destroy (dialog);
1845 if (new_color != NULL)
1846 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1850 static TnyStream* create_stream_for_uri (const gchar* uri)
1855 TnyStream *result = NULL;
1857 GnomeVFSHandle *handle = NULL;
1858 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1859 if (test == GNOME_VFS_OK) {
1860 /* Create the tinymail stream: */
1861 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1862 result = TNY_STREAM (tny_vfs_stream_new (handle));
1869 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1872 ModestMsgEditWindowPrivate *priv;
1873 GtkWidget *dialog = NULL;
1875 GSList *uris = NULL;
1876 GSList *uri_node = NULL;
1878 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1880 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1881 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1882 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1884 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1886 response = gtk_dialog_run (GTK_DIALOG (dialog));
1888 case GTK_RESPONSE_OK:
1889 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1894 gtk_widget_destroy (dialog);
1896 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1898 GnomeVFSHandle *handle = NULL;
1899 GnomeVFSResult result;
1900 GtkTextIter position;
1901 GtkTextMark *insert_mark;
1903 uri = (const gchar *) uri_node->data;
1904 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1905 if (result == GNOME_VFS_OK) {
1907 GnomeVFSFileInfo info;
1908 gchar *filename, *basename, *escaped_filename;
1909 TnyMimePart *mime_part;
1911 const gchar *mime_type = NULL;
1912 GnomeVFSURI *vfs_uri;
1914 vfs_uri = gnome_vfs_uri_new (uri);
1916 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1917 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1918 g_free (escaped_filename);
1919 gnome_vfs_uri_unref (vfs_uri);
1921 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1922 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1924 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1926 mime_part = tny_platform_factory_new_mime_part
1927 (modest_runtime_get_platform_factory ());
1929 TnyStream *stream = create_stream_for_uri (uri);
1930 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1932 content_id = g_strdup_printf ("%d", priv->last_cid);
1933 tny_mime_part_set_content_id (mime_part, content_id);
1934 g_free (content_id);
1937 basename = g_path_get_basename (filename);
1938 tny_mime_part_set_filename (mime_part, basename);
1941 pixbuf = pixbuf_from_stream (stream, mime_type);
1943 if (pixbuf != NULL) {
1944 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1945 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1946 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1949 priv->images = g_list_prepend (priv->images, mime_part);
1950 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1960 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1963 ModestMsgEditWindowPrivate *priv;
1964 GtkWidget *dialog = NULL;
1966 GSList *uris = NULL;
1969 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1971 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1972 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1973 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1975 response = gtk_dialog_run (GTK_DIALOG (dialog));
1977 case GTK_RESPONSE_OK:
1978 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1983 gtk_widget_destroy (dialog);
1985 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1986 const gchar *uri = (const gchar *) uri_node->data;
1987 modest_msg_edit_window_attach_file_one (window, uri);
1989 g_slist_foreach (uris, (GFunc) g_free, NULL);
1990 g_slist_free (uris);
1994 modest_msg_edit_window_attach_file_one (
1995 ModestMsgEditWindow *window,
1998 g_return_if_fail (window);
1999 g_return_if_fail (uri);
2001 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2004 GnomeVFSHandle *handle = NULL;
2005 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2006 if (result == GNOME_VFS_OK) {
2007 TnyMimePart *mime_part;
2009 const gchar *mime_type = NULL;
2011 gchar *escaped_filename;
2014 GnomeVFSFileInfo info;
2015 GnomeVFSURI *vfs_uri;
2017 vfs_uri = gnome_vfs_uri_new (uri);
2020 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2021 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2022 g_free (escaped_filename);
2023 gnome_vfs_uri_unref (vfs_uri);
2025 if (gnome_vfs_get_file_info (uri,
2027 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2028 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2030 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2031 mime_part = tny_platform_factory_new_mime_part
2032 (modest_runtime_get_platform_factory ());
2033 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2035 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2037 content_id = g_strdup_printf ("%d", priv->last_cid);
2038 tny_mime_part_set_content_id (mime_part, content_id);
2039 g_free (content_id);
2042 basename = g_path_get_basename (filename);
2043 tny_mime_part_set_filename (mime_part, basename);
2046 priv->attachments = g_list_prepend (priv->attachments, mime_part);
2047 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2049 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2050 gtk_widget_show_all (priv->attachments_caption);
2051 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2057 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2060 ModestMsgEditWindowPrivate *priv;
2061 gboolean clean_list = FALSE;
2063 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2064 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2066 if (att_list == NULL) {
2067 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2071 if (att_list == NULL) {
2072 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2074 GtkWidget *confirmation_dialog = NULL;
2075 gboolean dialog_response;
2077 gchar *message = NULL;
2078 gchar *filename = NULL;
2080 if (att_list->next == NULL) {
2081 if (TNY_IS_MSG (att_list->data)) {
2082 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2084 filename = g_strdup (tny_header_get_subject (header));
2085 g_object_unref (header);
2087 if (filename == NULL) {
2088 filename = g_strdup (_("mail_va_no_subject"));
2091 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2094 filename = g_strdup ("");
2096 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2097 att_list->next == NULL), filename);
2099 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2101 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2102 gtk_widget_destroy (confirmation_dialog);
2103 if (!dialog_response) {
2105 g_list_free (att_list);
2108 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2110 for (node = att_list; node != NULL; node = g_list_next (node)) {
2111 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2112 const gchar *att_id;
2113 priv->attachments = g_list_remove (priv->attachments, mime_part);
2115 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2117 if (priv->attachments == NULL)
2118 gtk_widget_hide (priv->attachments_caption);
2119 att_id = tny_mime_part_get_content_id (mime_part);
2121 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2123 g_object_unref (mime_part);
2124 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2129 g_list_free (att_list);
2133 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2136 ModestMsgEditWindowPrivate *priv;
2137 GdkColor *new_color;
2138 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2140 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2141 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2144 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2146 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2148 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2150 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2155 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2158 ModestMsgEditWindowPrivate *priv;
2159 gint new_size_index;
2160 ModestMsgEditWindow *window;
2163 window = MODEST_MSG_EDIT_WINDOW (userdata);
2164 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2165 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2167 if (gtk_check_menu_item_get_active (menu_item)) {
2169 WPTextBufferFormat format;
2171 memset (&format, 0, sizeof (format));
2172 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2174 label = gtk_bin_get_child (GTK_BIN (menu_item));
2176 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2177 format.cs.font_size = TRUE;
2178 format.cs.text_position = TRUE;
2179 format.cs.font = TRUE;
2180 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2181 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2183 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2184 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2185 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2187 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2188 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2189 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2195 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2198 ModestMsgEditWindowPrivate *priv;
2199 gint new_font_index;
2200 ModestMsgEditWindow *window;
2203 window = MODEST_MSG_EDIT_WINDOW (userdata);
2204 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2205 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2207 if (gtk_check_menu_item_get_active (menu_item)) {
2210 label = gtk_bin_get_child (GTK_BIN (menu_item));
2212 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2214 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2215 (gpointer) new_font_index))
2216 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2218 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2219 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2220 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2226 modest_msg_edit_window_set_zoom (ModestWindow *window,
2229 ModestMsgEditWindowPrivate *priv;
2230 ModestWindowPrivate *parent_priv;
2231 GtkRadioAction *zoom_radio_action;
2233 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2235 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2236 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2237 priv->zoom_level = zoom;
2238 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2240 /* Zoom level menu options should be updated with the current zoom level */
2241 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2242 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2243 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2244 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2245 /* FIXME: Not availible before Gtk 2.10 */
2247 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2252 modest_msg_edit_window_get_zoom (ModestWindow *window)
2254 ModestMsgEditWindowPrivate *priv;
2256 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2258 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2259 return priv->zoom_level;
2263 zoom_allowed (ModestMsgEditWindow *window)
2267 focus = gtk_window_get_focus (GTK_WINDOW (window));
2268 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2272 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2274 ModestWindowPrivate *parent_priv;
2275 GtkRadioAction *zoom_radio_action;
2276 GSList *group, *node;
2278 /* First we check if the text view is focused. If not, zooming is not allowed */
2279 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2280 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2284 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2285 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2286 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2288 group = gtk_radio_action_get_group (zoom_radio_action);
2290 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2291 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2295 for (node = group; node != NULL; node = g_slist_next (node)) {
2296 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2297 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2305 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2307 ModestWindowPrivate *parent_priv;
2308 GtkRadioAction *zoom_radio_action;
2309 GSList *group, *node;
2311 /* First we check if the text view is focused. If not, zooming is not allowed */
2312 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2313 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2317 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2318 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2319 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2321 group = gtk_radio_action_get_group (zoom_radio_action);
2323 for (node = group; node != NULL; node = g_slist_next (node)) {
2324 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2325 if (node->next != NULL) {
2326 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2329 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2337 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2339 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2340 ModestWindowPrivate *parent_priv;
2341 ModestWindowMgr *mgr;
2342 gboolean is_fullscreen;
2343 GtkAction *fs_toggle_action;
2346 mgr = modest_runtime_get_window_mgr ();
2347 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2349 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2351 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2352 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2353 if (is_fullscreen != active)
2354 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2362 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2365 ModestMsgEditWindowPrivate *priv = NULL;
2366 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2368 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2369 if (!priv->update_caption_visibility)
2372 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2374 gtk_widget_show (priv->cc_caption);
2376 gtk_widget_hide (priv->cc_caption);
2378 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2382 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2385 ModestMsgEditWindowPrivate *priv = NULL;
2386 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2388 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2389 if (!priv->update_caption_visibility)
2392 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2394 gtk_widget_show (priv->bcc_caption);
2396 gtk_widget_hide (priv->bcc_caption);
2398 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2402 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2403 ModestRecptEditor *editor)
2405 ModestMsgEditWindowPrivate *priv;
2407 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2408 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2409 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2411 if (editor == NULL) {
2412 GtkWidget *view_focus;
2413 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2415 /* This code should be kept in sync with ModestRecptEditor. The
2416 textview inside the recpt editor is the one that really gets the
2417 focus. As it's inside a scrolled window, and this one inside the
2418 hbox recpt editor inherits from, we'll need to go up in the
2419 hierarchy to know if the text view is part of the recpt editor
2420 or if it's a different text entry */
2422 if (gtk_widget_get_parent (view_focus)) {
2423 GtkWidget *first_parent;
2425 first_parent = gtk_widget_get_parent (view_focus);
2426 if (gtk_widget_get_parent (first_parent) &&
2427 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2428 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2433 editor = MODEST_RECPT_EDITOR (priv->to_field);
2437 modest_address_book_select_addresses (editor);
2442 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2444 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2446 modest_msg_edit_window_open_addressbook (window, NULL);
2450 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2451 gboolean show_toolbar)
2453 ModestWindowPrivate *parent_priv;
2454 const gchar *action_name;
2457 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2458 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2460 /* We can not just use the code of
2461 modest_msg_edit_window_setup_toolbar because it has a
2462 mixture of both initialization and creation code. */
2464 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2466 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2468 /* Update also the actions (to update the toggles in the
2469 menus), we have to do it manually because some other window
2470 of the same time could have changed it (remember that the
2471 toolbar fullscreen mode is shared by all the windows of the
2473 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2474 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2476 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2478 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2479 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2485 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2486 TnyHeaderFlags priority_flags)
2488 ModestMsgEditWindowPrivate *priv;
2489 ModestWindowPrivate *parent_priv;
2491 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2493 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2494 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2496 if (priv->priority_flags != priority_flags) {
2497 GtkAction *priority_action = NULL;
2499 priv->priority_flags = priority_flags;
2501 switch (priority_flags) {
2502 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2503 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2504 gtk_widget_show (priv->priority_icon);
2505 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2506 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2508 case TNY_HEADER_FLAG_LOW_PRIORITY:
2509 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2510 gtk_widget_show (priv->priority_icon);
2511 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2512 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2515 gtk_widget_hide (priv->priority_icon);
2516 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2517 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2520 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2521 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2526 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2529 ModestMsgEditWindowPrivate *priv;
2530 ModestWindowPrivate *parent_priv;
2531 gint current_format;
2533 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2535 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2536 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2538 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2539 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2541 if (current_format != file_format) {
2542 switch (file_format) {
2543 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2544 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2545 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2547 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2551 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2552 response = gtk_dialog_run (GTK_DIALOG (dialog));
2553 gtk_widget_destroy (dialog);
2554 if (response == GTK_RESPONSE_OK) {
2555 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2557 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2558 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2563 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2568 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2571 ModestMsgEditWindowPrivate *priv;
2572 WPTextBufferFormat oldfmt, fmt;
2573 gint old_position = 0;
2577 GdkColor *color = NULL;
2578 gboolean bold, bold_set, italic, italic_set;
2579 gboolean underline, underline_set;
2580 gboolean strikethrough, strikethrough_set;
2581 gboolean position_set;
2582 gboolean font_size_set, font_set, color_set;
2585 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2586 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2588 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2590 /* First we get the currently selected font information */
2591 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2592 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2594 switch (oldfmt.text_position) {
2595 case TEXT_POSITION_NORMAL:
2598 case TEXT_POSITION_SUPERSCRIPT:
2606 g_object_set (G_OBJECT (dialog),
2607 "bold", oldfmt.bold != FALSE,
2608 "bold-set", !oldfmt.cs.bold,
2609 "underline", oldfmt.underline != FALSE,
2610 "underline-set", !oldfmt.cs.underline,
2611 "italic", oldfmt.italic != FALSE,
2612 "italic-set", !oldfmt.cs.italic,
2613 "strikethrough", oldfmt.strikethrough != FALSE,
2614 "strikethrough-set", !oldfmt.cs.strikethrough,
2615 "color", &oldfmt.color,
2616 "color-set", !oldfmt.cs.color,
2617 "size", wp_font_size[oldfmt.font_size],
2618 "size-set", !oldfmt.cs.font_size,
2619 "position", old_position,
2620 "position-set", !oldfmt.cs.text_position,
2621 "family", wp_get_font_name (oldfmt.font),
2622 "family-set", !oldfmt.cs.font,
2625 gtk_widget_show_all (dialog);
2626 response = gtk_dialog_run (GTK_DIALOG (dialog));
2627 if (response == GTK_RESPONSE_OK) {
2629 g_object_get( dialog,
2631 "bold-set", &bold_set,
2632 "underline", &underline,
2633 "underline-set", &underline_set,
2635 "italic-set", &italic_set,
2636 "strikethrough", &strikethrough,
2637 "strikethrough-set", &strikethrough_set,
2639 "color-set", &color_set,
2641 "size-set", &font_size_set,
2642 "family", &font_name,
2643 "family-set", &font_set,
2644 "position", &position,
2645 "position-set", &position_set,
2650 if (response == GTK_RESPONSE_OK) {
2651 memset(&fmt, 0, sizeof(fmt));
2657 fmt.italic = italic;
2658 fmt.cs.italic = TRUE;
2660 if (underline_set) {
2661 fmt.underline = underline;
2662 fmt.cs.underline = TRUE;
2664 if (strikethrough_set) {
2665 fmt.strikethrough = strikethrough;
2666 fmt.cs.strikethrough = TRUE;
2671 ? TEXT_POSITION_NORMAL
2672 : ( ( position == 1 )
2673 ? TEXT_POSITION_SUPERSCRIPT
2674 : TEXT_POSITION_SUBSCRIPT );
2675 fmt.cs.text_position = TRUE;
2679 fmt.cs.color = TRUE;
2682 fmt.font = wp_get_font_index(font_name,
2687 if (font_size_set) {
2688 fmt.font_size = wp_get_font_size_index(
2689 font_size, DEFAULT_FONT_SIZE);
2690 fmt.cs.font_size = TRUE;
2692 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2693 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2695 gtk_widget_destroy (dialog);
2697 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2701 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2703 ModestMsgEditWindowPrivate *priv;
2705 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2706 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2708 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2710 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2715 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2717 ModestMsgEditWindowPrivate *priv;
2719 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2720 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2722 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2724 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2729 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2731 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2733 priv->can_undo = can_undo;
2737 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2739 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2741 priv->can_redo = can_redo;
2745 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2747 ModestMsgEditWindowPrivate *priv;
2748 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2749 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2751 return priv->can_undo;
2755 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2757 ModestMsgEditWindowPrivate *priv;
2758 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2759 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2761 return priv->can_redo;
2766 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2769 GtkTextIter match_start, match_end;
2771 if (image_id == NULL)
2774 gtk_text_buffer_get_start_iter (buffer, &iter);
2776 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2777 GSList *tags = gtk_text_iter_get_tags (&match_start);
2779 for (node = tags; node != NULL; node = g_slist_next (node)) {
2780 GtkTextTag *tag = (GtkTextTag *) node->data;
2781 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2782 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2783 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2785 offset = gtk_text_iter_get_offset (&match_start);
2786 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2787 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2791 gtk_text_iter_forward_char (&iter);
2796 message_is_empty (ModestMsgEditWindow *window)
2798 ModestMsgEditWindowPrivate *priv = NULL;
2800 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2801 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2803 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2804 * so we can ignore markup.
2806 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2809 count = gtk_text_buffer_get_char_count (buf);
2815 msg_body_focus (GtkWidget *focus,
2816 GdkEventFocus *event,
2820 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2825 recpt_field_changed (GtkTextBuffer *buffer,
2826 ModestMsgEditWindow *editor)
2828 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2832 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2834 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2838 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2840 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2841 GtkTextBuffer *buffer;
2843 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2844 gtk_text_buffer_set_modified (buffer, FALSE);
2845 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2846 gtk_text_buffer_set_modified (buffer, FALSE);
2847 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2848 gtk_text_buffer_set_modified (buffer, FALSE);
2849 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2853 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2855 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2856 GtkTextBuffer *buffer;
2858 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2859 if (gtk_text_buffer_get_modified (buffer))
2861 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2862 if (gtk_text_buffer_get_modified (buffer))
2864 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2865 if (gtk_text_buffer_get_modified (buffer))
2867 if (gtk_text_buffer_get_modified (priv->text_buffer))
2877 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2879 ModestMsgEditWindowPrivate *priv = NULL;
2881 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2882 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2884 /* check if there's no recipient added */
2885 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2886 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2887 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2888 /* no recipient contents, then select contacts */
2889 modest_msg_edit_window_open_addressbook (window, NULL);
2893 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2894 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2897 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2898 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2901 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2902 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2906 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2907 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2908 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2915 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2916 ModestMsgEditWindow *window)
2918 modest_msg_edit_window_offer_attach_file (window);
2922 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2924 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2926 return priv->clipboard_text;
2930 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2932 ModestMsgEditWindow *window)
2934 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2935 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2937 if (!GTK_WIDGET_VISIBLE (window))
2940 text = gtk_clipboard_wait_for_text (selection_clipboard);
2942 if (priv->clipboard_text != NULL) {
2943 g_free (priv->clipboard_text);
2945 priv->clipboard_text = text;
2947 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2950 subject_field_move_cursor (GtkEntry *entry,
2951 GtkMovementStep step,
2956 if (!GTK_WIDGET_VISIBLE (window))
2959 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2963 update_window_title (ModestMsgEditWindow *window)
2965 ModestMsgEditWindowPrivate *priv = NULL;
2966 const gchar *subject;
2968 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2969 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2970 if (subject == NULL || subject[0] == '\0')
2971 subject = _("mail_va_new_email");
2973 gtk_window_set_title (GTK_WINDOW (window), subject);
2978 subject_field_changed (GtkEditable *editable,
2979 ModestMsgEditWindow *window)
2981 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2982 update_window_title (window);
2983 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2984 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2988 subject_field_insert_text (GtkEditable *editable,
2990 gint new_text_length,
2992 ModestMsgEditWindow *window)
2994 GString *result = g_string_new ("");
2996 gint result_len = 0;
2997 const gchar *entry_text = NULL;
3000 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3001 old_length = g_utf8_strlen (entry_text, -1);
3003 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3004 gunichar c = g_utf8_get_char_validated (current, 8);
3005 /* Invalid unichar, stop */
3011 result = g_string_append_unichar (result, c);
3015 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3016 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3019 /* Prevent endless recursion */
3020 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3021 g_signal_emit_by_name (editable, "insert-text",
3022 (gpointer) result->str, (gpointer) result->len,
3023 (gpointer) position, (gpointer) window);
3024 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3028 if (result_len + old_length > 1000) {
3029 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3030 dgettext("hildon-common-strings",
3031 "ckdg_ib_maximum_characters_reached"));
3034 g_string_free (result, TRUE);
3038 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3041 ModestMsgEditWindowPrivate *priv = NULL;
3043 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3044 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3046 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3049 gtk_widget_show_all (priv->find_toolbar);
3050 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3052 gtk_widget_hide_all (priv->find_toolbar);
3053 gtk_widget_grab_focus (priv->msg_body);
3059 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3061 GtkTextIter *match_start,
3062 GtkTextIter *match_end)
3064 GtkTextIter end_iter;
3065 gchar *str_casefold;
3068 gchar *range_casefold;
3071 gboolean result = FALSE;
3078 gtk_text_iter_forward_to_end (&end_iter);
3080 str_casefold = g_utf8_casefold (str, -1);
3081 str_chars_n = strlen (str);
3083 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3084 range_casefold = g_utf8_casefold (range_text, -1);
3085 range_chars_n = strlen (range_casefold);
3087 if (range_chars_n < str_chars_n) {
3088 g_free (str_casefold);
3089 g_free (range_text);
3090 g_free (range_casefold);
3094 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3095 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3096 if (!g_utf8_collate (range_subtext, str_casefold)) {
3097 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3099 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3100 match_start, match_end, NULL);
3101 g_free (found_text);
3103 g_free (range_subtext);
3107 g_free (str_casefold);
3108 g_free (range_text);
3109 g_free (range_casefold);
3116 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3117 ModestMsgEditWindow *window)
3119 gchar *current_search = NULL;
3120 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3122 GtkTextIter selection_start, selection_end;
3123 GtkTextIter match_start, match_end;
3124 gboolean continue_search = FALSE;
3126 if (message_is_empty (window)) {
3127 g_free (priv->last_search);
3128 priv->last_search = NULL;
3129 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3133 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3134 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3135 g_free (current_search);
3136 g_free (priv->last_search);
3137 priv->last_search = NULL;
3138 /* Information banner about empty search */
3139 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3143 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3144 continue_search = TRUE;
3146 g_free (priv->last_search);
3147 priv->last_search = g_strdup (current_search);
3150 if (continue_search) {
3151 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3152 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3153 &match_start, &match_end);
3155 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3157 GtkTextIter buffer_start;
3158 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3159 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3160 &match_start, &match_end);
3162 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3165 /* Mark as selected the string found in search */
3167 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3168 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3170 g_free (priv->last_search);
3171 priv->last_search = NULL;
3173 g_free (current_search);
3177 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3178 ModestMsgEditWindow *window)
3180 GtkToggleAction *toggle;
3181 ModestWindowPrivate *parent_priv;
3182 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3184 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3185 gtk_toggle_action_set_active (toggle, FALSE);
3189 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3191 ModestMsgEditWindowPrivate *priv;
3193 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3198 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3201 ModestMsgEditWindowPrivate *priv;
3203 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3209 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3212 ModestMsgEditWindowPrivate *priv;
3213 TnyHeader *header = NULL;
3215 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3216 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3218 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3219 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3221 if (priv->draft_msg != NULL) {
3222 modest_window_mgr_unregister_window (mgr, MODEST_WINDOW (window));
3223 g_object_unref (priv->draft_msg);
3226 if (draft != NULL) {
3227 g_object_ref (draft);
3228 header = tny_msg_get_header (draft);
3229 if (priv->msg_uid) {
3230 g_free (priv->msg_uid);
3231 priv->msg_uid = NULL;
3233 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3234 if (GTK_WIDGET_REALIZED (window))
3235 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3238 priv->draft_msg = draft;
3242 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3243 GtkTextIter *start, GtkTextIter *end,
3246 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3247 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3250 if (tag == NULL+13) return;
3251 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3252 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3253 replace_with_images (window, priv->images);
3258 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3261 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3263 g_return_if_fail (TNY_IS_MIME_PART (part));
3264 priv->attachments = g_list_prepend (priv->attachments, part);
3265 g_object_ref (part);
3266 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3267 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3268 gtk_widget_show_all (priv->attachments_caption);
3269 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3273 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3275 ModestMsgEditWindowPrivate *priv;
3277 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3278 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3280 return priv->msg_uid;
3284 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3285 ModestMsgEditWindowWidgetType widget_type)
3287 ModestMsgEditWindowPrivate *priv;
3289 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3290 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3292 switch (widget_type) {
3293 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3294 return priv->msg_body;
3296 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3297 return priv->to_field;
3299 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3300 return priv->cc_field;
3302 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3303 return priv->bcc_field;
3305 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3306 return priv->subject_field;
3308 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3309 return priv->attachments_view;
3317 remove_tags (WPTextBuffer *buffer)
3319 GtkTextIter start, end;
3321 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3322 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3324 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3328 on_account_removed (TnyAccountStore *account_store,
3329 TnyAccount *account,
3332 /* Do nothing if it's a store account, because we use the
3333 transport to send the messages */
3334 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3335 const gchar *parent_acc = NULL;
3336 const gchar *our_acc = NULL;
3338 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3339 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3340 /* Close this window if I'm showing a message of the removed account */
3341 if (strcmp (parent_acc, our_acc) == 0)
3342 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));