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;
385 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
386 GTK_WINDOW(obj),"applications_email_editor");
390 /* FIXME: this is a dup from the one in gtk/ */
393 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
395 static ModestPairList*
396 get_transports (void)
398 GSList *transports = NULL;
400 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
401 GSList *accounts = modest_account_mgr_account_names (account_mgr,
402 TRUE /* only enabled accounts. */);
404 GSList *cursor = accounts;
406 gchar *account_name = cursor->data;
407 gchar *from_string = NULL;
409 from_string = modest_account_mgr_get_from_string (account_mgr,
413 if (from_string && account_name) {
414 gchar *name = account_name;
415 ModestPair *pair = modest_pair_new ((gpointer) name,
416 (gpointer) from_string , TRUE);
417 transports = g_slist_prepend (transports, pair);
420 cursor = cursor->next;
422 g_slist_free (accounts); /* only free the accounts, not the elements,
423 * because they are used in the pairlist */
427 void vadj_changed (GtkAdjustment *adj,
428 ModestMsgEditWindow *window)
430 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
432 GdkRectangle rectangle, cursor_rectangle;
433 GtkTextIter position;
437 /* We detect if cursor is visible using the full height, not only the center. This
439 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
440 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
442 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
443 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
445 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
446 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
448 if (gtk_widget_is_focus (priv->msg_body) &&
450 if (priv->last_vadj_upper != adj->upper) {
453 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
454 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
455 insert, 0.1, FALSE, 0.0, 0.0);
458 priv->last_vadj_upper = adj->upper;
463 init_window (ModestMsgEditWindow *obj)
465 GtkWidget *from_caption, *to_caption, *subject_caption;
466 GtkWidget *main_vbox;
467 ModestMsgEditWindowPrivate *priv;
469 GtkSizeGroup *size_group;
471 GtkWidget *subject_box;
472 GtkWidget *attachment_icon;
473 GtkWidget *window_box;
474 #if (GTK_MINOR_VERSION >= 10)
475 GdkAtom deserialize_type;
477 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
479 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
481 /* Note: This ModestPairList* must exist for as long as the combo
482 * that uses it, because the ModestComboBox uses the ID opaquely,
483 * so it can't know how to manage its memory. */
484 priv->from_field_protos = get_transports ();
486 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
488 priv->to_field = modest_recpt_editor_new ();
489 priv->cc_field = modest_recpt_editor_new ();
490 priv->bcc_field = modest_recpt_editor_new ();
491 subject_box = gtk_hbox_new (FALSE, 0);
492 priv->priority_icon = gtk_image_new ();
493 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
494 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
495 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
496 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
497 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
498 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
499 priv->add_attachment_button = gtk_button_new ();
500 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
501 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
502 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
503 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
504 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
505 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
506 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
507 priv->attachments_view = modest_attachments_view_new (NULL);
509 priv->header_box = gtk_vbox_new (FALSE, 0);
511 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
512 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
513 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
514 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
515 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
516 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
517 g_object_unref (size_group);
519 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
520 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
521 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
522 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
523 gtk_size_group_add_widget (size_group, priv->subject_field);
524 gtk_size_group_add_widget (size_group, priv->attachments_view);
525 g_object_unref (size_group);
527 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
528 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
529 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
530 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
531 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
532 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
533 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
536 priv->msg_body = wp_text_view_new ();
537 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
538 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
539 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
540 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
541 #if (GTK_MINOR_VERSION >= 10)
542 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
543 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
545 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
546 deserialize_type, TRUE);
548 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
550 priv->find_toolbar = hildon_find_toolbar_new (NULL);
551 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
553 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
555 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
556 G_CALLBACK (text_buffer_refresh_attributes), obj);
557 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
558 G_CALLBACK (text_buffer_can_undo), obj);
559 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
560 G_CALLBACK (text_buffer_can_redo), obj);
561 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
562 G_CALLBACK (body_changed), obj);
563 g_signal_connect (G_OBJECT (obj), "window-state-event",
564 G_CALLBACK (modest_msg_edit_window_window_state_event),
566 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
567 G_CALLBACK (text_buffer_apply_tag), obj);
568 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
569 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
570 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
571 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
572 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
573 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
575 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
576 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
578 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
579 G_CALLBACK (msg_body_focus), obj);
580 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
581 G_CALLBACK (msg_body_focus), obj);
582 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
583 "changed", G_CALLBACK (recpt_field_changed), obj);
584 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
585 "changed", G_CALLBACK (recpt_field_changed), obj);
586 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
587 "changed", G_CALLBACK (recpt_field_changed), obj);
588 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
589 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
590 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
592 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
593 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
595 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
596 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
597 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
598 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
600 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
602 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
603 frame = gtk_frame_new (NULL);
604 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
606 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
607 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
608 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
610 G_CALLBACK (vadj_changed),
612 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
614 window_box = gtk_vbox_new (FALSE, 0);
615 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
616 gtk_container_add (GTK_CONTAINER(obj), window_box);
617 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
618 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
620 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
621 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
622 priv->default_clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
623 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
628 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
630 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
632 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
633 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
634 priv->clipboard_change_handler_id))
635 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
636 priv->clipboard_change_handler_id);
637 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
638 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
639 priv->default_clipboard_change_handler_id))
640 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
641 priv->default_clipboard_change_handler_id);
643 if (priv->account_removed_handler_id &&
644 g_signal_handler_is_connected (modest_runtime_get_account_store (),
645 priv->account_removed_handler_id))
646 g_signal_handler_disconnect(modest_runtime_get_account_store (),
647 priv->account_removed_handler_id);
651 modest_msg_edit_window_finalize (GObject *obj)
653 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
655 /* Sanity check: shouldn't be needed, the window mgr should
656 call this function before */
657 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
659 if (priv->clipboard_text != NULL) {
660 g_free (priv->clipboard_text);
661 priv->clipboard_text = NULL;
664 if (priv->draft_msg != NULL) {
665 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
666 if (TNY_IS_HEADER (header)) {
667 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
668 modest_window_mgr_unregister_header (mgr, header);
670 g_object_unref (priv->draft_msg);
671 priv->draft_msg = NULL;
673 if (priv->outbox_msg != NULL) {
674 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
675 if (TNY_IS_HEADER (header)) {
676 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
677 modest_window_mgr_unregister_header (mgr, header);
679 g_object_unref (priv->outbox_msg);
680 priv->outbox_msg = NULL;
682 if (priv->msg_uid != NULL) {
683 g_free (priv->msg_uid);
684 priv->msg_uid = NULL;
687 /* This had to stay alive for as long as the combobox that used it: */
688 modest_pair_list_free (priv->from_field_protos);
690 G_OBJECT_CLASS(parent_class)->finalize (obj);
694 menubar_to_menu (GtkUIManager *ui_manager)
696 GtkWidget *main_menu;
700 /* Create new main menu */
701 main_menu = gtk_menu_new();
703 /* Get the menubar from the UI manager */
704 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
706 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
710 menu = GTK_WIDGET (iter->data);
711 gtk_widget_reparent(menu, main_menu);
713 iter = g_list_next (iter);
719 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
721 GdkPixbufLoader *loader;
724 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
729 tny_stream_reset (TNY_STREAM (stream));
730 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
731 unsigned char read_buffer[128];
733 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
734 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
738 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
739 g_object_ref (pixbuf);
740 gdk_pixbuf_loader_close (loader, NULL);
741 g_object_unref (loader);
743 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
744 GdkPixbuf *new_pixbuf;
746 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
747 gdk_pixbuf_get_width (pixbuf);
748 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
749 g_object_unref (pixbuf);
757 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
759 ModestMsgEditWindowPrivate *priv;
762 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
764 for (node = attachments; node != NULL; node = g_list_next (node)) {
765 TnyMimePart *part = (TnyMimePart *) node->data;
766 const gchar *cid = tny_mime_part_get_content_id (part);
767 const gchar *mime_type = tny_mime_part_get_content_type (part);
768 if ((cid != NULL)&&(mime_type != NULL)) {
769 TnyStream *stream = tny_mime_part_get_stream (part);
770 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
771 g_object_unref (stream);
773 if (pixbuf != NULL) {
774 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
775 g_object_unref (pixbuf);
782 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
784 TnyMimePart *parent = NULL;
785 const gchar *content_type = NULL;
786 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
788 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
790 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
791 parent = g_object_ref (msg);
792 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
793 TnyList *parts = TNY_LIST (tny_simple_list_new ());
796 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
797 iter = tny_list_create_iterator (parts);
798 while (!tny_iterator_is_done (iter)) {
800 part = TNY_MIME_PART (tny_iterator_get_current (iter));
801 content_type = tny_mime_part_get_content_type (part);
802 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
806 g_object_unref (part);
808 tny_iterator_next (iter);
810 g_object_unref (iter);
811 g_object_unref (parts);
814 if (parent != NULL) {
815 TnyList *parts = TNY_LIST (tny_simple_list_new ());
818 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
819 iter = tny_list_create_iterator (parts);
820 while (!tny_iterator_is_done (iter)) {
822 part = TNY_MIME_PART (tny_iterator_get_current (iter));
823 content_type = tny_mime_part_get_content_type (part);
824 if (content_type && g_str_has_prefix (content_type, "image/")) {
825 priv->images = g_list_prepend (priv->images, part);
827 g_object_unref (part);
829 tny_iterator_next (iter);
831 g_object_unref (iter);
832 g_object_unref (parts);
833 g_object_unref (parent);
838 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
841 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
843 for (node = attachments; node != NULL; node = g_list_next (node)) {
844 TnyMimePart *part = (TnyMimePart *) node->data;
845 const gchar *cid = tny_mime_part_get_content_id (part);
847 char *invalid = NULL;
848 gint int_cid = strtol (cid, &invalid, 10);
849 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
850 priv->last_cid = int_cid;
858 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
861 const gchar *to, *cc, *bcc, *subject;
863 ModestMsgEditWindowPrivate *priv;
865 TnyHeaderFlags priority_flags;
866 TnyFolder *msg_folder;
867 gboolean is_html = FALSE;
869 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
870 g_return_if_fail (TNY_IS_MSG (msg));
872 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
874 header = tny_msg_get_header (msg);
875 to = tny_header_get_to (header);
876 cc = tny_header_get_cc (header);
877 bcc = tny_header_get_bcc (header);
878 subject = tny_header_get_subject (header);
879 priority_flags = tny_header_get_priority (header);
882 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
884 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
885 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
886 gtk_widget_show (priv->cc_caption);
887 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
888 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
889 gtk_widget_hide (priv->cc_caption);
892 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
893 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
894 gtk_widget_show (priv->bcc_caption);
895 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
896 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
897 gtk_widget_hide (priv->bcc_caption);
900 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
901 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
904 update_window_title (self);
906 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
907 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
909 if ((body == NULL)||(body[0] == '\0')) {
911 body = modest_text_utils_convert_to_html ("");
914 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
915 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
918 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
921 /* Add attachments to the view */
922 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
923 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
924 if (priv->attachments == NULL) {
925 gtk_widget_hide (priv->attachments_caption);
927 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
928 gtk_widget_show_all (priv->attachments_caption);
930 get_related_images (self, msg);
931 update_last_cid (self, priv->attachments);
932 update_last_cid (self, priv->images);
933 replace_with_images (self, priv->images);
935 if (preserve_is_rich && !is_html) {
936 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
937 /* Get the default format required from configuration */
938 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
939 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
942 /* Set the default focus depending on having already a To: field or not */
943 if ((!to)||(*to == '\0')) {
944 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
946 gtk_widget_grab_focus (priv->msg_body);
949 /* TODO: lower priority, select in the From: combo to the
950 value that comes from msg <- not sure, should it be
953 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
955 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
956 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
958 modest_msg_edit_window_reset_modified (self);
960 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
961 text_buffer_can_undo (priv->text_buffer, FALSE, self);
962 text_buffer_can_redo (priv->text_buffer, FALSE, self);
965 g_free (priv->msg_uid);
966 priv->msg_uid = NULL;
969 /* we should set a reference to the incoming message if it is a draft */
970 msg_folder = tny_msg_get_folder (msg);
972 if (modest_tny_folder_is_local_folder (msg_folder)) {
973 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
974 if (type == TNY_FOLDER_TYPE_INVALID)
975 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
977 if (type == TNY_FOLDER_TYPE_DRAFTS)
978 priv->draft_msg = g_object_ref(msg);
979 if (type == TNY_FOLDER_TYPE_OUTBOX)
980 priv->outbox_msg = g_object_ref(msg);
981 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
983 g_object_unref (msg_folder);
988 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
991 GList *item_children, *node;
992 GtkWidget *bin_child;
994 bin_child = gtk_bin_get_child (GTK_BIN(item));
996 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
998 for (node = item_children; node != NULL; node = g_list_next (node)) {
999 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1000 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1003 g_list_free (item_children);
1007 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1010 GList *item_children, *node;
1012 box = gtk_bin_get_child (GTK_BIN (item));
1013 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1014 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1016 for (node = item_children; node != NULL; node = g_list_next (node)) {
1017 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1018 if (GTK_IS_TOGGLE_BUTTON (node->data))
1019 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1020 else if (GTK_IS_BUTTON (node->data))
1021 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1023 g_list_free (item_children);
1028 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1030 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1031 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1032 GtkWidget *placeholder;
1033 GtkWidget *tool_item;
1038 GtkWidget *sizes_menu;
1039 GtkWidget *fonts_menu;
1040 GSList *radio_group = NULL;
1041 GSList *node = NULL;
1045 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1046 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1048 /* Font color placeholder */
1049 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1050 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1053 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1054 priv->font_color_button = hildon_color_button_new ();
1055 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1056 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1057 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1058 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1059 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1060 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1061 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1063 G_CALLBACK (modest_msg_edit_window_color_button_change),
1066 /* Font size and face placeholder */
1067 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1068 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1070 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1071 priv->size_tool_button_label = gtk_label_new (NULL);
1072 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1073 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1074 size_text,"</span>", NULL);
1075 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1077 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1078 sizes_menu = gtk_menu_new ();
1079 priv->size_items_group = NULL;
1081 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1082 GtkWidget *size_menu_item;
1084 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1085 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1086 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1087 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1088 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1089 gtk_widget_show (size_menu_item);
1091 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1095 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1096 GtkWidget *item = (GtkWidget *) node->data;
1097 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1101 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1102 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1103 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1104 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1105 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1106 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1107 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1108 priv->font_size_toolitem = tool_item;
1111 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1112 priv->font_tool_button_label = gtk_label_new (NULL);
1113 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1114 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1116 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1117 fonts_menu = gtk_menu_new ();
1118 priv->font_items_group = NULL;
1120 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1121 GtkWidget *font_menu_item;
1122 GtkWidget *child_label;
1124 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1125 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1126 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1127 wp_get_font_name (font_index), "</span>", NULL);
1128 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1131 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1132 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1133 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1134 gtk_widget_show (font_menu_item);
1136 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1139 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1140 GtkWidget *item = (GtkWidget *) node->data;
1141 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1144 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1145 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1146 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1147 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1148 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1149 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1150 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1151 priv->font_face_toolitem = tool_item;
1153 /* Set expand and homogeneous for remaining items */
1154 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1155 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1156 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1157 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1158 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1159 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1160 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1161 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1162 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1164 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1165 will not show the tool items added to the placeholders) */
1166 gtk_widget_show_all (parent_priv->toolbar);
1168 /* Set the no show all *after* showing all items. We do not
1169 want the toolbar to be shown with a show all because it
1170 could go agains the gconf setting regarding showing or not
1171 the toolbar of the editor window */
1172 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1178 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1181 ModestWindowPrivate *parent_priv;
1182 ModestMsgEditWindowPrivate *priv;
1183 GtkActionGroup *action_group;
1184 GError *error = NULL;
1185 GdkPixbuf *window_icon = NULL;
1188 ModestPair *account_pair = NULL;
1189 ModestDimmingRulesGroup *menu_rules_group = NULL;
1190 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1191 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1193 g_return_val_if_fail (msg, NULL);
1194 g_return_val_if_fail (account_name, NULL);
1196 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1198 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1199 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1201 parent_priv->ui_manager = gtk_ui_manager_new();
1202 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1203 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1205 /* Add common actions */
1206 gtk_action_group_add_actions (action_group,
1207 modest_msg_edit_action_entries,
1208 G_N_ELEMENTS (modest_msg_edit_action_entries),
1210 gtk_action_group_add_toggle_actions (action_group,
1211 modest_msg_edit_toggle_action_entries,
1212 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1214 gtk_action_group_add_radio_actions (action_group,
1215 modest_msg_edit_alignment_radio_action_entries,
1216 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1218 G_CALLBACK (modest_ui_actions_on_change_justify),
1220 gtk_action_group_add_radio_actions (action_group,
1221 modest_msg_edit_zoom_action_entries,
1222 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1224 G_CALLBACK (modest_ui_actions_on_change_zoom),
1226 gtk_action_group_add_radio_actions (action_group,
1227 modest_msg_edit_priority_action_entries,
1228 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1230 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1232 gtk_action_group_add_radio_actions (action_group,
1233 modest_msg_edit_file_format_action_entries,
1234 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1235 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1236 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1238 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1239 g_object_unref (action_group);
1241 /* Load the UI definition */
1242 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1244 if (error != NULL) {
1245 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1246 g_clear_error (&error);
1249 /* Add accelerators */
1250 gtk_window_add_accel_group (GTK_WINDOW (obj),
1251 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1253 /* Menubar. Update the state of some toggles */
1254 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1255 conf = modest_runtime_get_conf ();
1256 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1257 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1258 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1259 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1260 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1261 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1262 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1263 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1265 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1268 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1270 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1272 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1274 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1275 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1277 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1278 if (account_pair != NULL)
1279 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1281 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1282 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1283 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1284 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1285 /* Add common dimming rules */
1286 modest_dimming_rules_group_add_rules (menu_rules_group,
1287 modest_msg_edit_window_menu_dimming_entries,
1288 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1289 MODEST_WINDOW (obj));
1290 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1291 modest_msg_edit_window_toolbar_dimming_entries,
1292 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1293 MODEST_WINDOW (obj));
1294 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1295 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1296 MODEST_WINDOW (obj));
1297 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1298 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1299 MODEST_WINDOW (obj));
1300 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1301 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1302 MODEST_WINDOW (obj));
1303 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1304 modest_msg_edit_window_clipboard_dimming_entries,
1305 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1306 MODEST_WINDOW (obj));
1307 /* Insert dimming rules group for this window */
1308 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1309 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1310 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1311 /* Checks the dimming rules */
1312 g_object_unref (menu_rules_group);
1313 g_object_unref (toolbar_rules_group);
1314 g_object_unref (clipboard_rules_group);
1316 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1318 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1320 /* Set window icon */
1321 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1323 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1324 g_object_unref (window_icon);
1327 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1328 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1330 /* Dim at start clipboard actions */
1331 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1332 gtk_action_set_sensitive (action, FALSE);
1333 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1334 gtk_action_set_sensitive (action, FALSE);
1335 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1336 gtk_action_set_sensitive (action, FALSE);
1338 /* set initial state of cc and bcc */
1339 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1340 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1341 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1342 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1343 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1344 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1346 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1347 priv->update_caption_visibility = TRUE;
1349 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1351 /* Track account-removed signal, this window should be closed
1352 in the case we're creating a mail associated to the account
1354 priv->account_removed_handler_id =
1355 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1357 G_CALLBACK(on_account_removed),
1360 return (ModestWindow*) obj;
1364 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1366 GString **string_buffer = (GString **) user_data;
1368 *string_buffer = g_string_append (*string_buffer, buffer);
1374 * @result: A new string which should be freed with g_free().
1377 get_formatted_data (ModestMsgEditWindow *edit_window)
1379 ModestMsgEditWindowPrivate *priv;
1380 GString *string_buffer = g_string_new ("");
1382 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1384 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1386 return g_string_free (string_buffer, FALSE);
1391 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1394 const gchar *account_name;
1395 ModestMsgEditWindowPrivate *priv;
1397 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1399 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1401 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1402 g_return_val_if_fail (account_name, NULL);
1405 /* don't free these (except from) */
1406 data = g_slice_new0 (MsgData);
1407 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1409 data->account_name = g_strdup (account_name);
1410 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1411 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1412 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1413 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1414 if (priv->draft_msg) {
1415 data->draft_msg = g_object_ref (priv->draft_msg);
1416 } else if (priv->outbox_msg) {
1417 data->draft_msg = g_object_ref (priv->outbox_msg);
1419 data->draft_msg = NULL;
1422 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1424 gtk_text_buffer_get_bounds (buf, &b, &e);
1425 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1427 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1428 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1430 data->html_body = NULL;
1432 /* deep-copy the data */
1433 GList *cursor = priv->attachments;
1434 data->attachments = NULL;
1436 if (!(TNY_IS_MIME_PART(cursor->data))) {
1437 g_warning ("strange data in attachment list");
1438 cursor = g_list_next (cursor);
1441 data->attachments = g_list_append (data->attachments,
1442 g_object_ref (cursor->data));
1443 cursor = g_list_next (cursor);
1446 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1447 cursor = priv->images;
1448 data->images = NULL;
1451 if (!(TNY_IS_MIME_PART(cursor->data))) {
1452 g_warning ("strange data in attachment list");
1453 cursor = g_list_next (cursor);
1456 cid = tny_mime_part_get_content_id (cursor->data);
1458 gchar *image_tag_id;
1459 GtkTextTag *image_tag;
1461 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1462 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1463 g_free (image_tag_id);
1465 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1467 ((gtk_text_iter_has_tag (&iter, image_tag))||
1468 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1469 data->images = g_list_append (data->images,
1470 g_object_ref (cursor->data));
1472 cursor = g_list_next (cursor);
1475 data->priority_flags = priv->priority_flags;
1482 unref_gobject (GObject *obj, gpointer data)
1484 if (!G_IS_OBJECT(obj))
1486 g_object_unref (obj);
1490 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1493 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1501 g_free (data->from);
1502 g_free (data->subject);
1503 g_free (data->plain_body);
1504 g_free (data->html_body);
1505 g_free (data->account_name);
1507 if (data->draft_msg != NULL) {
1508 g_object_unref (data->draft_msg);
1509 data->draft_msg = NULL;
1512 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1513 g_list_free (data->attachments);
1514 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1515 g_list_free (data->images);
1517 g_slice_free (MsgData, data);
1521 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1524 ModestMsgEditWindowPrivate *priv = NULL;
1525 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1527 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1529 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1531 return MODEST_MSG_EDIT_FORMAT_HTML;
1533 return MODEST_MSG_EDIT_FORMAT_TEXT;
1537 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1538 ModestMsgEditFormat format)
1540 ModestMsgEditWindowPrivate *priv;
1542 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1543 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1546 case MODEST_MSG_EDIT_FORMAT_HTML:
1547 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1549 case MODEST_MSG_EDIT_FORMAT_TEXT:
1550 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1553 g_return_if_reached ();
1557 ModestMsgEditFormatState *
1558 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1560 ModestMsgEditFormatState *format_state = NULL;
1561 ModestMsgEditWindowPrivate *priv;
1562 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1564 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1565 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1567 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1569 format_state = g_new0 (ModestMsgEditFormatState, 1);
1570 format_state->bold = buffer_format->bold&0x1;
1571 format_state->italics = buffer_format->italic&0x1;
1572 format_state->bullet = buffer_format->bullet&0x1;
1573 format_state->color = buffer_format->color;
1574 format_state->font_size = buffer_format->font_size;
1575 format_state->font_family = wp_get_font_name (buffer_format->font);
1576 format_state->justification = buffer_format->justification;
1577 g_free (buffer_format);
1579 return format_state;
1584 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1585 const ModestMsgEditFormatState *format_state)
1587 ModestMsgEditWindowPrivate *priv;
1588 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1589 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1590 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1591 g_return_if_fail (format_state != NULL);
1593 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1594 gtk_widget_grab_focus (priv->msg_body);
1595 buffer_format->bold = (format_state->bold != FALSE);
1596 buffer_format->italic = (format_state->italics != FALSE);
1597 buffer_format->color = format_state->color;
1598 buffer_format->font_size = format_state->font_size;
1599 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1600 buffer_format->justification = format_state->justification;
1601 buffer_format->bullet = format_state->bullet;
1603 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1605 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1606 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1607 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1608 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1609 buffer_format->cs.font = (buffer_format->font != current_format->font);
1610 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1611 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1613 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1614 if (buffer_format->cs.bold) {
1615 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1617 if (buffer_format->cs.italic) {
1618 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1620 if (buffer_format->cs.color) {
1621 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1623 if (buffer_format->cs.font_size) {
1624 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1626 if (buffer_format->cs.justification) {
1627 switch (buffer_format->justification) {
1628 case GTK_JUSTIFY_LEFT:
1629 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1631 case GTK_JUSTIFY_CENTER:
1632 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1634 case GTK_JUSTIFY_RIGHT:
1635 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1642 if (buffer_format->cs.font) {
1643 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1645 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1646 if (buffer_format->cs.bullet) {
1647 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1649 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1651 g_free (current_format);
1656 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1658 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1660 ModestWindowPrivate *parent_priv;
1661 ModestMsgEditWindowPrivate *priv;
1662 GtkWidget *new_size_menuitem;
1663 GtkWidget *new_font_menuitem;
1665 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1666 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1668 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1669 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1670 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1671 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1673 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1674 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1675 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1678 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1680 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1681 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1683 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1684 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1686 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1687 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1689 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1690 G_CALLBACK (modest_msg_edit_window_color_button_change),
1692 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1693 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1694 G_CALLBACK (modest_msg_edit_window_color_button_change),
1697 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1698 buffer_format->font_size))->data);
1699 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1703 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1704 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1705 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1707 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1708 G_CALLBACK (modest_msg_edit_window_size_change),
1710 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1711 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1712 G_CALLBACK (modest_msg_edit_window_size_change),
1716 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1717 buffer_format->font))->data);
1718 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1722 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1723 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1724 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1726 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1727 G_CALLBACK (modest_msg_edit_window_font_change),
1729 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1730 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1731 G_CALLBACK (modest_msg_edit_window_font_change),
1735 g_free (buffer_format);
1739 #ifdef MODEST_HILDON_VERSION_0
1741 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1744 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1745 ModestMsgEditWindowPrivate *priv;
1746 GtkWidget *dialog = NULL;
1748 GdkColor *new_color = NULL;
1750 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1751 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1753 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1754 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1755 g_free (buffer_format);
1757 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1758 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1759 if (new_color != NULL) {
1760 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1761 (gpointer) new_color);
1764 gtk_widget_destroy (dialog);
1769 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1772 ModestMsgEditWindowPrivate *priv;
1773 GtkWidget *dialog = NULL;
1775 GdkColor *old_color = NULL;
1776 const GdkColor *new_color = NULL;
1778 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1779 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1781 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1782 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1784 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1785 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1786 if (new_color != NULL)
1787 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1789 gtk_widget_destroy (dialog);
1795 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1798 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1799 ModestMsgEditWindowPrivate *priv;
1800 GtkWidget *dialog = NULL;
1802 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1803 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1805 dialog = hildon_color_chooser_new ();
1806 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1807 g_free (buffer_format);
1809 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1811 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1812 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1815 gtk_widget_destroy (dialog);
1820 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1823 ModestMsgEditWindowPrivate *priv;
1824 GtkWidget *dialog = NULL;
1825 GdkColor *old_color = NULL;
1827 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1828 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1830 dialog = hildon_color_chooser_new ();
1831 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1833 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1835 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1836 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1838 gtk_widget_destroy (dialog);
1841 #endif /*!MODEST_HILDON_VERSION_0*/
1845 static TnyStream* create_stream_for_uri (const gchar* uri)
1850 TnyStream *result = NULL;
1852 GnomeVFSHandle *handle = NULL;
1853 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1854 if (test == GNOME_VFS_OK) {
1855 /* Create the tinymail stream: */
1856 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1857 result = TNY_STREAM (tny_vfs_stream_new (handle));
1864 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1867 ModestMsgEditWindowPrivate *priv;
1868 GtkWidget *dialog = NULL;
1870 GSList *uris = NULL;
1871 GSList *uri_node = NULL;
1873 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1875 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1876 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1877 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1879 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1881 response = gtk_dialog_run (GTK_DIALOG (dialog));
1883 case GTK_RESPONSE_OK:
1884 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1889 gtk_widget_destroy (dialog);
1891 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1893 GnomeVFSHandle *handle = NULL;
1894 GnomeVFSResult result;
1895 GtkTextIter position;
1896 GtkTextMark *insert_mark;
1898 uri = (const gchar *) uri_node->data;
1899 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1900 if (result == GNOME_VFS_OK) {
1902 GnomeVFSFileInfo info;
1903 gchar *filename, *basename, *escaped_filename;
1904 TnyMimePart *mime_part;
1906 const gchar *mime_type = NULL;
1907 GnomeVFSURI *vfs_uri;
1909 vfs_uri = gnome_vfs_uri_new (uri);
1911 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1912 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1913 g_free (escaped_filename);
1914 gnome_vfs_uri_unref (vfs_uri);
1916 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1917 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1919 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1921 mime_part = tny_platform_factory_new_mime_part
1922 (modest_runtime_get_platform_factory ());
1924 TnyStream *stream = create_stream_for_uri (uri);
1925 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1927 content_id = g_strdup_printf ("%d", priv->last_cid);
1928 tny_mime_part_set_content_id (mime_part, content_id);
1929 g_free (content_id);
1932 basename = g_path_get_basename (filename);
1933 tny_mime_part_set_filename (mime_part, basename);
1936 pixbuf = pixbuf_from_stream (stream, mime_type);
1938 if (pixbuf != NULL) {
1939 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1940 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1941 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1944 priv->images = g_list_prepend (priv->images, mime_part);
1945 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1955 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1957 GtkWidget *dialog = NULL;
1959 GSList *uris = NULL;
1962 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1963 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1964 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1966 response = gtk_dialog_run (GTK_DIALOG (dialog));
1968 case GTK_RESPONSE_OK:
1969 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1974 gtk_widget_destroy (dialog);
1976 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1977 const gchar *uri = (const gchar *) uri_node->data;
1978 modest_msg_edit_window_attach_file_one (window, uri);
1980 g_slist_foreach (uris, (GFunc) g_free, NULL);
1981 g_slist_free (uris);
1985 modest_msg_edit_window_attach_file_one (
1986 ModestMsgEditWindow *window,
1989 g_return_if_fail (window);
1990 g_return_if_fail (uri);
1992 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1995 GnomeVFSHandle *handle = NULL;
1996 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1997 if (result == GNOME_VFS_OK) {
1998 TnyMimePart *mime_part;
2000 const gchar *mime_type = NULL;
2002 gchar *escaped_filename;
2005 GnomeVFSFileInfo info;
2006 GnomeVFSURI *vfs_uri;
2008 vfs_uri = gnome_vfs_uri_new (uri);
2011 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2012 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2013 g_free (escaped_filename);
2014 gnome_vfs_uri_unref (vfs_uri);
2016 if (gnome_vfs_get_file_info (uri,
2018 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2019 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2021 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2022 mime_part = tny_platform_factory_new_mime_part
2023 (modest_runtime_get_platform_factory ());
2024 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2026 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2028 content_id = g_strdup_printf ("%d", priv->last_cid);
2029 tny_mime_part_set_content_id (mime_part, content_id);
2030 g_free (content_id);
2033 basename = g_path_get_basename (filename);
2034 tny_mime_part_set_filename (mime_part, basename);
2037 priv->attachments = g_list_prepend (priv->attachments, mime_part);
2038 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2040 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2041 gtk_widget_show_all (priv->attachments_caption);
2042 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2048 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2051 ModestMsgEditWindowPrivate *priv;
2052 gboolean clean_list = FALSE;
2054 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2055 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2057 if (att_list == NULL) {
2058 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2062 if (att_list == NULL) {
2063 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2065 GtkWidget *confirmation_dialog = NULL;
2066 gboolean dialog_response;
2068 gchar *message = NULL;
2069 gchar *filename = NULL;
2071 if (att_list->next == NULL) {
2072 if (TNY_IS_MSG (att_list->data)) {
2073 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2075 filename = g_strdup (tny_header_get_subject (header));
2076 g_object_unref (header);
2078 if (filename == NULL) {
2079 filename = g_strdup (_("mail_va_no_subject"));
2082 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2085 filename = g_strdup ("");
2087 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2088 att_list->next == NULL), filename);
2090 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2092 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2093 gtk_widget_destroy (confirmation_dialog);
2094 if (!dialog_response) {
2096 g_list_free (att_list);
2099 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2101 for (node = att_list; node != NULL; node = g_list_next (node)) {
2102 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2103 const gchar *att_id;
2104 priv->attachments = g_list_remove (priv->attachments, mime_part);
2106 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2108 if (priv->attachments == NULL)
2109 gtk_widget_hide (priv->attachments_caption);
2110 att_id = tny_mime_part_get_content_id (mime_part);
2112 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2114 g_object_unref (mime_part);
2115 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2120 g_list_free (att_list);
2124 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2127 ModestMsgEditWindowPrivate *priv;
2128 GdkColor *new_color;
2129 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2131 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2132 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2135 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2137 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2139 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2141 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2146 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2149 ModestMsgEditWindowPrivate *priv;
2150 gint new_size_index;
2151 ModestMsgEditWindow *window;
2154 window = MODEST_MSG_EDIT_WINDOW (userdata);
2155 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2156 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2158 if (gtk_check_menu_item_get_active (menu_item)) {
2160 WPTextBufferFormat format;
2162 memset (&format, 0, sizeof (format));
2163 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2165 label = gtk_bin_get_child (GTK_BIN (menu_item));
2167 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2168 format.cs.font_size = TRUE;
2169 format.cs.text_position = TRUE;
2170 format.cs.font = TRUE;
2171 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2172 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2174 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2175 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2176 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2178 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2179 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2180 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2186 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2189 ModestMsgEditWindowPrivate *priv;
2190 gint new_font_index;
2191 ModestMsgEditWindow *window;
2194 window = MODEST_MSG_EDIT_WINDOW (userdata);
2195 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2196 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2198 if (gtk_check_menu_item_get_active (menu_item)) {
2201 label = gtk_bin_get_child (GTK_BIN (menu_item));
2203 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2205 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2206 (gpointer) new_font_index))
2207 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2209 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2210 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2211 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2217 modest_msg_edit_window_set_zoom (ModestWindow *window,
2220 ModestMsgEditWindowPrivate *priv;
2221 ModestWindowPrivate *parent_priv;
2222 GtkRadioAction *zoom_radio_action;
2224 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2226 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2227 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2228 priv->zoom_level = zoom;
2229 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2231 /* Zoom level menu options should be updated with the current zoom level */
2232 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2233 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2234 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2235 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2236 /* FIXME: Not availible before Gtk 2.10 */
2238 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2243 modest_msg_edit_window_get_zoom (ModestWindow *window)
2245 ModestMsgEditWindowPrivate *priv;
2247 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2249 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2250 return priv->zoom_level;
2254 zoom_allowed (ModestMsgEditWindow *window)
2258 focus = gtk_window_get_focus (GTK_WINDOW (window));
2259 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2263 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2265 ModestWindowPrivate *parent_priv;
2266 GtkRadioAction *zoom_radio_action;
2267 GSList *group, *node;
2269 /* First we check if the text view is focused. If not, zooming is not allowed */
2270 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2271 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2275 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2276 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2277 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2279 group = gtk_radio_action_get_group (zoom_radio_action);
2281 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2282 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2286 for (node = group; node != NULL; node = g_slist_next (node)) {
2287 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2288 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2296 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2298 ModestWindowPrivate *parent_priv;
2299 GtkRadioAction *zoom_radio_action;
2300 GSList *group, *node;
2302 /* First we check if the text view is focused. If not, zooming is not allowed */
2303 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2304 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2308 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2309 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2310 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2312 group = gtk_radio_action_get_group (zoom_radio_action);
2314 for (node = group; node != NULL; node = g_slist_next (node)) {
2315 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2316 if (node->next != NULL) {
2317 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2320 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2328 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2330 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2331 ModestWindowPrivate *parent_priv;
2332 ModestWindowMgr *mgr;
2333 gboolean is_fullscreen;
2334 GtkAction *fs_toggle_action;
2337 mgr = modest_runtime_get_window_mgr ();
2338 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2340 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2342 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2343 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2344 if (is_fullscreen != active)
2345 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2353 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2356 ModestMsgEditWindowPrivate *priv = NULL;
2357 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2359 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2360 if (!priv->update_caption_visibility)
2363 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2365 gtk_widget_show (priv->cc_caption);
2367 gtk_widget_hide (priv->cc_caption);
2369 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2373 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2376 ModestMsgEditWindowPrivate *priv = NULL;
2377 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2379 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2380 if (!priv->update_caption_visibility)
2383 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2385 gtk_widget_show (priv->bcc_caption);
2387 gtk_widget_hide (priv->bcc_caption);
2389 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2393 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2394 ModestRecptEditor *editor)
2396 ModestMsgEditWindowPrivate *priv;
2398 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2399 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2400 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2402 if (editor == NULL) {
2403 GtkWidget *view_focus;
2404 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2406 /* This code should be kept in sync with ModestRecptEditor. The
2407 textview inside the recpt editor is the one that really gets the
2408 focus. As it's inside a scrolled window, and this one inside the
2409 hbox recpt editor inherits from, we'll need to go up in the
2410 hierarchy to know if the text view is part of the recpt editor
2411 or if it's a different text entry */
2413 if (gtk_widget_get_parent (view_focus)) {
2414 GtkWidget *first_parent;
2416 first_parent = gtk_widget_get_parent (view_focus);
2417 if (gtk_widget_get_parent (first_parent) &&
2418 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2419 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2424 editor = MODEST_RECPT_EDITOR (priv->to_field);
2428 modest_address_book_select_addresses (editor);
2433 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2435 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2437 modest_msg_edit_window_open_addressbook (window, NULL);
2441 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2442 gboolean show_toolbar)
2444 ModestWindowPrivate *parent_priv;
2445 const gchar *action_name;
2448 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2449 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2451 /* We can not just use the code of
2452 modest_msg_edit_window_setup_toolbar because it has a
2453 mixture of both initialization and creation code. */
2455 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2457 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2459 /* Update also the actions (to update the toggles in the
2460 menus), we have to do it manually because some other window
2461 of the same time could have changed it (remember that the
2462 toolbar fullscreen mode is shared by all the windows of the
2464 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2465 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2467 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2469 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2470 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2476 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2477 TnyHeaderFlags priority_flags)
2479 ModestMsgEditWindowPrivate *priv;
2480 ModestWindowPrivate *parent_priv;
2482 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2484 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2485 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2487 if (priv->priority_flags != priority_flags) {
2488 GtkAction *priority_action = NULL;
2490 priv->priority_flags = priority_flags;
2492 switch (priority_flags) {
2493 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2494 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2495 gtk_widget_show (priv->priority_icon);
2496 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2497 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2499 case TNY_HEADER_FLAG_LOW_PRIORITY:
2500 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2501 gtk_widget_show (priv->priority_icon);
2502 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2503 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2506 gtk_widget_hide (priv->priority_icon);
2507 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2508 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2511 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2512 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2517 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2520 ModestMsgEditWindowPrivate *priv;
2521 ModestWindowPrivate *parent_priv;
2522 gint current_format;
2524 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2526 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2527 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2529 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2530 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2532 if (current_format != file_format) {
2533 switch (file_format) {
2534 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2535 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2536 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2538 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2542 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2543 response = gtk_dialog_run (GTK_DIALOG (dialog));
2544 gtk_widget_destroy (dialog);
2545 if (response == GTK_RESPONSE_OK) {
2546 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2548 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2549 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2554 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2559 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2562 ModestMsgEditWindowPrivate *priv;
2563 WPTextBufferFormat oldfmt, fmt;
2564 gint old_position = 0;
2568 GdkColor *color = NULL;
2569 gboolean bold, bold_set, italic, italic_set;
2570 gboolean underline, underline_set;
2571 gboolean strikethrough, strikethrough_set;
2572 gboolean position_set;
2573 gboolean font_size_set, font_set, color_set;
2576 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2577 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2579 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2581 /* First we get the currently selected font information */
2582 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2583 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2585 switch (oldfmt.text_position) {
2586 case TEXT_POSITION_NORMAL:
2589 case TEXT_POSITION_SUPERSCRIPT:
2597 g_object_set (G_OBJECT (dialog),
2598 "bold", oldfmt.bold != FALSE,
2599 "bold-set", !oldfmt.cs.bold,
2600 "underline", oldfmt.underline != FALSE,
2601 "underline-set", !oldfmt.cs.underline,
2602 "italic", oldfmt.italic != FALSE,
2603 "italic-set", !oldfmt.cs.italic,
2604 "strikethrough", oldfmt.strikethrough != FALSE,
2605 "strikethrough-set", !oldfmt.cs.strikethrough,
2606 "color", &oldfmt.color,
2607 "color-set", !oldfmt.cs.color,
2608 "size", wp_font_size[oldfmt.font_size],
2609 "size-set", !oldfmt.cs.font_size,
2610 "position", old_position,
2611 "position-set", !oldfmt.cs.text_position,
2612 "family", wp_get_font_name (oldfmt.font),
2613 "family-set", !oldfmt.cs.font,
2616 gtk_widget_show_all (dialog);
2617 response = gtk_dialog_run (GTK_DIALOG (dialog));
2618 if (response == GTK_RESPONSE_OK) {
2620 g_object_get( dialog,
2622 "bold-set", &bold_set,
2623 "underline", &underline,
2624 "underline-set", &underline_set,
2626 "italic-set", &italic_set,
2627 "strikethrough", &strikethrough,
2628 "strikethrough-set", &strikethrough_set,
2630 "color-set", &color_set,
2632 "size-set", &font_size_set,
2633 "family", &font_name,
2634 "family-set", &font_set,
2635 "position", &position,
2636 "position-set", &position_set,
2641 if (response == GTK_RESPONSE_OK) {
2642 memset(&fmt, 0, sizeof(fmt));
2648 fmt.italic = italic;
2649 fmt.cs.italic = TRUE;
2651 if (underline_set) {
2652 fmt.underline = underline;
2653 fmt.cs.underline = TRUE;
2655 if (strikethrough_set) {
2656 fmt.strikethrough = strikethrough;
2657 fmt.cs.strikethrough = TRUE;
2662 ? TEXT_POSITION_NORMAL
2663 : ( ( position == 1 )
2664 ? TEXT_POSITION_SUPERSCRIPT
2665 : TEXT_POSITION_SUBSCRIPT );
2666 fmt.cs.text_position = TRUE;
2670 fmt.cs.color = TRUE;
2673 fmt.font = wp_get_font_index(font_name,
2678 if (font_size_set) {
2679 fmt.font_size = wp_get_font_size_index(
2680 font_size, DEFAULT_FONT_SIZE);
2681 fmt.cs.font_size = TRUE;
2683 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2684 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2686 gtk_widget_destroy (dialog);
2688 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2692 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2694 ModestMsgEditWindowPrivate *priv;
2696 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2697 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2699 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2701 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2706 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2708 ModestMsgEditWindowPrivate *priv;
2710 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2711 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2713 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2715 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2720 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2722 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2724 priv->can_undo = can_undo;
2728 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2730 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2732 priv->can_redo = can_redo;
2736 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2738 ModestMsgEditWindowPrivate *priv;
2739 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2740 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2742 return priv->can_undo;
2746 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2748 ModestMsgEditWindowPrivate *priv;
2749 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2750 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2752 return priv->can_redo;
2757 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2760 GtkTextIter match_start, match_end;
2762 if (image_id == NULL)
2765 gtk_text_buffer_get_start_iter (buffer, &iter);
2767 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2768 GSList *tags = gtk_text_iter_get_tags (&match_start);
2770 for (node = tags; node != NULL; node = g_slist_next (node)) {
2771 GtkTextTag *tag = (GtkTextTag *) node->data;
2772 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2773 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2774 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2776 offset = gtk_text_iter_get_offset (&match_start);
2777 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2778 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2782 gtk_text_iter_forward_char (&iter);
2787 message_is_empty (ModestMsgEditWindow *window)
2789 ModestMsgEditWindowPrivate *priv = NULL;
2791 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2792 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2794 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2795 * so we can ignore markup.
2797 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2800 count = gtk_text_buffer_get_char_count (buf);
2806 msg_body_focus (GtkWidget *focus,
2807 GdkEventFocus *event,
2811 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2816 recpt_field_changed (GtkTextBuffer *buffer,
2817 ModestMsgEditWindow *editor)
2819 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2823 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2825 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2829 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2831 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2832 GtkTextBuffer *buffer;
2834 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2835 gtk_text_buffer_set_modified (buffer, FALSE);
2836 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2837 gtk_text_buffer_set_modified (buffer, FALSE);
2838 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2839 gtk_text_buffer_set_modified (buffer, FALSE);
2840 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2844 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2846 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2847 GtkTextBuffer *buffer;
2849 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2850 if (gtk_text_buffer_get_modified (buffer))
2852 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2853 if (gtk_text_buffer_get_modified (buffer))
2855 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2856 if (gtk_text_buffer_get_modified (buffer))
2858 if (gtk_text_buffer_get_modified (priv->text_buffer))
2868 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2870 ModestMsgEditWindowPrivate *priv = NULL;
2872 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2873 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2875 /* check if there's no recipient added */
2876 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2877 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2878 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2879 /* no recipient contents, then select contacts */
2880 modest_msg_edit_window_open_addressbook (window, NULL);
2884 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2885 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2888 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2889 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2892 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2893 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2897 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2898 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2899 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2906 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2907 ModestMsgEditWindow *window)
2909 modest_msg_edit_window_offer_attach_file (window);
2913 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2915 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2917 return priv->clipboard_text;
2921 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2923 ModestMsgEditWindow *window)
2925 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2926 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2928 if (!GTK_WIDGET_VISIBLE (window))
2931 text = gtk_clipboard_wait_for_text (selection_clipboard);
2933 if (priv->clipboard_text != NULL) {
2934 g_free (priv->clipboard_text);
2936 priv->clipboard_text = text;
2938 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2941 subject_field_move_cursor (GtkEntry *entry,
2942 GtkMovementStep step,
2947 if (!GTK_WIDGET_VISIBLE (window))
2950 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2954 update_window_title (ModestMsgEditWindow *window)
2956 ModestMsgEditWindowPrivate *priv = NULL;
2957 const gchar *subject;
2959 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2960 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2961 if (subject == NULL || subject[0] == '\0')
2962 subject = _("mail_va_new_email");
2964 gtk_window_set_title (GTK_WINDOW (window), subject);
2969 subject_field_changed (GtkEditable *editable,
2970 ModestMsgEditWindow *window)
2972 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2973 update_window_title (window);
2974 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2975 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2979 subject_field_insert_text (GtkEditable *editable,
2981 gint new_text_length,
2983 ModestMsgEditWindow *window)
2985 GString *result = g_string_new ("");
2987 gint result_len = 0;
2988 const gchar *entry_text = NULL;
2991 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2992 old_length = g_utf8_strlen (entry_text, -1);
2994 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2995 gunichar c = g_utf8_get_char_validated (current, 8);
2996 /* Invalid unichar, stop */
3002 result = g_string_append_unichar (result, c);
3006 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3007 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3010 /* Prevent endless recursion */
3011 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3012 g_signal_emit_by_name (editable, "insert-text",
3013 (gpointer) result->str, (gpointer) result->len,
3014 (gpointer) position, (gpointer) window);
3015 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3019 if (result_len + old_length > 1000) {
3020 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3021 dgettext("hildon-common-strings",
3022 "ckdg_ib_maximum_characters_reached"));
3025 g_string_free (result, TRUE);
3029 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3032 ModestMsgEditWindowPrivate *priv = NULL;
3034 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3035 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3037 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3040 gtk_widget_show_all (priv->find_toolbar);
3041 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3043 gtk_widget_hide_all (priv->find_toolbar);
3044 gtk_widget_grab_focus (priv->msg_body);
3050 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3052 GtkTextIter *match_start,
3053 GtkTextIter *match_end)
3055 GtkTextIter end_iter;
3056 gchar *str_casefold;
3059 gchar *range_casefold;
3062 gboolean result = FALSE;
3069 gtk_text_iter_forward_to_end (&end_iter);
3071 str_casefold = g_utf8_casefold (str, -1);
3072 str_chars_n = strlen (str);
3074 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3075 range_casefold = g_utf8_casefold (range_text, -1);
3076 range_chars_n = strlen (range_casefold);
3078 if (range_chars_n < str_chars_n) {
3079 g_free (str_casefold);
3080 g_free (range_text);
3081 g_free (range_casefold);
3085 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3086 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3087 if (!g_utf8_collate (range_subtext, str_casefold)) {
3088 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3090 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3091 match_start, match_end, NULL);
3092 g_free (found_text);
3094 g_free (range_subtext);
3098 g_free (str_casefold);
3099 g_free (range_text);
3100 g_free (range_casefold);
3107 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3108 ModestMsgEditWindow *window)
3110 gchar *current_search = NULL;
3111 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3113 GtkTextIter selection_start, selection_end;
3114 GtkTextIter match_start, match_end;
3115 gboolean continue_search = FALSE;
3117 if (message_is_empty (window)) {
3118 g_free (priv->last_search);
3119 priv->last_search = NULL;
3120 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3124 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3125 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3126 g_free (current_search);
3127 g_free (priv->last_search);
3128 priv->last_search = NULL;
3129 /* Information banner about empty search */
3130 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3134 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3135 continue_search = TRUE;
3137 g_free (priv->last_search);
3138 priv->last_search = g_strdup (current_search);
3141 if (continue_search) {
3142 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3143 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3144 &match_start, &match_end);
3146 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3148 GtkTextIter buffer_start;
3149 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3150 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3151 &match_start, &match_end);
3153 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3156 /* Mark as selected the string found in search */
3158 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3159 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3161 g_free (priv->last_search);
3162 priv->last_search = NULL;
3164 g_free (current_search);
3168 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3169 ModestMsgEditWindow *window)
3171 GtkToggleAction *toggle;
3172 ModestWindowPrivate *parent_priv;
3173 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3175 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3176 gtk_toggle_action_set_active (toggle, FALSE);
3180 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3182 ModestMsgEditWindowPrivate *priv;
3184 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3189 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3192 ModestMsgEditWindowPrivate *priv;
3194 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3200 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3203 ModestMsgEditWindowPrivate *priv;
3204 TnyHeader *header = NULL;
3206 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3207 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3209 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3210 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3212 if (priv->draft_msg != NULL) {
3213 g_object_unref (priv->draft_msg);
3216 if (draft != NULL) {
3217 g_object_ref (draft);
3218 header = tny_msg_get_header (draft);
3219 if (priv->msg_uid) {
3220 g_free (priv->msg_uid);
3221 priv->msg_uid = NULL;
3223 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3224 if (GTK_WIDGET_REALIZED (window))
3225 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3228 priv->draft_msg = draft;
3232 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3233 GtkTextIter *start, GtkTextIter *end,
3236 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3237 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3240 if (tag == NULL+13) return;
3241 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3242 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3243 replace_with_images (window, priv->images);
3248 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3251 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3253 g_return_if_fail (TNY_IS_MIME_PART (part));
3254 priv->attachments = g_list_prepend (priv->attachments, part);
3255 g_object_ref (part);
3256 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3257 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3258 gtk_widget_show_all (priv->attachments_caption);
3259 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3263 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3265 ModestMsgEditWindowPrivate *priv;
3267 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3268 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3270 return priv->msg_uid;
3274 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3275 ModestMsgEditWindowWidgetType widget_type)
3277 ModestMsgEditWindowPrivate *priv;
3279 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3280 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3282 switch (widget_type) {
3283 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3284 return priv->msg_body;
3286 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3287 return priv->to_field;
3289 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3290 return priv->cc_field;
3292 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3293 return priv->bcc_field;
3295 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3296 return priv->subject_field;
3298 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3299 return priv->attachments_view;
3307 remove_tags (WPTextBuffer *buffer)
3309 GtkTextIter start, end;
3311 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3312 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3314 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3318 on_account_removed (TnyAccountStore *account_store,
3319 TnyAccount *account,
3322 /* Do nothing if it's a store account, because we use the
3323 transport to send the messages */
3324 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3325 const gchar *parent_acc = NULL;
3326 const gchar *our_acc = NULL;
3328 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3329 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3330 /* Close this window if I'm showing a message of the removed account */
3331 if (strcmp (parent_acc, our_acc) == 0)
3332 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));