1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include "modest-maemo-utils.h"
81 #define DEFAULT_FONT_SIZE 3
82 #define DEFAULT_FONT 2
83 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
84 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
85 #define DEFAULT_MAIN_VBOX_SPACING 6
86 #define SUBJECT_MAX_LENGTH 1000
87 #define IMAGE_MAX_WIDTH 560
88 #define DEFAULT_FONT_SCALE 1.5
90 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
91 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
92 static void modest_msg_edit_window_finalize (GObject *obj);
94 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
95 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
96 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
98 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
99 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
100 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
101 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
102 GtkTextIter *start, GtkTextIter *end,
104 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
105 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
106 static void subject_field_insert_text (GtkEditable *editable,
108 gint new_text_length,
110 ModestMsgEditWindow *window);
111 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
113 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
115 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
117 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
118 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
119 GdkEventWindowState *event,
121 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
122 ModestRecptEditor *editor);
123 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
124 ModestMsgEditWindow *window);
126 /* ModestWindow methods implementation */
127 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
128 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
129 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
130 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
131 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
132 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
133 gboolean show_toolbar);
134 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
136 ModestMsgEditWindow *window);
137 static void subject_field_move_cursor (GtkEntry *entry,
138 GtkMovementStep step,
142 static void update_window_title (ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
148 ModestMsgEditWindow *window);
149 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
151 GtkTextIter *match_start,
152 GtkTextIter *match_end);
154 static void remove_tags (WPTextBuffer *buffer);
156 static void on_account_removed (TnyAccountStore *account_store,
161 static void DEBUG_BUFFER (WPTextBuffer *buffer)
166 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
167 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
168 while (!gtk_text_iter_is_end (&iter)) {
169 GString *output = g_string_new ("");
170 GSList *toggled_tags;
173 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
174 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
175 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
176 GtkTextTag *tag = (GtkTextTag *) node->data;
178 g_object_get (G_OBJECT (tag), "name", &name, NULL);
179 output = g_string_append (output, name);
180 g_string_append (output, " ");
182 output = g_string_append (output, "] OPENED [ ");
183 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
184 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
185 GtkTextTag *tag = (GtkTextTag *) node->data;
187 g_object_get (G_OBJECT (tag), "name", &name, NULL);
188 output = g_string_append (output, name);
189 g_string_append (output, " ");
191 output = g_string_append (output, "]\n");
192 g_message ("%s", output->str);
193 g_string_free (output, TRUE);
194 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
196 g_message ("END BUFFER");
201 /* static gboolean */
202 /* on_key_pressed (GtkWidget *self, */
203 /* GdkEventKey *event, */
204 /* gpointer user_data); */
206 /* list my signals */
213 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
214 struct _ModestMsgEditWindowPrivate {
216 GtkWidget *header_box;
218 ModestPairList *from_field_protos;
219 GtkWidget *from_field;
223 GtkWidget *bcc_field;
224 GtkWidget *subject_field;
225 GtkWidget *attachments_view;
226 GtkWidget *priority_icon;
227 GtkWidget *add_attachment_button;
229 GtkWidget *cc_caption;
230 GtkWidget *bcc_caption;
231 gboolean update_caption_visibility;
232 GtkWidget *attachments_caption;
234 GtkTextBuffer *text_buffer;
236 GtkWidget *font_size_toolitem;
237 GtkWidget *font_face_toolitem;
238 GtkWidget *font_color_button;
239 GSList *font_items_group;
240 GtkWidget *font_tool_button_label;
241 GSList *size_items_group;
242 GtkWidget *size_tool_button_label;
244 GtkWidget *find_toolbar;
248 GtkWidget *scroll_area;
249 gint last_vadj_upper;
255 TnyHeaderFlags priority_flags;
259 gboolean can_undo, can_redo;
260 gulong clipboard_change_handler_id;
261 gulong default_clipboard_change_handler_id;
262 gulong account_removed_handler_id;
263 gchar *clipboard_text;
272 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
273 MODEST_TYPE_MSG_EDIT_WINDOW, \
274 ModestMsgEditWindowPrivate))
276 static GtkWindowClass *parent_class = NULL;
278 /* uncomment the following if you have defined any signals */
279 /* static guint signals[LAST_SIGNAL] = {0}; */
282 modest_msg_edit_window_get_type (void)
284 static GType my_type = 0;
286 static const GTypeInfo my_info = {
287 sizeof(ModestMsgEditWindowClass),
288 NULL, /* base init */
289 NULL, /* base finalize */
290 (GClassInitFunc) modest_msg_edit_window_class_init,
291 NULL, /* class finalize */
292 NULL, /* class data */
293 sizeof(ModestMsgEditWindow),
295 (GInstanceInitFunc) modest_msg_edit_window_init,
298 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
299 "ModestMsgEditWindow",
302 wp_text_buffer_library_init ();
308 save_state (ModestWindow *self)
310 modest_widget_memory_save (modest_runtime_get_conf(),
311 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
316 restore_settings (ModestMsgEditWindow *self)
318 modest_widget_memory_restore (modest_runtime_get_conf(),
319 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
324 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
326 GObjectClass *gobject_class;
327 ModestWindowClass *modest_window_class;
328 gobject_class = (GObjectClass*) klass;
329 modest_window_class = (ModestWindowClass*) klass;
331 parent_class = g_type_class_peek_parent (klass);
332 gobject_class->finalize = modest_msg_edit_window_finalize;
334 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
335 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
336 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
337 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
338 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
339 modest_window_class->save_state_func = save_state;
340 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
342 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
346 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
348 ModestMsgEditWindowPrivate *priv;
349 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
351 priv->msg_body = NULL;
352 priv->from_field = NULL;
353 priv->to_field = NULL;
354 priv->cc_field = NULL;
355 priv->bcc_field = NULL;
356 priv->subject_field = NULL;
357 priv->attachments = NULL;
360 priv->zoom_level = 1.0;
362 priv->cc_caption = NULL;
363 priv->bcc_caption = NULL;
364 priv->update_caption_visibility = FALSE;
366 priv->priority_flags = 0;
368 priv->find_toolbar = NULL;
369 priv->last_search = NULL;
371 priv->draft_msg = NULL;
372 priv->outbox_msg = NULL;
373 priv->msg_uid = NULL;
375 priv->can_undo = FALSE;
376 priv->can_redo = FALSE;
377 priv->clipboard_change_handler_id = 0;
378 priv->default_clipboard_change_handler_id = 0;
379 priv->account_removed_handler_id = 0;
380 priv->clipboard_text = NULL;
383 priv->last_vadj_upper = 0;
387 /* FIXME: this is a dup from the one in gtk/ */
390 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
392 static ModestPairList*
393 get_transports (void)
395 GSList *transports = NULL;
397 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
398 GSList *accounts = modest_account_mgr_account_names (account_mgr,
399 TRUE /* only enabled accounts. */);
401 GSList *cursor = accounts;
403 gchar *account_name = cursor->data;
404 gchar *from_string = NULL;
406 from_string = modest_account_mgr_get_from_string (account_mgr,
410 if (from_string && account_name) {
411 gchar *name = account_name;
412 ModestPair *pair = modest_pair_new ((gpointer) name,
413 (gpointer) from_string , TRUE);
414 transports = g_slist_prepend (transports, pair);
417 cursor = cursor->next;
419 g_slist_free (accounts); /* only free the accounts, not the elements,
420 * because they are used in the pairlist */
424 void vadj_changed (GtkAdjustment *adj,
425 ModestMsgEditWindow *window)
427 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
429 GdkRectangle rectangle, cursor_rectangle;
430 GtkTextIter position;
434 /* We detect if cursor is visible using the full height, not only the center. This
436 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
437 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
439 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
440 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
442 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
443 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
445 if (gtk_widget_is_focus (priv->msg_body) &&
447 if (priv->last_vadj_upper != adj->upper) {
450 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
451 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
452 insert, 0.1, FALSE, 0.0, 0.0);
455 priv->last_vadj_upper = adj->upper;
460 init_window (ModestMsgEditWindow *obj)
462 GtkWidget *from_caption, *to_caption, *subject_caption;
463 GtkWidget *main_vbox;
464 ModestMsgEditWindowPrivate *priv;
466 GtkSizeGroup *size_group;
468 GtkWidget *subject_box;
469 GtkWidget *attachment_icon;
470 GtkWidget *window_box;
471 #if (GTK_MINOR_VERSION >= 10)
472 GdkAtom deserialize_type;
474 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
476 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
478 /* Note: This ModestPairList* must exist for as long as the combo
479 * that uses it, because the ModestComboBox uses the ID opaquely,
480 * so it can't know how to manage its memory. */
481 priv->from_field_protos = get_transports ();
483 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
485 priv->to_field = modest_recpt_editor_new ();
486 priv->cc_field = modest_recpt_editor_new ();
487 priv->bcc_field = modest_recpt_editor_new ();
488 subject_box = gtk_hbox_new (FALSE, 0);
489 priv->priority_icon = gtk_image_new ();
490 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
491 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
492 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
493 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
494 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
495 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
496 priv->add_attachment_button = gtk_button_new ();
497 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
498 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
499 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
500 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
501 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
502 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
503 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
504 priv->attachments_view = modest_attachments_view_new (NULL);
506 priv->header_box = gtk_vbox_new (FALSE, 0);
508 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
509 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
510 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
511 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
512 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
513 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
514 g_object_unref (size_group);
516 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
517 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
518 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
519 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
520 gtk_size_group_add_widget (size_group, priv->subject_field);
521 gtk_size_group_add_widget (size_group, priv->attachments_view);
522 g_object_unref (size_group);
524 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
525 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
526 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
527 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
528 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
529 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
530 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
533 priv->msg_body = wp_text_view_new ();
534 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
535 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
536 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
537 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
538 #if (GTK_MINOR_VERSION >= 10)
539 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
540 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
542 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
543 deserialize_type, TRUE);
545 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
547 priv->find_toolbar = hildon_find_toolbar_new (NULL);
548 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
550 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
552 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
553 G_CALLBACK (text_buffer_refresh_attributes), obj);
554 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
555 G_CALLBACK (text_buffer_can_undo), obj);
556 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
557 G_CALLBACK (text_buffer_can_redo), obj);
558 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
559 G_CALLBACK (body_changed), obj);
560 g_signal_connect (G_OBJECT (obj), "window-state-event",
561 G_CALLBACK (modest_msg_edit_window_window_state_event),
563 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
564 G_CALLBACK (text_buffer_apply_tag), obj);
565 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
566 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
567 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
568 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
569 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
570 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
572 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
573 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
575 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
576 G_CALLBACK (msg_body_focus), obj);
577 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
578 G_CALLBACK (msg_body_focus), obj);
579 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
580 "changed", G_CALLBACK (recpt_field_changed), obj);
581 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
582 "changed", G_CALLBACK (recpt_field_changed), obj);
583 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
584 "changed", G_CALLBACK (recpt_field_changed), obj);
585 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
586 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
587 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
589 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
590 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
592 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
593 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
594 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
595 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
597 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
599 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
600 frame = gtk_frame_new (NULL);
601 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
603 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
604 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
605 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
607 G_CALLBACK (vadj_changed),
609 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
611 window_box = gtk_vbox_new (FALSE, 0);
612 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
613 gtk_container_add (GTK_CONTAINER(obj), window_box);
614 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
615 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
617 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
618 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
619 priv->default_clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
620 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
625 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
627 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
629 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
630 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
631 priv->clipboard_change_handler_id))
632 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
633 priv->clipboard_change_handler_id);
634 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
635 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
636 priv->default_clipboard_change_handler_id))
637 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
638 priv->default_clipboard_change_handler_id);
640 if (priv->account_removed_handler_id &&
641 g_signal_handler_is_connected (modest_runtime_get_account_store (),
642 priv->account_removed_handler_id))
643 g_signal_handler_disconnect(modest_runtime_get_account_store (),
644 priv->account_removed_handler_id);
648 modest_msg_edit_window_finalize (GObject *obj)
650 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
652 /* Sanity check: shouldn't be needed, the window mgr should
653 call this function before */
654 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
656 if (priv->clipboard_text != NULL) {
657 g_free (priv->clipboard_text);
658 priv->clipboard_text = NULL;
661 if (priv->draft_msg != NULL) {
662 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
663 if (TNY_IS_HEADER (header)) {
664 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
665 modest_window_mgr_unregister_header (mgr, header);
667 g_object_unref (priv->draft_msg);
668 priv->draft_msg = NULL;
670 if (priv->outbox_msg != NULL) {
671 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
672 if (TNY_IS_HEADER (header)) {
673 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
674 modest_window_mgr_unregister_header (mgr, header);
676 g_object_unref (priv->outbox_msg);
677 priv->outbox_msg = NULL;
679 if (priv->msg_uid != NULL) {
680 g_free (priv->msg_uid);
681 priv->msg_uid = NULL;
684 /* This had to stay alive for as long as the combobox that used it: */
685 modest_pair_list_free (priv->from_field_protos);
687 G_OBJECT_CLASS(parent_class)->finalize (obj);
691 menubar_to_menu (GtkUIManager *ui_manager)
693 GtkWidget *main_menu;
697 /* Create new main menu */
698 main_menu = gtk_menu_new();
700 /* Get the menubar from the UI manager */
701 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
703 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
707 menu = GTK_WIDGET (iter->data);
708 gtk_widget_reparent(menu, main_menu);
710 iter = g_list_next (iter);
716 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
718 GdkPixbufLoader *loader;
721 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
726 tny_stream_reset (TNY_STREAM (stream));
727 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
728 unsigned char read_buffer[128];
730 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
731 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
735 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
736 g_object_ref (pixbuf);
737 gdk_pixbuf_loader_close (loader, NULL);
738 g_object_unref (loader);
740 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
741 GdkPixbuf *new_pixbuf;
743 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
744 gdk_pixbuf_get_width (pixbuf);
745 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
746 g_object_unref (pixbuf);
754 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
756 ModestMsgEditWindowPrivate *priv;
759 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
761 for (node = attachments; node != NULL; node = g_list_next (node)) {
762 TnyMimePart *part = (TnyMimePart *) node->data;
763 const gchar *cid = tny_mime_part_get_content_id (part);
764 const gchar *mime_type = tny_mime_part_get_content_type (part);
765 if ((cid != NULL)&&(mime_type != NULL)) {
766 TnyStream *stream = tny_mime_part_get_stream (part);
767 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
768 g_object_unref (stream);
770 if (pixbuf != NULL) {
771 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
772 g_object_unref (pixbuf);
779 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
781 TnyMimePart *parent = NULL;
782 const gchar *content_type = NULL;
783 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
785 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
787 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
788 parent = g_object_ref (msg);
789 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
790 TnyList *parts = TNY_LIST (tny_simple_list_new ());
793 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
794 iter = tny_list_create_iterator (parts);
795 while (!tny_iterator_is_done (iter)) {
797 part = TNY_MIME_PART (tny_iterator_get_current (iter));
798 content_type = tny_mime_part_get_content_type (part);
799 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
803 g_object_unref (part);
805 tny_iterator_next (iter);
807 g_object_unref (iter);
808 g_object_unref (parts);
811 if (parent != NULL) {
812 TnyList *parts = TNY_LIST (tny_simple_list_new ());
815 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
816 iter = tny_list_create_iterator (parts);
817 while (!tny_iterator_is_done (iter)) {
819 part = TNY_MIME_PART (tny_iterator_get_current (iter));
820 content_type = tny_mime_part_get_content_type (part);
821 if (content_type && g_str_has_prefix (content_type, "image/")) {
822 priv->images = g_list_prepend (priv->images, part);
824 g_object_unref (part);
826 tny_iterator_next (iter);
828 g_object_unref (iter);
829 g_object_unref (parts);
830 g_object_unref (parent);
835 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
838 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
840 for (node = attachments; node != NULL; node = g_list_next (node)) {
841 TnyMimePart *part = (TnyMimePart *) node->data;
842 const gchar *cid = tny_mime_part_get_content_id (part);
844 char *invalid = NULL;
845 gint int_cid = strtol (cid, &invalid, 10);
846 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
847 priv->last_cid = int_cid;
855 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
858 const gchar *to, *cc, *bcc, *subject;
860 ModestMsgEditWindowPrivate *priv;
862 TnyHeaderFlags priority_flags;
863 TnyFolder *msg_folder;
864 gboolean is_html = FALSE;
866 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
867 g_return_if_fail (TNY_IS_MSG (msg));
869 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
871 header = tny_msg_get_header (msg);
872 to = tny_header_get_to (header);
873 cc = tny_header_get_cc (header);
874 bcc = tny_header_get_bcc (header);
875 subject = tny_header_get_subject (header);
876 priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
879 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
881 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
882 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
883 gtk_widget_show (priv->cc_caption);
884 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
885 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
886 gtk_widget_hide (priv->cc_caption);
889 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
890 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
891 gtk_widget_show (priv->bcc_caption);
892 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
893 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
894 gtk_widget_hide (priv->bcc_caption);
897 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
898 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
901 update_window_title (self);
903 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
904 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
906 if ((body == NULL)||(body[0] == '\0')) {
908 body = modest_text_utils_convert_to_html ("");
911 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
912 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
915 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
918 /* Add attachments to the view */
919 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
920 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
921 if (priv->attachments == NULL) {
922 gtk_widget_hide (priv->attachments_caption);
924 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
925 gtk_widget_show_all (priv->attachments_caption);
927 get_related_images (self, msg);
928 update_last_cid (self, priv->attachments);
929 update_last_cid (self, priv->images);
930 replace_with_images (self, priv->images);
932 if (preserve_is_rich && !is_html) {
933 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
934 /* Get the default format required from configuration */
935 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
936 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
939 /* Set the default focus depending on having already a To: field or not */
940 if ((!to)||(*to == '\0')) {
941 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
943 gtk_widget_grab_focus (priv->msg_body);
946 /* TODO: lower priority, select in the From: combo to the
947 value that comes from msg <- not sure, should it be
950 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
952 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
953 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
955 modest_msg_edit_window_reset_modified (self);
957 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
958 text_buffer_can_undo (priv->text_buffer, FALSE, self);
959 text_buffer_can_redo (priv->text_buffer, FALSE, self);
962 g_free (priv->msg_uid);
963 priv->msg_uid = NULL;
966 /* we should set a reference to the incoming message if it is a draft */
967 msg_folder = tny_msg_get_folder (msg);
969 if (modest_tny_folder_is_local_folder (msg_folder)) {
970 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
971 if (type == TNY_FOLDER_TYPE_DRAFTS)
972 priv->draft_msg = g_object_ref(msg);
973 if (type == TNY_FOLDER_TYPE_OUTBOX)
974 priv->outbox_msg = g_object_ref(msg);
975 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
977 g_object_unref (msg_folder);
982 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
985 GList *item_children, *node;
986 GtkWidget *bin_child;
988 bin_child = gtk_bin_get_child (GTK_BIN(item));
990 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
992 for (node = item_children; node != NULL; node = g_list_next (node)) {
993 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
994 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
997 g_list_free (item_children);
1001 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1004 GList *item_children, *node;
1006 box = gtk_bin_get_child (GTK_BIN (item));
1007 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1008 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1010 for (node = item_children; node != NULL; node = g_list_next (node)) {
1011 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1012 if (GTK_IS_TOGGLE_BUTTON (node->data))
1013 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1014 else if (GTK_IS_BUTTON (node->data))
1015 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1017 g_list_free (item_children);
1022 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1024 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1025 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1026 GtkWidget *placeholder;
1027 GtkWidget *tool_item;
1032 GtkWidget *sizes_menu;
1033 GtkWidget *fonts_menu;
1034 GSList *radio_group = NULL;
1035 GSList *node = NULL;
1039 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1040 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1042 /* Font color placeholder */
1043 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1044 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1047 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1048 priv->font_color_button = hildon_color_button_new ();
1049 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1050 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1051 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1052 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1053 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1054 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1055 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1057 G_CALLBACK (modest_msg_edit_window_color_button_change),
1060 /* Font size and face placeholder */
1061 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1062 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1064 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1065 priv->size_tool_button_label = gtk_label_new (NULL);
1066 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1067 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1068 size_text,"</span>", NULL);
1069 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1071 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1072 sizes_menu = gtk_menu_new ();
1073 priv->size_items_group = NULL;
1075 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1076 GtkWidget *size_menu_item;
1078 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1079 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1080 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1081 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1082 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1083 gtk_widget_show (size_menu_item);
1085 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1089 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1090 GtkWidget *item = (GtkWidget *) node->data;
1091 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1095 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1096 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1097 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1098 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1099 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1100 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1101 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1102 priv->font_size_toolitem = tool_item;
1105 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1106 priv->font_tool_button_label = gtk_label_new (NULL);
1107 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1108 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1110 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1111 fonts_menu = gtk_menu_new ();
1112 priv->font_items_group = NULL;
1114 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1115 GtkWidget *font_menu_item;
1116 GtkWidget *child_label;
1118 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1119 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1120 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1121 wp_get_font_name (font_index), "</span>", NULL);
1122 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1125 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1126 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1127 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1128 gtk_widget_show (font_menu_item);
1130 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1133 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1134 GtkWidget *item = (GtkWidget *) node->data;
1135 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1138 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1139 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1140 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1141 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1142 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1143 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1144 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1145 priv->font_face_toolitem = tool_item;
1147 /* Set expand and homogeneous for remaining items */
1148 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1149 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1150 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1151 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1152 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1153 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1154 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1155 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1156 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1158 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1159 will not show the tool items added to the placeholders) */
1160 gtk_widget_show_all (parent_priv->toolbar);
1162 /* Set the no show all *after* showing all items. We do not
1163 want the toolbar to be shown with a show all because it
1164 could go agains the gconf setting regarding showing or not
1165 the toolbar of the editor window */
1166 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1172 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1175 ModestWindowPrivate *parent_priv;
1176 ModestMsgEditWindowPrivate *priv;
1177 GtkActionGroup *action_group;
1178 GError *error = NULL;
1179 GdkPixbuf *window_icon = NULL;
1182 ModestPair *account_pair = NULL;
1183 ModestDimmingRulesGroup *menu_rules_group = NULL;
1184 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1185 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1187 g_return_val_if_fail (msg, NULL);
1188 g_return_val_if_fail (account_name, NULL);
1190 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1192 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1193 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1195 parent_priv->ui_manager = gtk_ui_manager_new();
1196 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1197 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1199 /* Add common actions */
1200 gtk_action_group_add_actions (action_group,
1201 modest_msg_edit_action_entries,
1202 G_N_ELEMENTS (modest_msg_edit_action_entries),
1204 gtk_action_group_add_toggle_actions (action_group,
1205 modest_msg_edit_toggle_action_entries,
1206 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1208 gtk_action_group_add_radio_actions (action_group,
1209 modest_msg_edit_alignment_radio_action_entries,
1210 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1212 G_CALLBACK (modest_ui_actions_on_change_justify),
1214 gtk_action_group_add_radio_actions (action_group,
1215 modest_msg_edit_zoom_action_entries,
1216 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1218 G_CALLBACK (modest_ui_actions_on_change_zoom),
1220 gtk_action_group_add_radio_actions (action_group,
1221 modest_msg_edit_priority_action_entries,
1222 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1224 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1226 gtk_action_group_add_radio_actions (action_group,
1227 modest_msg_edit_file_format_action_entries,
1228 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1229 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1230 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1232 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1233 g_object_unref (action_group);
1235 /* Load the UI definition */
1236 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1238 if (error != NULL) {
1239 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1240 g_clear_error (&error);
1243 /* Add accelerators */
1244 gtk_window_add_accel_group (GTK_WINDOW (obj),
1245 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1247 /* Menubar. Update the state of some toggles */
1248 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1249 conf = modest_runtime_get_conf ();
1250 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1251 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1252 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1253 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1254 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1255 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1256 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1257 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1259 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1262 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1264 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1266 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1268 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1269 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1271 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1272 if (account_pair != NULL)
1273 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1275 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1276 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1277 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1278 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1279 /* Add common dimming rules */
1280 modest_dimming_rules_group_add_rules (menu_rules_group,
1281 modest_msg_edit_window_menu_dimming_entries,
1282 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1283 MODEST_WINDOW (obj));
1284 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1285 modest_msg_edit_window_toolbar_dimming_entries,
1286 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1287 MODEST_WINDOW (obj));
1288 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1289 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1290 MODEST_WINDOW (obj));
1291 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1292 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1293 MODEST_WINDOW (obj));
1294 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1295 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1296 MODEST_WINDOW (obj));
1297 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1298 modest_msg_edit_window_clipboard_dimming_entries,
1299 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1300 MODEST_WINDOW (obj));
1301 /* Insert dimming rules group for this window */
1302 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1303 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1304 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1305 /* Checks the dimming rules */
1306 g_object_unref (menu_rules_group);
1307 g_object_unref (toolbar_rules_group);
1308 g_object_unref (clipboard_rules_group);
1310 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1312 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1314 /* Set window icon */
1315 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1317 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1318 g_object_unref (window_icon);
1321 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1322 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1324 /* Dim at start clipboard actions */
1325 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1326 gtk_action_set_sensitive (action, FALSE);
1327 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1328 gtk_action_set_sensitive (action, FALSE);
1329 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1330 gtk_action_set_sensitive (action, FALSE);
1332 /* set initial state of cc and bcc */
1333 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1334 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1335 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1336 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1337 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1338 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1340 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1341 priv->update_caption_visibility = TRUE;
1343 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1345 /* Track account-removed signal, this window should be closed
1346 in the case we're creating a mail associated to the account
1348 priv->account_removed_handler_id =
1349 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1351 G_CALLBACK(on_account_removed),
1354 return (ModestWindow*) obj;
1358 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1360 GString **string_buffer = (GString **) user_data;
1362 *string_buffer = g_string_append (*string_buffer, buffer);
1368 * @result: A new string which should be freed with g_free().
1371 get_formatted_data (ModestMsgEditWindow *edit_window)
1373 ModestMsgEditWindowPrivate *priv;
1374 GString *string_buffer = g_string_new ("");
1376 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1378 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1380 return g_string_free (string_buffer, FALSE);
1385 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1388 const gchar *account_name;
1389 ModestMsgEditWindowPrivate *priv;
1391 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1393 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1395 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1396 g_return_val_if_fail (account_name, NULL);
1399 /* don't free these (except from) */
1400 data = g_slice_new0 (MsgData);
1401 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1403 data->account_name = g_strdup (account_name);
1404 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1405 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1406 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1407 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1408 if (priv->draft_msg) {
1409 data->draft_msg = g_object_ref (priv->draft_msg);
1410 } else if (priv->outbox_msg) {
1411 data->draft_msg = g_object_ref (priv->outbox_msg);
1413 data->draft_msg = NULL;
1416 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1418 gtk_text_buffer_get_bounds (buf, &b, &e);
1419 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1421 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1422 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1424 data->html_body = NULL;
1426 /* deep-copy the data */
1427 GList *cursor = priv->attachments;
1428 data->attachments = NULL;
1430 if (!(TNY_IS_MIME_PART(cursor->data))) {
1431 g_warning ("strange data in attachment list");
1432 cursor = g_list_next (cursor);
1435 data->attachments = g_list_append (data->attachments,
1436 g_object_ref (cursor->data));
1437 cursor = g_list_next (cursor);
1440 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1441 cursor = priv->images;
1442 data->images = NULL;
1445 if (!(TNY_IS_MIME_PART(cursor->data))) {
1446 g_warning ("strange data in attachment list");
1447 cursor = g_list_next (cursor);
1450 cid = tny_mime_part_get_content_id (cursor->data);
1452 gchar *image_tag_id;
1453 GtkTextTag *image_tag;
1455 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1456 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1457 g_free (image_tag_id);
1459 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1461 ((gtk_text_iter_has_tag (&iter, image_tag))||
1462 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1463 data->images = g_list_append (data->images,
1464 g_object_ref (cursor->data));
1466 cursor = g_list_next (cursor);
1469 data->priority_flags = priv->priority_flags;
1476 unref_gobject (GObject *obj, gpointer data)
1478 if (!G_IS_OBJECT(obj))
1480 g_object_unref (obj);
1484 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1487 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1495 g_free (data->subject);
1496 g_free (data->plain_body);
1497 g_free (data->html_body);
1498 g_free (data->account_name);
1500 if (data->draft_msg != NULL) {
1501 g_object_unref (data->draft_msg);
1502 data->draft_msg = NULL;
1505 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1506 g_list_free (data->attachments);
1507 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1508 g_list_free (data->images);
1510 g_slice_free (MsgData, data);
1514 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1517 ModestMsgEditWindowPrivate *priv = NULL;
1518 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1520 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1522 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1524 return MODEST_MSG_EDIT_FORMAT_HTML;
1526 return MODEST_MSG_EDIT_FORMAT_TEXT;
1530 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1531 ModestMsgEditFormat format)
1533 ModestMsgEditWindowPrivate *priv;
1535 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1536 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1539 case MODEST_MSG_EDIT_FORMAT_HTML:
1540 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1542 case MODEST_MSG_EDIT_FORMAT_TEXT:
1543 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1546 g_return_if_reached ();
1550 ModestMsgEditFormatState *
1551 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1553 ModestMsgEditFormatState *format_state = NULL;
1554 ModestMsgEditWindowPrivate *priv;
1555 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1557 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1558 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1560 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1562 format_state = g_new0 (ModestMsgEditFormatState, 1);
1563 format_state->bold = buffer_format->bold&0x1;
1564 format_state->italics = buffer_format->italic&0x1;
1565 format_state->bullet = buffer_format->bullet&0x1;
1566 format_state->color = buffer_format->color;
1567 format_state->font_size = buffer_format->font_size;
1568 format_state->font_family = wp_get_font_name (buffer_format->font);
1569 format_state->justification = buffer_format->justification;
1570 g_free (buffer_format);
1572 return format_state;
1577 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1578 const ModestMsgEditFormatState *format_state)
1580 ModestMsgEditWindowPrivate *priv;
1581 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1582 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1583 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1584 g_return_if_fail (format_state != NULL);
1586 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1587 gtk_widget_grab_focus (priv->msg_body);
1588 buffer_format->bold = (format_state->bold != FALSE);
1589 buffer_format->italic = (format_state->italics != FALSE);
1590 buffer_format->color = format_state->color;
1591 buffer_format->font_size = format_state->font_size;
1592 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1593 buffer_format->justification = format_state->justification;
1594 buffer_format->bullet = format_state->bullet;
1596 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1598 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1599 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1600 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1601 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1602 buffer_format->cs.font = (buffer_format->font != current_format->font);
1603 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1604 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1606 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1607 if (buffer_format->cs.bold) {
1608 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1610 if (buffer_format->cs.italic) {
1611 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1613 if (buffer_format->cs.color) {
1614 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1616 if (buffer_format->cs.font_size) {
1617 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1619 if (buffer_format->cs.justification) {
1620 switch (buffer_format->justification) {
1621 case GTK_JUSTIFY_LEFT:
1622 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1624 case GTK_JUSTIFY_CENTER:
1625 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1627 case GTK_JUSTIFY_RIGHT:
1628 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1635 if (buffer_format->cs.font) {
1636 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1638 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1639 if (buffer_format->cs.bullet) {
1640 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1642 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1644 g_free (current_format);
1649 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1651 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1653 ModestWindowPrivate *parent_priv;
1654 ModestMsgEditWindowPrivate *priv;
1655 GtkWidget *new_size_menuitem;
1656 GtkWidget *new_font_menuitem;
1658 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1659 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1661 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1662 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1663 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1664 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1666 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1667 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1668 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1671 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1673 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1674 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1676 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1677 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1679 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1680 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1682 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1683 G_CALLBACK (modest_msg_edit_window_color_button_change),
1685 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1686 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1687 G_CALLBACK (modest_msg_edit_window_color_button_change),
1690 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1691 buffer_format->font_size))->data);
1692 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1696 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1697 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1698 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1700 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1701 G_CALLBACK (modest_msg_edit_window_size_change),
1703 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1704 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1705 G_CALLBACK (modest_msg_edit_window_size_change),
1709 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1710 buffer_format->font))->data);
1711 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1715 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1716 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1717 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1719 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1720 G_CALLBACK (modest_msg_edit_window_font_change),
1722 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1723 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1724 G_CALLBACK (modest_msg_edit_window_font_change),
1728 g_free (buffer_format);
1734 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1737 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1738 ModestMsgEditWindowPrivate *priv;
1739 GtkWidget *dialog = NULL;
1741 const GdkColor *new_color = NULL;
1743 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1744 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1746 #ifdef MODEST_HILDON_VERSION_0
1747 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1748 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1750 dialog = hildon_color_chooser_new ();
1751 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1752 #endif /*MODEST_HILDON_VERSION_0*/
1753 g_free (buffer_format);
1755 response = gtk_dialog_run (GTK_DIALOG (dialog));
1757 case GTK_RESPONSE_OK: {
1758 #ifdef MODEST_HILDON_VERSION_0
1759 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1762 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1764 #endif /*MODEST_HILDON_VERSION_0*/
1771 gtk_widget_destroy (dialog);
1773 if (new_color != NULL)
1774 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1779 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1782 ModestMsgEditWindowPrivate *priv;
1783 GtkWidget *dialog = NULL;
1785 GdkColor *old_color = NULL;
1786 const GdkColor *new_color = NULL;
1788 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1789 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1791 #ifdef MODEST_HILDON_VERSION_0
1792 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1793 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1795 dialog = hildon_color_chooser_new ();
1796 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1797 #endif /*MODEST_HILDON_VERSION_9*/
1799 response = gtk_dialog_run (GTK_DIALOG (dialog));
1801 case GTK_RESPONSE_OK: {
1802 #ifdef MODEST_HILDON_VERSION_0
1803 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1806 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1808 #endif /*MODEST_HILDON_VERSION_0*/
1814 gtk_widget_destroy (dialog);
1816 if (new_color != NULL)
1817 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1821 static TnyStream* create_stream_for_uri (const gchar* uri)
1826 TnyStream *result = NULL;
1828 GnomeVFSHandle *handle = NULL;
1829 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1830 if (test == GNOME_VFS_OK) {
1831 /* Create the tinymail stream: */
1832 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1833 result = TNY_STREAM (tny_vfs_stream_new (handle));
1840 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1843 ModestMsgEditWindowPrivate *priv;
1844 GtkWidget *dialog = NULL;
1846 GSList *uris = NULL;
1847 GSList *uri_node = NULL;
1849 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1851 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1852 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1853 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1855 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1857 response = gtk_dialog_run (GTK_DIALOG (dialog));
1859 case GTK_RESPONSE_OK:
1860 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1865 gtk_widget_destroy (dialog);
1867 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1869 GnomeVFSHandle *handle = NULL;
1870 GnomeVFSResult result;
1871 GtkTextIter position;
1872 GtkTextMark *insert_mark;
1874 uri = (const gchar *) uri_node->data;
1875 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1876 if (result == GNOME_VFS_OK) {
1878 GnomeVFSFileInfo info;
1879 gchar *filename, *basename, *escaped_filename;
1880 TnyMimePart *mime_part;
1882 const gchar *mime_type = NULL;
1883 GnomeVFSURI *vfs_uri;
1885 vfs_uri = gnome_vfs_uri_new (uri);
1887 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1888 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1889 g_free (escaped_filename);
1890 gnome_vfs_uri_unref (vfs_uri);
1892 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1893 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1895 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1897 mime_part = tny_platform_factory_new_mime_part
1898 (modest_runtime_get_platform_factory ());
1900 TnyStream *stream = create_stream_for_uri (uri);
1901 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1903 content_id = g_strdup_printf ("%d", priv->last_cid);
1904 tny_mime_part_set_content_id (mime_part, content_id);
1905 g_free (content_id);
1908 basename = g_path_get_basename (filename);
1909 tny_mime_part_set_filename (mime_part, basename);
1912 pixbuf = pixbuf_from_stream (stream, mime_type);
1914 if (pixbuf != NULL) {
1915 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1916 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1917 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1920 priv->images = g_list_prepend (priv->images, mime_part);
1921 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1931 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1934 ModestMsgEditWindowPrivate *priv;
1935 GtkWidget *dialog = NULL;
1937 GSList *uris = NULL;
1940 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1942 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1943 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1944 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1946 response = gtk_dialog_run (GTK_DIALOG (dialog));
1948 case GTK_RESPONSE_OK:
1949 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1954 gtk_widget_destroy (dialog);
1956 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1957 const gchar *uri = (const gchar *) uri_node->data;
1958 modest_msg_edit_window_attach_file_one (window, uri);
1960 g_slist_foreach (uris, (GFunc) g_free, NULL);
1961 g_slist_free (uris);
1965 modest_msg_edit_window_attach_file_one (
1966 ModestMsgEditWindow *window,
1969 g_return_if_fail (window);
1970 g_return_if_fail (uri);
1972 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1975 GnomeVFSHandle *handle = NULL;
1976 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1977 if (result == GNOME_VFS_OK) {
1978 TnyMimePart *mime_part;
1980 const gchar *mime_type = NULL;
1982 gchar *escaped_filename;
1985 GnomeVFSFileInfo info;
1986 GnomeVFSURI *vfs_uri;
1988 vfs_uri = gnome_vfs_uri_new (uri);
1991 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1992 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1993 g_free (escaped_filename);
1994 gnome_vfs_uri_unref (vfs_uri);
1996 if (gnome_vfs_get_file_info (uri,
1998 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1999 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2001 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2002 mime_part = tny_platform_factory_new_mime_part
2003 (modest_runtime_get_platform_factory ());
2004 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2006 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2008 content_id = g_strdup_printf ("%d", priv->last_cid);
2009 tny_mime_part_set_content_id (mime_part, content_id);
2010 g_free (content_id);
2013 basename = g_path_get_basename (filename);
2014 tny_mime_part_set_filename (mime_part, basename);
2017 priv->attachments = g_list_prepend (priv->attachments, mime_part);
2018 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2020 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2021 gtk_widget_show_all (priv->attachments_caption);
2022 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2028 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2031 ModestMsgEditWindowPrivate *priv;
2032 gboolean clean_list = FALSE;
2034 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2035 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2037 if (att_list == NULL) {
2038 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2042 if (att_list == NULL) {
2043 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2045 GtkWidget *confirmation_dialog = NULL;
2046 gboolean dialog_response;
2048 gchar *message = NULL;
2049 const gchar *filename = NULL;
2051 if (att_list->next == NULL) {
2052 filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
2056 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2057 att_list->next == NULL), filename);
2058 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2060 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2061 gtk_widget_destroy (confirmation_dialog);
2062 if (!dialog_response) {
2064 g_list_free (att_list);
2067 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2069 for (node = att_list; node != NULL; node = g_list_next (node)) {
2070 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2071 const gchar *att_id;
2072 priv->attachments = g_list_remove (priv->attachments, mime_part);
2074 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2076 if (priv->attachments == NULL)
2077 gtk_widget_hide (priv->attachments_caption);
2078 att_id = tny_mime_part_get_content_id (mime_part);
2080 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2082 g_object_unref (mime_part);
2083 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2088 g_list_free (att_list);
2092 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2095 ModestMsgEditWindowPrivate *priv;
2096 GdkColor *new_color;
2097 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2099 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2100 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2103 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2105 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2107 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2109 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2114 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2117 ModestMsgEditWindowPrivate *priv;
2118 gint new_size_index;
2119 ModestMsgEditWindow *window;
2122 window = MODEST_MSG_EDIT_WINDOW (userdata);
2123 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2124 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2126 if (gtk_check_menu_item_get_active (menu_item)) {
2128 WPTextBufferFormat format;
2130 memset (&format, 0, sizeof (format));
2131 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2133 label = gtk_bin_get_child (GTK_BIN (menu_item));
2135 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2136 format.cs.font_size = TRUE;
2137 format.cs.text_position = TRUE;
2138 format.cs.font = TRUE;
2139 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2140 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2142 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2143 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2144 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2146 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2147 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2148 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2154 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2157 ModestMsgEditWindowPrivate *priv;
2158 gint new_font_index;
2159 ModestMsgEditWindow *window;
2162 window = MODEST_MSG_EDIT_WINDOW (userdata);
2163 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2164 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2166 if (gtk_check_menu_item_get_active (menu_item)) {
2169 label = gtk_bin_get_child (GTK_BIN (menu_item));
2171 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2173 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2174 (gpointer) new_font_index))
2175 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2177 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2178 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2179 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2185 modest_msg_edit_window_set_zoom (ModestWindow *window,
2188 ModestMsgEditWindowPrivate *priv;
2189 ModestWindowPrivate *parent_priv;
2190 GtkRadioAction *zoom_radio_action;
2192 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2194 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2195 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2196 priv->zoom_level = zoom;
2197 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2199 /* Zoom level menu options should be updated with the current zoom level */
2200 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2201 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2202 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2203 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2204 /* FIXME: Not availible before Gtk 2.10 */
2206 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2211 modest_msg_edit_window_get_zoom (ModestWindow *window)
2213 ModestMsgEditWindowPrivate *priv;
2215 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2217 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2218 return priv->zoom_level;
2222 zoom_allowed (ModestMsgEditWindow *window)
2226 focus = gtk_window_get_focus (GTK_WINDOW (window));
2227 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2231 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2233 ModestWindowPrivate *parent_priv;
2234 GtkRadioAction *zoom_radio_action;
2235 GSList *group, *node;
2237 /* First we check if the text view is focused. If not, zooming is not allowed */
2238 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2239 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2243 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2244 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2245 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2247 group = gtk_radio_action_get_group (zoom_radio_action);
2249 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2250 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2254 for (node = group; node != NULL; node = g_slist_next (node)) {
2255 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2256 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2264 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2266 ModestWindowPrivate *parent_priv;
2267 GtkRadioAction *zoom_radio_action;
2268 GSList *group, *node;
2270 /* First we check if the text view is focused. If not, zooming is not allowed */
2271 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2272 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2276 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2277 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2278 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2280 group = gtk_radio_action_get_group (zoom_radio_action);
2282 for (node = group; node != NULL; node = g_slist_next (node)) {
2283 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2284 if (node->next != NULL) {
2285 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2288 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2296 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2298 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2299 ModestWindowPrivate *parent_priv;
2300 ModestWindowMgr *mgr;
2301 gboolean is_fullscreen;
2302 GtkAction *fs_toggle_action;
2305 mgr = modest_runtime_get_window_mgr ();
2306 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2308 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2310 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2311 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2312 if (is_fullscreen != active)
2313 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2321 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2324 ModestMsgEditWindowPrivate *priv = NULL;
2325 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2327 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2328 if (!priv->update_caption_visibility)
2331 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2333 gtk_widget_show (priv->cc_caption);
2335 gtk_widget_hide (priv->cc_caption);
2337 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2341 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2344 ModestMsgEditWindowPrivate *priv = NULL;
2345 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2347 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2348 if (!priv->update_caption_visibility)
2351 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2353 gtk_widget_show (priv->bcc_caption);
2355 gtk_widget_hide (priv->bcc_caption);
2357 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2361 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2362 ModestRecptEditor *editor)
2364 ModestMsgEditWindowPrivate *priv;
2366 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2367 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2368 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2370 if (editor == NULL) {
2371 GtkWidget *view_focus;
2372 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2374 /* This code should be kept in sync with ModestRecptEditor. The
2375 textview inside the recpt editor is the one that really gets the
2376 focus. As it's inside a scrolled window, and this one inside the
2377 hbox recpt editor inherits from, we'll need to go up in the
2378 hierarchy to know if the text view is part of the recpt editor
2379 or if it's a different text entry */
2381 if (gtk_widget_get_parent (view_focus)) {
2382 GtkWidget *first_parent;
2384 first_parent = gtk_widget_get_parent (view_focus);
2385 if (gtk_widget_get_parent (first_parent) &&
2386 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2387 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2392 editor = MODEST_RECPT_EDITOR (priv->to_field);
2396 modest_address_book_select_addresses (editor);
2401 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2403 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2405 modest_msg_edit_window_open_addressbook (window, NULL);
2409 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2410 gboolean show_toolbar)
2412 ModestWindowPrivate *parent_priv;
2413 const gchar *action_name;
2416 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2417 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2419 /* We can not just use the code of
2420 modest_msg_edit_window_setup_toolbar because it has a
2421 mixture of both initialization and creation code. */
2423 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2425 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2427 /* Update also the actions (to update the toggles in the
2428 menus), we have to do it manually because some other window
2429 of the same time could have changed it (remember that the
2430 toolbar fullscreen mode is shared by all the windows of the
2432 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2433 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2435 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2437 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2438 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2444 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2445 TnyHeaderFlags priority_flags)
2447 ModestMsgEditWindowPrivate *priv;
2448 ModestWindowPrivate *parent_priv;
2450 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2452 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2453 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2454 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2456 if (priv->priority_flags != priority_flags) {
2457 GtkAction *priority_action = NULL;
2459 priv->priority_flags = priority_flags;
2461 switch (priority_flags) {
2462 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2463 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2464 gtk_widget_show (priv->priority_icon);
2465 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2466 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2468 case TNY_HEADER_FLAG_LOW_PRIORITY:
2469 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2470 gtk_widget_show (priv->priority_icon);
2471 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2472 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2475 gtk_widget_hide (priv->priority_icon);
2476 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2477 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2480 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2481 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2486 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2489 ModestMsgEditWindowPrivate *priv;
2490 ModestWindowPrivate *parent_priv;
2491 gint current_format;
2493 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2495 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2496 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2498 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2499 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2501 if (current_format != file_format) {
2502 switch (file_format) {
2503 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2504 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2505 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2507 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2511 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2512 response = gtk_dialog_run (GTK_DIALOG (dialog));
2513 gtk_widget_destroy (dialog);
2514 if (response == GTK_RESPONSE_OK) {
2515 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2517 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2518 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2523 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2528 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2531 ModestMsgEditWindowPrivate *priv;
2532 WPTextBufferFormat oldfmt, fmt;
2533 gint old_position = 0;
2537 GdkColor *color = NULL;
2538 gboolean bold, bold_set, italic, italic_set;
2539 gboolean underline, underline_set;
2540 gboolean strikethrough, strikethrough_set;
2541 gboolean position_set;
2542 gboolean font_size_set, font_set, color_set;
2545 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2548 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2550 /* First we get the currently selected font information */
2551 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2552 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2554 switch (oldfmt.text_position) {
2555 case TEXT_POSITION_NORMAL:
2558 case TEXT_POSITION_SUPERSCRIPT:
2566 g_object_set (G_OBJECT (dialog),
2567 "bold", oldfmt.bold != FALSE,
2568 "bold-set", !oldfmt.cs.bold,
2569 "underline", oldfmt.underline != FALSE,
2570 "underline-set", !oldfmt.cs.underline,
2571 "italic", oldfmt.italic != FALSE,
2572 "italic-set", !oldfmt.cs.italic,
2573 "strikethrough", oldfmt.strikethrough != FALSE,
2574 "strikethrough-set", !oldfmt.cs.strikethrough,
2575 "color", &oldfmt.color,
2576 "color-set", !oldfmt.cs.color,
2577 "size", wp_font_size[oldfmt.font_size],
2578 "size-set", !oldfmt.cs.font_size,
2579 "position", old_position,
2580 "position-set", !oldfmt.cs.text_position,
2581 "family", wp_get_font_name (oldfmt.font),
2582 "family-set", !oldfmt.cs.font,
2585 gtk_widget_show_all (dialog);
2586 response = gtk_dialog_run (GTK_DIALOG (dialog));
2587 if (response == GTK_RESPONSE_OK) {
2589 g_object_get( dialog,
2591 "bold-set", &bold_set,
2592 "underline", &underline,
2593 "underline-set", &underline_set,
2595 "italic-set", &italic_set,
2596 "strikethrough", &strikethrough,
2597 "strikethrough-set", &strikethrough_set,
2599 "color-set", &color_set,
2601 "size-set", &font_size_set,
2602 "family", &font_name,
2603 "family-set", &font_set,
2604 "position", &position,
2605 "position-set", &position_set,
2610 if (response == GTK_RESPONSE_OK) {
2611 memset(&fmt, 0, sizeof(fmt));
2617 fmt.italic = italic;
2618 fmt.cs.italic = TRUE;
2620 if (underline_set) {
2621 fmt.underline = underline;
2622 fmt.cs.underline = TRUE;
2624 if (strikethrough_set) {
2625 fmt.strikethrough = strikethrough;
2626 fmt.cs.strikethrough = TRUE;
2631 ? TEXT_POSITION_NORMAL
2632 : ( ( position == 1 )
2633 ? TEXT_POSITION_SUPERSCRIPT
2634 : TEXT_POSITION_SUBSCRIPT );
2635 fmt.cs.text_position = TRUE;
2639 fmt.cs.color = TRUE;
2642 fmt.font = wp_get_font_index(font_name,
2647 if (font_size_set) {
2648 fmt.font_size = wp_get_font_size_index(
2649 font_size, DEFAULT_FONT_SIZE);
2650 fmt.cs.font_size = TRUE;
2652 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2653 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2655 gtk_widget_destroy (dialog);
2657 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2661 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2663 ModestMsgEditWindowPrivate *priv;
2665 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2666 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2668 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2670 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2675 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2677 ModestMsgEditWindowPrivate *priv;
2679 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2680 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2682 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2684 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2689 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2691 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2693 priv->can_undo = can_undo;
2697 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2699 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2701 priv->can_redo = can_redo;
2705 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2707 ModestMsgEditWindowPrivate *priv;
2708 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2709 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2711 return priv->can_undo;
2715 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2717 ModestMsgEditWindowPrivate *priv;
2718 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2719 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2721 return priv->can_redo;
2726 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2729 GtkTextIter match_start, match_end;
2731 if (image_id == NULL)
2734 gtk_text_buffer_get_start_iter (buffer, &iter);
2736 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2737 GSList *tags = gtk_text_iter_get_tags (&match_start);
2739 for (node = tags; node != NULL; node = g_slist_next (node)) {
2740 GtkTextTag *tag = (GtkTextTag *) node->data;
2741 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2742 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2743 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2745 offset = gtk_text_iter_get_offset (&match_start);
2746 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2747 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2751 gtk_text_iter_forward_char (&iter);
2756 message_is_empty (ModestMsgEditWindow *window)
2758 ModestMsgEditWindowPrivate *priv = NULL;
2760 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2761 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2763 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2764 * so we can ignore markup.
2766 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2769 count = gtk_text_buffer_get_char_count (buf);
2775 msg_body_focus (GtkWidget *focus,
2776 GdkEventFocus *event,
2780 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2785 recpt_field_changed (GtkTextBuffer *buffer,
2786 ModestMsgEditWindow *editor)
2788 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2792 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2794 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2798 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2800 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2801 GtkTextBuffer *buffer;
2803 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2804 gtk_text_buffer_set_modified (buffer, FALSE);
2805 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2806 gtk_text_buffer_set_modified (buffer, FALSE);
2807 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2808 gtk_text_buffer_set_modified (buffer, FALSE);
2809 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2813 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2815 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2816 GtkTextBuffer *buffer;
2818 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2819 if (gtk_text_buffer_get_modified (buffer))
2821 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2822 if (gtk_text_buffer_get_modified (buffer))
2824 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2825 if (gtk_text_buffer_get_modified (buffer))
2827 if (gtk_text_buffer_get_modified (priv->text_buffer))
2837 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2839 ModestMsgEditWindowPrivate *priv = NULL;
2841 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2842 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2844 /* check if there's no recipient added */
2845 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2846 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2847 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2848 /* no recipient contents, then select contacts */
2849 modest_msg_edit_window_open_addressbook (window, NULL);
2853 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2854 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2857 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2858 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2861 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2862 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2866 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2867 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2868 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2875 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2876 ModestMsgEditWindow *window)
2878 modest_msg_edit_window_offer_attach_file (window);
2882 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2884 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2886 return priv->clipboard_text;
2890 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2892 ModestMsgEditWindow *window)
2894 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2895 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2897 if (!GTK_WIDGET_VISIBLE (window))
2900 text = gtk_clipboard_wait_for_text (selection_clipboard);
2902 if (priv->clipboard_text != NULL) {
2903 g_free (priv->clipboard_text);
2905 priv->clipboard_text = text;
2907 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2910 subject_field_move_cursor (GtkEntry *entry,
2911 GtkMovementStep step,
2916 if (!GTK_WIDGET_VISIBLE (window))
2919 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2923 update_window_title (ModestMsgEditWindow *window)
2925 ModestMsgEditWindowPrivate *priv = NULL;
2926 const gchar *subject;
2928 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2929 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2930 if (subject == NULL || subject[0] == '\0')
2931 subject = _("mail_va_new_email");
2933 gtk_window_set_title (GTK_WINDOW (window), subject);
2938 subject_field_changed (GtkEditable *editable,
2939 ModestMsgEditWindow *window)
2941 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2942 update_window_title (window);
2943 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2944 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2948 subject_field_insert_text (GtkEditable *editable,
2950 gint new_text_length,
2952 ModestMsgEditWindow *window)
2954 GString *result = g_string_new ("");
2956 gint result_len = 0;
2957 const gchar *entry_text = NULL;
2960 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2961 old_length = g_utf8_strlen (entry_text, -1);
2963 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2964 gunichar c = g_utf8_get_char_validated (current, 8);
2965 /* Invalid unichar, stop */
2971 result = g_string_append_unichar (result, c);
2975 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2976 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2979 /* Prevent endless recursion */
2980 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2981 g_signal_emit_by_name (editable, "insert-text",
2982 (gpointer) result->str, (gpointer) result->len,
2983 (gpointer) position, (gpointer) window);
2984 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2988 if (result_len + old_length > 1000) {
2989 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2990 dgettext("hildon-common-strings",
2991 "ckdg_ib_maximum_characters_reached"));
2994 g_string_free (result, TRUE);
2998 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3001 ModestMsgEditWindowPrivate *priv = NULL;
3003 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3004 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3006 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3009 gtk_widget_show_all (priv->find_toolbar);
3010 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3012 gtk_widget_hide_all (priv->find_toolbar);
3013 gtk_widget_grab_focus (priv->msg_body);
3019 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3021 GtkTextIter *match_start,
3022 GtkTextIter *match_end)
3024 GtkTextIter end_iter;
3025 gchar *str_casefold;
3028 gchar *range_casefold;
3031 gboolean result = FALSE;
3038 gtk_text_iter_forward_to_end (&end_iter);
3040 str_casefold = g_utf8_casefold (str, -1);
3041 str_chars_n = strlen (str);
3043 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3044 range_casefold = g_utf8_casefold (range_text, -1);
3045 range_chars_n = strlen (range_casefold);
3047 if (range_chars_n < str_chars_n) {
3048 g_free (str_casefold);
3049 g_free (range_text);
3050 g_free (range_casefold);
3054 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3055 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3056 if (!g_utf8_collate (range_subtext, str_casefold)) {
3057 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3059 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3060 match_start, match_end, NULL);
3061 g_free (found_text);
3063 g_free (range_subtext);
3067 g_free (str_casefold);
3068 g_free (range_text);
3069 g_free (range_casefold);
3076 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3077 ModestMsgEditWindow *window)
3079 gchar *current_search = NULL;
3080 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3082 GtkTextIter selection_start, selection_end;
3083 GtkTextIter match_start, match_end;
3084 gboolean continue_search = FALSE;
3086 if (message_is_empty (window)) {
3087 g_free (priv->last_search);
3088 priv->last_search = NULL;
3089 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3093 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3094 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3095 g_free (current_search);
3096 g_free (priv->last_search);
3097 priv->last_search = NULL;
3098 /* Information banner about empty search */
3099 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3103 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3104 continue_search = TRUE;
3106 g_free (priv->last_search);
3107 priv->last_search = g_strdup (current_search);
3110 if (continue_search) {
3111 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3112 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3113 &match_start, &match_end);
3115 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3117 GtkTextIter buffer_start;
3118 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3119 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3120 &match_start, &match_end);
3122 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3125 /* Mark as selected the string found in search */
3127 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3128 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3130 g_free (priv->last_search);
3131 priv->last_search = NULL;
3133 g_free (current_search);
3137 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3138 ModestMsgEditWindow *window)
3140 GtkToggleAction *toggle;
3141 ModestWindowPrivate *parent_priv;
3142 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3144 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3145 gtk_toggle_action_set_active (toggle, FALSE);
3149 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3151 ModestMsgEditWindowPrivate *priv;
3153 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3158 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3161 ModestMsgEditWindowPrivate *priv;
3163 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3169 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3172 ModestMsgEditWindowPrivate *priv;
3173 TnyHeader *header = NULL;
3175 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3176 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3178 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3179 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3181 if (priv->draft_msg != NULL) {
3182 header = tny_msg_get_header (priv->draft_msg);
3183 if (TNY_IS_HEADER (header)) {
3184 modest_window_mgr_unregister_header (mgr, header);
3186 g_object_unref (priv->draft_msg);
3189 if (draft != NULL) {
3190 g_object_ref (draft);
3191 header = tny_msg_get_header (draft);
3192 if (TNY_IS_HEADER (header))
3193 modest_window_mgr_register_header (mgr, header);
3194 if (priv->msg_uid) {
3195 g_free (priv->msg_uid);
3196 priv->msg_uid = NULL;
3198 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3201 priv->draft_msg = draft;
3205 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3206 GtkTextIter *start, GtkTextIter *end,
3209 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3210 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3213 if (tag == NULL+13) return;
3214 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3215 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3216 replace_with_images (window, priv->images);
3221 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3224 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3226 g_return_if_fail (TNY_IS_MIME_PART (part));
3227 priv->attachments = g_list_prepend (priv->attachments, part);
3228 g_object_ref (part);
3229 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3230 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3231 gtk_widget_show_all (priv->attachments_caption);
3232 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3236 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3238 ModestMsgEditWindowPrivate *priv;
3240 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3241 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3243 return priv->msg_uid;
3247 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3248 ModestMsgEditWindowWidgetType widget_type)
3250 ModestMsgEditWindowPrivate *priv;
3252 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3253 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3255 switch (widget_type) {
3256 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3257 return priv->msg_body;
3259 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3260 return priv->to_field;
3262 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3263 return priv->cc_field;
3265 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3266 return priv->bcc_field;
3268 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3269 return priv->subject_field;
3271 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3272 return priv->attachments_view;
3280 remove_tags (WPTextBuffer *buffer)
3282 GtkTextIter start, end;
3284 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3285 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3287 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3291 on_account_removed (TnyAccountStore *account_store,
3292 TnyAccount *account,
3295 /* Do nothing if it's a store account, because we use the
3296 transport to send the messages */
3297 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3298 const gchar *parent_acc = NULL;
3299 const gchar *our_acc = NULL;
3301 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3302 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3303 /* Close this window if I'm showing a message of the removed account */
3304 if (strcmp (parent_acc, our_acc) == 0)
3305 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));