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);
1732 #ifdef MODEST_HILDON_VERSION_0
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 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 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1747 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1748 g_free (buffer_format);
1750 response = gtk_dialog_run (GTK_DIALOG (dialog));
1752 case GTK_RESPONSE_OK: {
1753 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1759 gtk_widget_destroy (dialog);
1761 if (new_color != NULL) {
1762 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1763 /* FIXME: free new_color here? */
1768 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1771 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1772 ModestMsgEditWindowPrivate *priv;
1773 GtkWidget *dialog = NULL;
1775 const GdkColor *new_color = NULL;
1778 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1779 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1781 dialog = hildon_color_chooser_new ();
1782 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1783 g_free (buffer_format);
1785 response = gtk_dialog_run (GTK_DIALOG (dialog));
1787 case GTK_RESPONSE_OK: {
1788 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1796 gtk_widget_destroy (dialog);
1797 if (new_color != NULL)
1798 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1799 (gpointer) new_color);
1802 #endif /*!MODEST_HILDON_VERSION_0*/
1805 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1808 ModestMsgEditWindowPrivate *priv;
1809 GtkWidget *dialog = NULL;
1811 GdkColor *old_color = NULL;
1812 const GdkColor *new_color = NULL;
1814 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1815 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1817 #ifdef MODEST_HILDON_VERSION_0
1818 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1819 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1821 dialog = hildon_color_chooser_new ();
1822 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1823 #endif /*MODEST_HILDON_VERSION_9*/
1825 response = gtk_dialog_run (GTK_DIALOG (dialog));
1827 case GTK_RESPONSE_OK: {
1828 #ifdef MODEST_HILDON_VERSION_0
1829 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1832 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1834 #endif /*MODEST_HILDON_VERSION_0*/
1840 gtk_widget_destroy (dialog);
1842 if (new_color != NULL)
1843 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1847 static TnyStream* create_stream_for_uri (const gchar* uri)
1852 TnyStream *result = NULL;
1854 GnomeVFSHandle *handle = NULL;
1855 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1856 if (test == GNOME_VFS_OK) {
1857 /* Create the tinymail stream: */
1858 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1859 result = TNY_STREAM (tny_vfs_stream_new (handle));
1866 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1869 ModestMsgEditWindowPrivate *priv;
1870 GtkWidget *dialog = NULL;
1872 GSList *uris = NULL;
1873 GSList *uri_node = NULL;
1875 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1877 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1878 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1879 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1881 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1883 response = gtk_dialog_run (GTK_DIALOG (dialog));
1885 case GTK_RESPONSE_OK:
1886 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1891 gtk_widget_destroy (dialog);
1893 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1895 GnomeVFSHandle *handle = NULL;
1896 GnomeVFSResult result;
1897 GtkTextIter position;
1898 GtkTextMark *insert_mark;
1900 uri = (const gchar *) uri_node->data;
1901 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1902 if (result == GNOME_VFS_OK) {
1904 GnomeVFSFileInfo info;
1905 gchar *filename, *basename, *escaped_filename;
1906 TnyMimePart *mime_part;
1908 const gchar *mime_type = NULL;
1909 GnomeVFSURI *vfs_uri;
1911 vfs_uri = gnome_vfs_uri_new (uri);
1913 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1914 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1915 g_free (escaped_filename);
1916 gnome_vfs_uri_unref (vfs_uri);
1918 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1919 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1921 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1923 mime_part = tny_platform_factory_new_mime_part
1924 (modest_runtime_get_platform_factory ());
1926 TnyStream *stream = create_stream_for_uri (uri);
1927 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1929 content_id = g_strdup_printf ("%d", priv->last_cid);
1930 tny_mime_part_set_content_id (mime_part, content_id);
1931 g_free (content_id);
1934 basename = g_path_get_basename (filename);
1935 tny_mime_part_set_filename (mime_part, basename);
1938 pixbuf = pixbuf_from_stream (stream, mime_type);
1940 if (pixbuf != NULL) {
1941 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1942 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1943 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1946 priv->images = g_list_prepend (priv->images, mime_part);
1947 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1957 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1960 ModestMsgEditWindowPrivate *priv;
1961 GtkWidget *dialog = NULL;
1963 GSList *uris = NULL;
1966 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1968 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1969 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1970 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1972 response = gtk_dialog_run (GTK_DIALOG (dialog));
1974 case GTK_RESPONSE_OK:
1975 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1980 gtk_widget_destroy (dialog);
1982 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1983 const gchar *uri = (const gchar *) uri_node->data;
1984 modest_msg_edit_window_attach_file_one (window, uri);
1986 g_slist_foreach (uris, (GFunc) g_free, NULL);
1987 g_slist_free (uris);
1991 modest_msg_edit_window_attach_file_one (
1992 ModestMsgEditWindow *window,
1995 g_return_if_fail (window);
1996 g_return_if_fail (uri);
1998 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2001 GnomeVFSHandle *handle = NULL;
2002 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2003 if (result == GNOME_VFS_OK) {
2004 TnyMimePart *mime_part;
2006 const gchar *mime_type = NULL;
2008 gchar *escaped_filename;
2011 GnomeVFSFileInfo info;
2012 GnomeVFSURI *vfs_uri;
2014 vfs_uri = gnome_vfs_uri_new (uri);
2017 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2018 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2019 g_free (escaped_filename);
2020 gnome_vfs_uri_unref (vfs_uri);
2022 if (gnome_vfs_get_file_info (uri,
2024 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2025 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2027 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2028 mime_part = tny_platform_factory_new_mime_part
2029 (modest_runtime_get_platform_factory ());
2030 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2032 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2034 content_id = g_strdup_printf ("%d", priv->last_cid);
2035 tny_mime_part_set_content_id (mime_part, content_id);
2036 g_free (content_id);
2039 basename = g_path_get_basename (filename);
2040 tny_mime_part_set_filename (mime_part, basename);
2043 priv->attachments = g_list_prepend (priv->attachments, mime_part);
2044 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2046 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2047 gtk_widget_show_all (priv->attachments_caption);
2048 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2054 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2057 ModestMsgEditWindowPrivate *priv;
2058 gboolean clean_list = FALSE;
2060 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2061 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2063 if (att_list == NULL) {
2064 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2068 if (att_list == NULL) {
2069 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2071 GtkWidget *confirmation_dialog = NULL;
2072 gboolean dialog_response;
2074 gchar *message = NULL;
2075 gchar *filename = NULL;
2077 if (att_list->next == NULL) {
2078 if (TNY_IS_MSG (att_list->data)) {
2079 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2081 filename = g_strdup (tny_header_get_subject (header));
2082 g_object_unref (header);
2084 if (filename == NULL) {
2085 filename = g_strdup (_("mail_va_no_subject"));
2088 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2091 filename = g_strdup ("");
2093 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2094 att_list->next == NULL), filename);
2096 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2098 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2099 gtk_widget_destroy (confirmation_dialog);
2100 if (!dialog_response) {
2102 g_list_free (att_list);
2105 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2107 for (node = att_list; node != NULL; node = g_list_next (node)) {
2108 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2109 const gchar *att_id;
2110 priv->attachments = g_list_remove (priv->attachments, mime_part);
2112 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2114 if (priv->attachments == NULL)
2115 gtk_widget_hide (priv->attachments_caption);
2116 att_id = tny_mime_part_get_content_id (mime_part);
2118 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2120 g_object_unref (mime_part);
2121 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2126 g_list_free (att_list);
2130 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2133 ModestMsgEditWindowPrivate *priv;
2134 GdkColor *new_color;
2135 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2137 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2138 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2141 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2143 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2145 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2147 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2152 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2155 ModestMsgEditWindowPrivate *priv;
2156 gint new_size_index;
2157 ModestMsgEditWindow *window;
2160 window = MODEST_MSG_EDIT_WINDOW (userdata);
2161 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2162 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2164 if (gtk_check_menu_item_get_active (menu_item)) {
2166 WPTextBufferFormat format;
2168 memset (&format, 0, sizeof (format));
2169 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2171 label = gtk_bin_get_child (GTK_BIN (menu_item));
2173 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2174 format.cs.font_size = TRUE;
2175 format.cs.text_position = TRUE;
2176 format.cs.font = TRUE;
2177 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2178 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2180 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2181 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2182 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2184 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2185 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2186 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2192 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2195 ModestMsgEditWindowPrivate *priv;
2196 gint new_font_index;
2197 ModestMsgEditWindow *window;
2200 window = MODEST_MSG_EDIT_WINDOW (userdata);
2201 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2202 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2204 if (gtk_check_menu_item_get_active (menu_item)) {
2207 label = gtk_bin_get_child (GTK_BIN (menu_item));
2209 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2211 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2212 (gpointer) new_font_index))
2213 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2215 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2216 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2217 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2223 modest_msg_edit_window_set_zoom (ModestWindow *window,
2226 ModestMsgEditWindowPrivate *priv;
2227 ModestWindowPrivate *parent_priv;
2228 GtkRadioAction *zoom_radio_action;
2230 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2232 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2233 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2234 priv->zoom_level = zoom;
2235 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2237 /* Zoom level menu options should be updated with the current zoom level */
2238 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2239 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2240 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2241 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2242 /* FIXME: Not availible before Gtk 2.10 */
2244 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2249 modest_msg_edit_window_get_zoom (ModestWindow *window)
2251 ModestMsgEditWindowPrivate *priv;
2253 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2255 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2256 return priv->zoom_level;
2260 zoom_allowed (ModestMsgEditWindow *window)
2264 focus = gtk_window_get_focus (GTK_WINDOW (window));
2265 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2269 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2271 ModestWindowPrivate *parent_priv;
2272 GtkRadioAction *zoom_radio_action;
2273 GSList *group, *node;
2275 /* First we check if the text view is focused. If not, zooming is not allowed */
2276 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2277 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2281 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2282 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2283 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2285 group = gtk_radio_action_get_group (zoom_radio_action);
2287 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2288 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2292 for (node = group; node != NULL; node = g_slist_next (node)) {
2293 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2294 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2302 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2304 ModestWindowPrivate *parent_priv;
2305 GtkRadioAction *zoom_radio_action;
2306 GSList *group, *node;
2308 /* First we check if the text view is focused. If not, zooming is not allowed */
2309 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2310 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2314 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2315 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2316 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2318 group = gtk_radio_action_get_group (zoom_radio_action);
2320 for (node = group; node != NULL; node = g_slist_next (node)) {
2321 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2322 if (node->next != NULL) {
2323 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2326 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2334 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2336 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2337 ModestWindowPrivate *parent_priv;
2338 ModestWindowMgr *mgr;
2339 gboolean is_fullscreen;
2340 GtkAction *fs_toggle_action;
2343 mgr = modest_runtime_get_window_mgr ();
2344 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2346 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2348 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2349 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2350 if (is_fullscreen != active)
2351 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2359 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2362 ModestMsgEditWindowPrivate *priv = NULL;
2363 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2365 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2366 if (!priv->update_caption_visibility)
2369 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2371 gtk_widget_show (priv->cc_caption);
2373 gtk_widget_hide (priv->cc_caption);
2375 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2379 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2382 ModestMsgEditWindowPrivate *priv = NULL;
2383 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2385 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2386 if (!priv->update_caption_visibility)
2389 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2391 gtk_widget_show (priv->bcc_caption);
2393 gtk_widget_hide (priv->bcc_caption);
2395 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2399 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2400 ModestRecptEditor *editor)
2402 ModestMsgEditWindowPrivate *priv;
2404 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2405 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2406 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2408 if (editor == NULL) {
2409 GtkWidget *view_focus;
2410 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2412 /* This code should be kept in sync with ModestRecptEditor. The
2413 textview inside the recpt editor is the one that really gets the
2414 focus. As it's inside a scrolled window, and this one inside the
2415 hbox recpt editor inherits from, we'll need to go up in the
2416 hierarchy to know if the text view is part of the recpt editor
2417 or if it's a different text entry */
2419 if (gtk_widget_get_parent (view_focus)) {
2420 GtkWidget *first_parent;
2422 first_parent = gtk_widget_get_parent (view_focus);
2423 if (gtk_widget_get_parent (first_parent) &&
2424 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2425 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2430 editor = MODEST_RECPT_EDITOR (priv->to_field);
2434 modest_address_book_select_addresses (editor);
2439 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2441 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2443 modest_msg_edit_window_open_addressbook (window, NULL);
2447 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2448 gboolean show_toolbar)
2450 ModestWindowPrivate *parent_priv;
2451 const gchar *action_name;
2454 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2455 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2457 /* We can not just use the code of
2458 modest_msg_edit_window_setup_toolbar because it has a
2459 mixture of both initialization and creation code. */
2461 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2463 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2465 /* Update also the actions (to update the toggles in the
2466 menus), we have to do it manually because some other window
2467 of the same time could have changed it (remember that the
2468 toolbar fullscreen mode is shared by all the windows of the
2470 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2471 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2473 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2475 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2476 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2482 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2483 TnyHeaderFlags priority_flags)
2485 ModestMsgEditWindowPrivate *priv;
2486 ModestWindowPrivate *parent_priv;
2488 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2490 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2491 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2492 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2494 if (priv->priority_flags != priority_flags) {
2495 GtkAction *priority_action = NULL;
2497 priv->priority_flags = priority_flags;
2499 switch (priority_flags) {
2500 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2501 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2502 gtk_widget_show (priv->priority_icon);
2503 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2504 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2506 case TNY_HEADER_FLAG_LOW_PRIORITY:
2507 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2508 gtk_widget_show (priv->priority_icon);
2509 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2510 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2513 gtk_widget_hide (priv->priority_icon);
2514 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2515 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2518 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2519 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2524 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2527 ModestMsgEditWindowPrivate *priv;
2528 ModestWindowPrivate *parent_priv;
2529 gint current_format;
2531 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2533 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2534 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2536 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2537 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2539 if (current_format != file_format) {
2540 switch (file_format) {
2541 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2542 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2543 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2545 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2549 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2550 response = gtk_dialog_run (GTK_DIALOG (dialog));
2551 gtk_widget_destroy (dialog);
2552 if (response == GTK_RESPONSE_OK) {
2553 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2555 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2556 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2561 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2566 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2569 ModestMsgEditWindowPrivate *priv;
2570 WPTextBufferFormat oldfmt, fmt;
2571 gint old_position = 0;
2575 GdkColor *color = NULL;
2576 gboolean bold, bold_set, italic, italic_set;
2577 gboolean underline, underline_set;
2578 gboolean strikethrough, strikethrough_set;
2579 gboolean position_set;
2580 gboolean font_size_set, font_set, color_set;
2583 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2584 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2586 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2588 /* First we get the currently selected font information */
2589 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2590 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2592 switch (oldfmt.text_position) {
2593 case TEXT_POSITION_NORMAL:
2596 case TEXT_POSITION_SUPERSCRIPT:
2604 g_object_set (G_OBJECT (dialog),
2605 "bold", oldfmt.bold != FALSE,
2606 "bold-set", !oldfmt.cs.bold,
2607 "underline", oldfmt.underline != FALSE,
2608 "underline-set", !oldfmt.cs.underline,
2609 "italic", oldfmt.italic != FALSE,
2610 "italic-set", !oldfmt.cs.italic,
2611 "strikethrough", oldfmt.strikethrough != FALSE,
2612 "strikethrough-set", !oldfmt.cs.strikethrough,
2613 "color", &oldfmt.color,
2614 "color-set", !oldfmt.cs.color,
2615 "size", wp_font_size[oldfmt.font_size],
2616 "size-set", !oldfmt.cs.font_size,
2617 "position", old_position,
2618 "position-set", !oldfmt.cs.text_position,
2619 "family", wp_get_font_name (oldfmt.font),
2620 "family-set", !oldfmt.cs.font,
2623 gtk_widget_show_all (dialog);
2624 response = gtk_dialog_run (GTK_DIALOG (dialog));
2625 if (response == GTK_RESPONSE_OK) {
2627 g_object_get( dialog,
2629 "bold-set", &bold_set,
2630 "underline", &underline,
2631 "underline-set", &underline_set,
2633 "italic-set", &italic_set,
2634 "strikethrough", &strikethrough,
2635 "strikethrough-set", &strikethrough_set,
2637 "color-set", &color_set,
2639 "size-set", &font_size_set,
2640 "family", &font_name,
2641 "family-set", &font_set,
2642 "position", &position,
2643 "position-set", &position_set,
2648 if (response == GTK_RESPONSE_OK) {
2649 memset(&fmt, 0, sizeof(fmt));
2655 fmt.italic = italic;
2656 fmt.cs.italic = TRUE;
2658 if (underline_set) {
2659 fmt.underline = underline;
2660 fmt.cs.underline = TRUE;
2662 if (strikethrough_set) {
2663 fmt.strikethrough = strikethrough;
2664 fmt.cs.strikethrough = TRUE;
2669 ? TEXT_POSITION_NORMAL
2670 : ( ( position == 1 )
2671 ? TEXT_POSITION_SUPERSCRIPT
2672 : TEXT_POSITION_SUBSCRIPT );
2673 fmt.cs.text_position = TRUE;
2677 fmt.cs.color = TRUE;
2680 fmt.font = wp_get_font_index(font_name,
2685 if (font_size_set) {
2686 fmt.font_size = wp_get_font_size_index(
2687 font_size, DEFAULT_FONT_SIZE);
2688 fmt.cs.font_size = TRUE;
2690 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2691 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2693 gtk_widget_destroy (dialog);
2695 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2699 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2701 ModestMsgEditWindowPrivate *priv;
2703 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2704 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2706 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2708 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2713 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2715 ModestMsgEditWindowPrivate *priv;
2717 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2718 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2720 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2722 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2727 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2729 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2731 priv->can_undo = can_undo;
2735 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2737 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2739 priv->can_redo = can_redo;
2743 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2745 ModestMsgEditWindowPrivate *priv;
2746 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2747 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2749 return priv->can_undo;
2753 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2755 ModestMsgEditWindowPrivate *priv;
2756 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2757 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2759 return priv->can_redo;
2764 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2767 GtkTextIter match_start, match_end;
2769 if (image_id == NULL)
2772 gtk_text_buffer_get_start_iter (buffer, &iter);
2774 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2775 GSList *tags = gtk_text_iter_get_tags (&match_start);
2777 for (node = tags; node != NULL; node = g_slist_next (node)) {
2778 GtkTextTag *tag = (GtkTextTag *) node->data;
2779 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2780 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2781 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2783 offset = gtk_text_iter_get_offset (&match_start);
2784 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2785 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2789 gtk_text_iter_forward_char (&iter);
2794 message_is_empty (ModestMsgEditWindow *window)
2796 ModestMsgEditWindowPrivate *priv = NULL;
2798 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2799 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2801 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2802 * so we can ignore markup.
2804 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2807 count = gtk_text_buffer_get_char_count (buf);
2813 msg_body_focus (GtkWidget *focus,
2814 GdkEventFocus *event,
2818 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2823 recpt_field_changed (GtkTextBuffer *buffer,
2824 ModestMsgEditWindow *editor)
2826 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2830 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2832 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2836 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2838 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2839 GtkTextBuffer *buffer;
2841 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2842 gtk_text_buffer_set_modified (buffer, FALSE);
2843 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2844 gtk_text_buffer_set_modified (buffer, FALSE);
2845 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2846 gtk_text_buffer_set_modified (buffer, FALSE);
2847 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2851 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2853 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2854 GtkTextBuffer *buffer;
2856 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2857 if (gtk_text_buffer_get_modified (buffer))
2859 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2860 if (gtk_text_buffer_get_modified (buffer))
2862 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2863 if (gtk_text_buffer_get_modified (buffer))
2865 if (gtk_text_buffer_get_modified (priv->text_buffer))
2875 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2877 ModestMsgEditWindowPrivate *priv = NULL;
2879 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2880 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2882 /* check if there's no recipient added */
2883 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2884 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2885 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2886 /* no recipient contents, then select contacts */
2887 modest_msg_edit_window_open_addressbook (window, NULL);
2891 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2892 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2895 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2896 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2899 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2900 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2904 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2905 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2906 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2913 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2914 ModestMsgEditWindow *window)
2916 modest_msg_edit_window_offer_attach_file (window);
2920 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2922 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2924 return priv->clipboard_text;
2928 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2930 ModestMsgEditWindow *window)
2932 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2933 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2935 if (!GTK_WIDGET_VISIBLE (window))
2938 text = gtk_clipboard_wait_for_text (selection_clipboard);
2940 if (priv->clipboard_text != NULL) {
2941 g_free (priv->clipboard_text);
2943 priv->clipboard_text = text;
2945 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2948 subject_field_move_cursor (GtkEntry *entry,
2949 GtkMovementStep step,
2954 if (!GTK_WIDGET_VISIBLE (window))
2957 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2961 update_window_title (ModestMsgEditWindow *window)
2963 ModestMsgEditWindowPrivate *priv = NULL;
2964 const gchar *subject;
2966 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2967 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2968 if (subject == NULL || subject[0] == '\0')
2969 subject = _("mail_va_new_email");
2971 gtk_window_set_title (GTK_WINDOW (window), subject);
2976 subject_field_changed (GtkEditable *editable,
2977 ModestMsgEditWindow *window)
2979 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2980 update_window_title (window);
2981 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2982 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2986 subject_field_insert_text (GtkEditable *editable,
2988 gint new_text_length,
2990 ModestMsgEditWindow *window)
2992 GString *result = g_string_new ("");
2994 gint result_len = 0;
2995 const gchar *entry_text = NULL;
2998 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2999 old_length = g_utf8_strlen (entry_text, -1);
3001 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3002 gunichar c = g_utf8_get_char_validated (current, 8);
3003 /* Invalid unichar, stop */
3009 result = g_string_append_unichar (result, c);
3013 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3014 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3017 /* Prevent endless recursion */
3018 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3019 g_signal_emit_by_name (editable, "insert-text",
3020 (gpointer) result->str, (gpointer) result->len,
3021 (gpointer) position, (gpointer) window);
3022 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3026 if (result_len + old_length > 1000) {
3027 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3028 dgettext("hildon-common-strings",
3029 "ckdg_ib_maximum_characters_reached"));
3032 g_string_free (result, TRUE);
3036 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3039 ModestMsgEditWindowPrivate *priv = NULL;
3041 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3042 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3044 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3047 gtk_widget_show_all (priv->find_toolbar);
3048 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3050 gtk_widget_hide_all (priv->find_toolbar);
3051 gtk_widget_grab_focus (priv->msg_body);
3057 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3059 GtkTextIter *match_start,
3060 GtkTextIter *match_end)
3062 GtkTextIter end_iter;
3063 gchar *str_casefold;
3066 gchar *range_casefold;
3069 gboolean result = FALSE;
3076 gtk_text_iter_forward_to_end (&end_iter);
3078 str_casefold = g_utf8_casefold (str, -1);
3079 str_chars_n = strlen (str);
3081 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3082 range_casefold = g_utf8_casefold (range_text, -1);
3083 range_chars_n = strlen (range_casefold);
3085 if (range_chars_n < str_chars_n) {
3086 g_free (str_casefold);
3087 g_free (range_text);
3088 g_free (range_casefold);
3092 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3093 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3094 if (!g_utf8_collate (range_subtext, str_casefold)) {
3095 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3097 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3098 match_start, match_end, NULL);
3099 g_free (found_text);
3101 g_free (range_subtext);
3105 g_free (str_casefold);
3106 g_free (range_text);
3107 g_free (range_casefold);
3114 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3115 ModestMsgEditWindow *window)
3117 gchar *current_search = NULL;
3118 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3120 GtkTextIter selection_start, selection_end;
3121 GtkTextIter match_start, match_end;
3122 gboolean continue_search = FALSE;
3124 if (message_is_empty (window)) {
3125 g_free (priv->last_search);
3126 priv->last_search = NULL;
3127 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3131 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3132 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3133 g_free (current_search);
3134 g_free (priv->last_search);
3135 priv->last_search = NULL;
3136 /* Information banner about empty search */
3137 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3141 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3142 continue_search = TRUE;
3144 g_free (priv->last_search);
3145 priv->last_search = g_strdup (current_search);
3148 if (continue_search) {
3149 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3150 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3151 &match_start, &match_end);
3153 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3155 GtkTextIter buffer_start;
3156 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3157 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3158 &match_start, &match_end);
3160 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3163 /* Mark as selected the string found in search */
3165 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3166 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3168 g_free (priv->last_search);
3169 priv->last_search = NULL;
3171 g_free (current_search);
3175 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3176 ModestMsgEditWindow *window)
3178 GtkToggleAction *toggle;
3179 ModestWindowPrivate *parent_priv;
3180 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3182 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3183 gtk_toggle_action_set_active (toggle, FALSE);
3187 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3189 ModestMsgEditWindowPrivate *priv;
3191 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3196 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3199 ModestMsgEditWindowPrivate *priv;
3201 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3207 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3210 ModestMsgEditWindowPrivate *priv;
3211 TnyHeader *header = NULL;
3213 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3214 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3216 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3217 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3219 if (priv->draft_msg != NULL) {
3220 modest_window_mgr_unregister_window (mgr, MODEST_WINDOW (window));
3221 g_object_unref (priv->draft_msg);
3224 if (draft != NULL) {
3225 g_object_ref (draft);
3226 header = tny_msg_get_header (draft);
3227 if (priv->msg_uid) {
3228 g_free (priv->msg_uid);
3229 priv->msg_uid = NULL;
3231 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3232 if (GTK_WIDGET_REALIZED (window))
3233 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3236 priv->draft_msg = draft;
3240 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3241 GtkTextIter *start, GtkTextIter *end,
3244 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3245 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3248 if (tag == NULL+13) return;
3249 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3250 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3251 replace_with_images (window, priv->images);
3256 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3259 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3261 g_return_if_fail (TNY_IS_MIME_PART (part));
3262 priv->attachments = g_list_prepend (priv->attachments, part);
3263 g_object_ref (part);
3264 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3265 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3266 gtk_widget_show_all (priv->attachments_caption);
3267 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3271 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3273 ModestMsgEditWindowPrivate *priv;
3275 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3276 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3278 return priv->msg_uid;
3282 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3283 ModestMsgEditWindowWidgetType widget_type)
3285 ModestMsgEditWindowPrivate *priv;
3287 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3288 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3290 switch (widget_type) {
3291 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3292 return priv->msg_body;
3294 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3295 return priv->to_field;
3297 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3298 return priv->cc_field;
3300 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3301 return priv->bcc_field;
3303 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3304 return priv->subject_field;
3306 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3307 return priv->attachments_view;
3315 remove_tags (WPTextBuffer *buffer)
3317 GtkTextIter start, end;
3319 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3320 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3322 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3326 on_account_removed (TnyAccountStore *account_store,
3327 TnyAccount *account,
3330 /* Do nothing if it's a store account, because we use the
3331 transport to send the messages */
3332 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3333 const gchar *parent_acc = NULL;
3334 const gchar *our_acc = NULL;
3336 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3337 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3338 /* Close this window if I'm showing a message of the removed account */
3339 if (strcmp (parent_acc, our_acc) == 0)
3340 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));