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-address-book.h"
60 #include "modest-text-utils.h"
61 #include <tny-simple-list.h>
62 #include <wptextview.h>
63 #include <wptextbuffer.h>
64 #include "modest-scroll-area.h"
65 #include "modest-msg-edit-window-ui-dimming.h"
67 #include "modest-hildon-includes.h"
68 #ifdef MODEST_HAVE_HILDON0_WIDGETS
69 #include <hildon-widgets/hildon-color-chooser.h>
71 #include "widgets/modest-msg-edit-window-ui.h"
72 #ifdef MODEST_HAVE_HILDON0_WIDGETS
73 #include <libgnomevfs/gnome-vfs-mime-utils.h>
75 #include <libgnomevfs/gnome-vfs-mime.h>
77 #include "modest-maemo-utils.h"
80 #define DEFAULT_FONT_SIZE 3
81 #define DEFAULT_FONT 2
82 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
83 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
84 #define DEFAULT_MAIN_VBOX_SPACING 6
85 #define SUBJECT_MAX_LENGTH 1000
86 #define IMAGE_MAX_WIDTH 560
87 #define DEFAULT_FONT_SCALE 1.5
89 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
90 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
91 static void modest_msg_edit_window_finalize (GObject *obj);
93 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
94 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
95 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
96 static void reset_modified (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 DEBUG_BUFFER (WPTextBuffer *buffer)
161 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
162 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
163 while (!gtk_text_iter_is_end (&iter)) {
164 GString *output = g_string_new ("");
165 GSList *toggled_tags;
168 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
169 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
170 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
171 GtkTextTag *tag = (GtkTextTag *) node->data;
173 g_object_get (G_OBJECT (tag), "name", &name, NULL);
174 output = g_string_append (output, name);
175 g_string_append (output, " ");
177 output = g_string_append (output, "] OPENED [ ");
178 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
179 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
180 GtkTextTag *tag = (GtkTextTag *) node->data;
182 g_object_get (G_OBJECT (tag), "name", &name, NULL);
183 output = g_string_append (output, name);
184 g_string_append (output, " ");
186 output = g_string_append (output, "]\n");
187 g_message ("%s", output->str);
188 g_string_free (output, TRUE);
189 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
191 g_message ("END BUFFER");
196 /* static gboolean */
197 /* on_key_pressed (GtkWidget *self, */
198 /* GdkEventKey *event, */
199 /* gpointer user_data); */
201 /* list my signals */
208 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
209 struct _ModestMsgEditWindowPrivate {
211 GtkWidget *header_box;
213 ModestPairList *from_field_protos;
214 GtkWidget *from_field;
218 GtkWidget *bcc_field;
219 GtkWidget *subject_field;
220 GtkWidget *attachments_view;
221 GtkWidget *priority_icon;
222 GtkWidget *add_attachment_button;
224 GtkWidget *cc_caption;
225 GtkWidget *bcc_caption;
226 gboolean update_caption_visibility;
227 GtkWidget *attachments_caption;
229 GtkTextBuffer *text_buffer;
231 GtkWidget *font_size_toolitem;
232 GtkWidget *font_face_toolitem;
233 GtkWidget *font_color_button;
234 GSList *font_items_group;
235 GtkWidget *font_tool_button_label;
236 GSList *size_items_group;
237 GtkWidget *size_tool_button_label;
239 GtkWidget *find_toolbar;
243 GtkWidget *scroll_area;
244 gint last_vadj_upper;
249 TnyHeaderFlags priority_flags;
253 gboolean can_undo, can_redo;
254 gulong clipboard_change_handler_id;
255 gulong default_clipboard_change_handler_id;
256 gchar *clipboard_text;
265 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
266 MODEST_TYPE_MSG_EDIT_WINDOW, \
267 ModestMsgEditWindowPrivate))
269 static GtkWindowClass *parent_class = NULL;
271 /* uncomment the following if you have defined any signals */
272 /* static guint signals[LAST_SIGNAL] = {0}; */
275 modest_msg_edit_window_get_type (void)
277 static GType my_type = 0;
279 static const GTypeInfo my_info = {
280 sizeof(ModestMsgEditWindowClass),
281 NULL, /* base init */
282 NULL, /* base finalize */
283 (GClassInitFunc) modest_msg_edit_window_class_init,
284 NULL, /* class finalize */
285 NULL, /* class data */
286 sizeof(ModestMsgEditWindow),
288 (GInstanceInitFunc) modest_msg_edit_window_init,
291 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
292 "ModestMsgEditWindow",
295 wp_text_buffer_library_init ();
301 save_state (ModestWindow *self)
303 modest_widget_memory_save (modest_runtime_get_conf(),
304 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
309 restore_settings (ModestMsgEditWindow *self)
311 modest_widget_memory_restore (modest_runtime_get_conf(),
312 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
317 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
319 GObjectClass *gobject_class;
320 ModestWindowClass *modest_window_class;
321 gobject_class = (GObjectClass*) klass;
322 modest_window_class = (ModestWindowClass*) klass;
324 parent_class = g_type_class_peek_parent (klass);
325 gobject_class->finalize = modest_msg_edit_window_finalize;
327 modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
328 modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
329 modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
330 modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
331 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
332 modest_window_class->save_state_func = save_state;
333 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
335 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
339 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
341 ModestMsgEditWindowPrivate *priv;
342 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
344 priv->msg_body = NULL;
345 priv->from_field = NULL;
346 priv->to_field = NULL;
347 priv->cc_field = NULL;
348 priv->bcc_field = NULL;
349 priv->subject_field = NULL;
350 priv->attachments = NULL;
352 priv->zoom_level = 1.0;
354 priv->cc_caption = NULL;
355 priv->bcc_caption = NULL;
356 priv->update_caption_visibility = FALSE;
358 priv->priority_flags = 0;
360 priv->find_toolbar = NULL;
361 priv->last_search = NULL;
363 priv->draft_msg = NULL;
364 priv->outbox_msg = NULL;
365 priv->msg_uid = NULL;
367 priv->can_undo = FALSE;
368 priv->can_redo = FALSE;
369 priv->clipboard_change_handler_id = 0;
370 priv->default_clipboard_change_handler_id = 0;
371 priv->clipboard_text = NULL;
374 priv->last_vadj_upper = 0;
378 /* FIXME: this is a dup from the one in gtk/ */
381 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
383 static ModestPairList*
384 get_transports (void)
386 GSList *transports = NULL;
388 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
389 GSList *accounts = modest_account_mgr_account_names (account_mgr,
390 TRUE /* only enabled accounts. */);
392 GSList *cursor = accounts;
394 gchar *account_name = cursor->data;
395 gchar *from_string = NULL;
397 from_string = modest_account_mgr_get_from_string (account_mgr,
401 if (from_string && account_name) {
402 gchar *name = account_name;
403 ModestPair *pair = modest_pair_new ((gpointer) name,
404 (gpointer) from_string , TRUE);
405 transports = g_slist_prepend (transports, pair);
408 cursor = cursor->next;
410 g_slist_free (accounts); /* only free the accounts, not the elements,
411 * because they are used in the pairlist */
415 void vadj_changed (GtkAdjustment *adj,
416 ModestMsgEditWindow *window)
418 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
420 GdkRectangle rectangle, cursor_rectangle;
421 GtkTextIter position;
425 /* We detect if cursor is visible using the full height, not only the center. This
427 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
428 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
430 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
431 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
433 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
434 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
436 if (gtk_widget_is_focus (priv->msg_body) &&
438 if (priv->last_vadj_upper != adj->upper) {
441 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
442 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
443 insert, 0.1, FALSE, 0.0, 0.0);
446 priv->last_vadj_upper = adj->upper;
451 init_window (ModestMsgEditWindow *obj)
453 GtkWidget *from_caption, *to_caption, *subject_caption;
454 GtkWidget *main_vbox;
455 ModestMsgEditWindowPrivate *priv;
457 GtkSizeGroup *size_group;
459 GtkWidget *subject_box;
460 GtkWidget *attachment_icon;
461 GtkWidget *window_box;
462 #if (GTK_MINOR_VERSION >= 10)
463 GdkAtom deserialize_type;
465 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
467 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
469 /* Note: This ModestPairList* must exist for as long as the combo
470 * that uses it, because the ModestComboBox uses the ID opaquely,
471 * so it can't know how to manage its memory. */
472 priv->from_field_protos = get_transports ();
474 priv->from_field = modest_combo_box_new (priv->from_field_protos, g_str_equal);
476 priv->to_field = modest_recpt_editor_new ();
477 priv->cc_field = modest_recpt_editor_new ();
478 priv->bcc_field = modest_recpt_editor_new ();
479 subject_box = gtk_hbox_new (FALSE, 0);
480 priv->priority_icon = gtk_image_new ();
481 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
482 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
483 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
484 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
485 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
486 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
487 priv->add_attachment_button = gtk_button_new ();
488 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
489 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
490 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
491 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
492 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
493 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
494 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
495 priv->attachments_view = modest_attachments_view_new (NULL);
497 priv->header_box = gtk_vbox_new (FALSE, 0);
499 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
500 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
501 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
502 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
503 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
504 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
505 g_object_unref (size_group);
507 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
508 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
509 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
510 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
511 gtk_size_group_add_widget (size_group, priv->subject_field);
512 gtk_size_group_add_widget (size_group, priv->attachments_view);
513 g_object_unref (size_group);
515 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
516 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
517 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
518 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
519 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
520 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
521 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
524 priv->msg_body = wp_text_view_new ();
525 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
526 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
527 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
528 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
529 #if (GTK_MINOR_VERSION >= 10)
530 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
531 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
533 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
534 deserialize_type, TRUE);
536 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
538 priv->find_toolbar = hildon_find_toolbar_new (NULL);
539 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
541 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
543 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
544 G_CALLBACK (text_buffer_refresh_attributes), obj);
545 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
546 G_CALLBACK (text_buffer_can_undo), obj);
547 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
548 G_CALLBACK (text_buffer_can_redo), obj);
549 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
550 G_CALLBACK (body_changed), obj);
551 g_signal_connect (G_OBJECT (obj), "window-state-event",
552 G_CALLBACK (modest_msg_edit_window_window_state_event),
554 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
555 G_CALLBACK (text_buffer_apply_tag), obj);
556 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
557 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
558 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
559 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
560 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
561 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
563 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
564 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
566 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
567 G_CALLBACK (msg_body_focus), obj);
568 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
569 G_CALLBACK (msg_body_focus), obj);
570 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
571 "changed", G_CALLBACK (recpt_field_changed), obj);
572 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
573 "changed", G_CALLBACK (recpt_field_changed), obj);
574 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
575 "changed", G_CALLBACK (recpt_field_changed), obj);
576 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
577 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
578 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
580 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
581 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
583 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
584 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
585 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
586 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
588 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
590 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
591 frame = gtk_frame_new (NULL);
592 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
594 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
595 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
596 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
598 G_CALLBACK (vadj_changed),
600 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
602 window_box = gtk_vbox_new (FALSE, 0);
603 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
604 gtk_container_add (GTK_CONTAINER(obj), window_box);
605 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
606 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
608 priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
609 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
610 priv->default_clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
611 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
616 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
618 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
620 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
621 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
622 priv->clipboard_change_handler_id))
623 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
624 priv->clipboard_change_handler_id);
625 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
626 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
627 priv->default_clipboard_change_handler_id))
628 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
629 priv->default_clipboard_change_handler_id);
633 modest_msg_edit_window_finalize (GObject *obj)
635 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
637 /* Sanity check: shouldn't be needed, the window mgr should
638 call this function before */
639 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
641 if (priv->clipboard_text != NULL) {
642 g_free (priv->clipboard_text);
643 priv->clipboard_text = NULL;
646 if (priv->draft_msg != NULL) {
647 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
648 if (TNY_IS_HEADER (header)) {
649 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
650 modest_window_mgr_unregister_header (mgr, header);
652 g_object_unref (priv->draft_msg);
653 priv->draft_msg = NULL;
655 if (priv->outbox_msg != NULL) {
656 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
657 if (TNY_IS_HEADER (header)) {
658 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
659 modest_window_mgr_unregister_header (mgr, header);
661 g_object_unref (priv->outbox_msg);
662 priv->outbox_msg = NULL;
664 if (priv->msg_uid != NULL) {
665 g_free (priv->msg_uid);
666 priv->msg_uid = NULL;
669 /* This had to stay alive for as long as the combobox that used it: */
670 modest_pair_list_free (priv->from_field_protos);
672 G_OBJECT_CLASS(parent_class)->finalize (obj);
676 menubar_to_menu (GtkUIManager *ui_manager)
678 GtkWidget *main_menu;
682 /* Create new main menu */
683 main_menu = gtk_menu_new();
685 /* Get the menubar from the UI manager */
686 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
688 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
692 menu = GTK_WIDGET (iter->data);
693 gtk_widget_reparent(menu, main_menu);
695 iter = g_list_next (iter);
701 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
703 GdkPixbufLoader *loader;
706 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
711 tny_stream_reset (TNY_STREAM (stream));
712 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
713 unsigned char read_buffer[128];
715 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
716 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
720 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
721 g_object_ref (pixbuf);
722 gdk_pixbuf_loader_close (loader, NULL);
723 g_object_unref (loader);
725 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
726 GdkPixbuf *new_pixbuf;
728 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
729 gdk_pixbuf_get_width (pixbuf);
730 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
731 g_object_unref (pixbuf);
739 replace_with_attachments (ModestMsgEditWindow *self, GList *attachments)
741 ModestMsgEditWindowPrivate *priv;
744 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
746 for (node = attachments; node != NULL; node = g_list_next (node)) {
747 TnyMimePart *part = (TnyMimePart *) node->data;
748 const gchar *cid = tny_mime_part_get_content_id (part);
749 const gchar *mime_type = tny_mime_part_get_content_type (part);
750 if ((cid != NULL)&&(mime_type != NULL)) {
751 TnyStream *stream = tny_mime_part_get_stream (part);
752 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
753 g_object_unref (stream);
755 if (pixbuf != NULL) {
756 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
757 g_object_unref (pixbuf);
764 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
767 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
769 for (node = attachments; node != NULL; node = g_list_next (node)) {
770 TnyMimePart *part = (TnyMimePart *) node->data;
771 const gchar *cid = tny_mime_part_get_content_id (part);
773 char *invalid = NULL;
774 gint int_cid = strtol (cid, &invalid, 10);
775 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
776 priv->last_cid = int_cid;
784 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
787 const gchar *to, *cc, *bcc, *subject;
789 ModestMsgEditWindowPrivate *priv;
791 TnyHeaderFlags priority_flags;
792 TnyFolder *msg_folder;
793 gboolean is_html = FALSE;
795 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
796 g_return_if_fail (TNY_IS_MSG (msg));
798 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
800 header = tny_msg_get_header (msg);
801 to = tny_header_get_to (header);
802 cc = tny_header_get_cc (header);
803 bcc = tny_header_get_bcc (header);
804 subject = tny_header_get_subject (header);
805 priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
808 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
810 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
811 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
812 gtk_widget_show (priv->cc_caption);
813 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
814 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
815 gtk_widget_hide (priv->cc_caption);
818 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
819 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
820 gtk_widget_show (priv->bcc_caption);
821 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
822 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
823 gtk_widget_hide (priv->bcc_caption);
826 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
827 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
830 update_window_title (self);
832 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
833 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
835 if ((body == NULL)||(body[0] == '\0')) {
837 body = modest_text_utils_convert_to_html ("");
840 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
841 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
844 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
847 /* Add attachments to the view */
848 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
849 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
850 if (priv->attachments == NULL) {
851 gtk_widget_hide (priv->attachments_caption);
853 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
854 gtk_widget_show_all (priv->attachments_caption);
855 replace_with_attachments (self, priv->attachments);
857 update_last_cid (self, priv->attachments);
859 if (preserve_is_rich && !is_html) {
860 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
861 /* Get the default format required from configuration */
862 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
863 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
866 /* Set the default focus depending on having already a To: field or not */
867 if ((!to)||(*to == '\0')) {
868 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
870 gtk_widget_grab_focus (priv->msg_body);
873 /* TODO: lower priority, select in the From: combo to the
874 value that comes from msg <- not sure, should it be
877 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
879 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
880 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
882 reset_modified (self);
884 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
885 text_buffer_can_undo (priv->text_buffer, FALSE, self);
886 text_buffer_can_redo (priv->text_buffer, FALSE, self);
889 g_free (priv->msg_uid);
890 priv->msg_uid = NULL;
893 /* we should set a reference to the incoming message if it is a draft */
894 msg_folder = tny_msg_get_folder (msg);
896 if (modest_tny_folder_is_local_folder (msg_folder)) {
897 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
898 if (type == TNY_FOLDER_TYPE_DRAFTS)
899 priv->draft_msg = g_object_ref(msg);
900 if (type == TNY_FOLDER_TYPE_OUTBOX)
901 priv->outbox_msg = g_object_ref(msg);
902 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
904 g_object_unref (msg_folder);
909 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
912 GList *item_children, *node;
913 GtkWidget *bin_child;
915 bin_child = gtk_bin_get_child (GTK_BIN(item));
917 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
919 for (node = item_children; node != NULL; node = g_list_next (node)) {
920 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
921 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
924 g_list_free (item_children);
928 menu_tool_button_dont_expand (GtkMenuToolButton *item)
931 GList *item_children, *node;
933 box = gtk_bin_get_child (GTK_BIN (item));
934 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
935 item_children = gtk_container_get_children (GTK_CONTAINER (box));
937 for (node = item_children; node != NULL; node = g_list_next (node)) {
938 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
939 if (GTK_IS_TOGGLE_BUTTON (node->data))
940 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
941 else if (GTK_IS_BUTTON (node->data))
942 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
944 g_list_free (item_children);
949 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
951 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
952 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
953 GtkWidget *placeholder;
954 GtkWidget *tool_item;
959 GtkWidget *sizes_menu;
960 GtkWidget *fonts_menu;
961 GSList *radio_group = NULL;
966 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
967 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
969 /* Font color placeholder */
970 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
971 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
974 tool_item = GTK_WIDGET (gtk_tool_item_new ());
975 priv->font_color_button = hildon_color_button_new ();
976 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
977 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
978 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
979 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
980 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
981 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
982 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
984 G_CALLBACK (modest_msg_edit_window_color_button_change),
987 /* Font size and face placeholder */
988 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
989 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
991 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
992 priv->size_tool_button_label = gtk_label_new (NULL);
993 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
994 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
995 size_text,"</span>", NULL);
996 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
998 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
999 sizes_menu = gtk_menu_new ();
1000 priv->size_items_group = NULL;
1002 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1003 GtkWidget *size_menu_item;
1005 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1006 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1007 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1008 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1009 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1010 gtk_widget_show (size_menu_item);
1012 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1016 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1017 GtkWidget *item = (GtkWidget *) node->data;
1018 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1022 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1023 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1024 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1025 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1026 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1027 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1028 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1029 priv->font_size_toolitem = tool_item;
1032 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1033 priv->font_tool_button_label = gtk_label_new (NULL);
1034 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1035 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1037 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1038 fonts_menu = gtk_menu_new ();
1039 priv->font_items_group = NULL;
1041 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1042 GtkWidget *font_menu_item;
1043 GtkWidget *child_label;
1045 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1046 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1047 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1048 wp_get_font_name (font_index), "</span>", NULL);
1049 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1052 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1053 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1054 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1055 gtk_widget_show (font_menu_item);
1057 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1060 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1061 GtkWidget *item = (GtkWidget *) node->data;
1062 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1065 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1066 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1067 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1068 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1069 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1070 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1071 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1072 priv->font_face_toolitem = tool_item;
1074 /* Set expand and homogeneous for remaining items */
1075 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1076 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1077 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1078 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1079 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1080 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1081 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1082 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1083 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1085 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1086 will not show the tool items added to the placeholders) */
1087 gtk_widget_show_all (parent_priv->toolbar);
1089 /* Set the no show all *after* showing all items. We do not
1090 want the toolbar to be shown with a show all because it
1091 could go agains the gconf setting regarding showing or not
1092 the toolbar of the editor window */
1093 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1099 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1102 ModestWindowPrivate *parent_priv;
1103 ModestMsgEditWindowPrivate *priv;
1104 GtkActionGroup *action_group;
1105 GError *error = NULL;
1106 GdkPixbuf *window_icon = NULL;
1109 ModestPair *account_pair = NULL;
1110 ModestDimmingRulesGroup *menu_rules_group = NULL;
1111 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1112 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1114 g_return_val_if_fail (msg, NULL);
1115 g_return_val_if_fail (account_name, NULL);
1117 obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1119 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1120 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1122 parent_priv->ui_manager = gtk_ui_manager_new();
1123 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1124 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1126 /* Add common actions */
1127 gtk_action_group_add_actions (action_group,
1128 modest_msg_edit_action_entries,
1129 G_N_ELEMENTS (modest_msg_edit_action_entries),
1131 gtk_action_group_add_toggle_actions (action_group,
1132 modest_msg_edit_toggle_action_entries,
1133 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1135 gtk_action_group_add_radio_actions (action_group,
1136 modest_msg_edit_alignment_radio_action_entries,
1137 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1139 G_CALLBACK (modest_ui_actions_on_change_justify),
1141 gtk_action_group_add_radio_actions (action_group,
1142 modest_msg_edit_zoom_action_entries,
1143 G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1145 G_CALLBACK (modest_ui_actions_on_change_zoom),
1147 gtk_action_group_add_radio_actions (action_group,
1148 modest_msg_edit_priority_action_entries,
1149 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1151 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1153 gtk_action_group_add_radio_actions (action_group,
1154 modest_msg_edit_file_format_action_entries,
1155 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1156 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1157 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1159 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1160 g_object_unref (action_group);
1162 /* Load the UI definition */
1163 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1165 if (error != NULL) {
1166 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1167 g_clear_error (&error);
1170 /* Add accelerators */
1171 gtk_window_add_accel_group (GTK_WINDOW (obj),
1172 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1174 /* Menubar. Update the state of some toggles */
1175 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1176 conf = modest_runtime_get_conf ();
1177 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1178 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
1179 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1180 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
1181 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1182 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
1183 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1184 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1186 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1189 init_window (MODEST_MSG_EDIT_WINDOW(obj));
1191 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1193 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1195 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1196 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1198 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1199 if (account_pair != NULL)
1200 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1202 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1203 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1204 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1205 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1206 /* Add common dimming rules */
1207 modest_dimming_rules_group_add_rules (menu_rules_group,
1208 modest_msg_edit_window_menu_dimming_entries,
1209 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1210 MODEST_WINDOW (obj));
1211 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1212 modest_msg_edit_window_toolbar_dimming_entries,
1213 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1214 MODEST_WINDOW (obj));
1215 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1216 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1217 MODEST_WINDOW (obj));
1218 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1219 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1220 MODEST_WINDOW (obj));
1221 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1222 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1223 MODEST_WINDOW (obj));
1224 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1225 modest_msg_edit_window_clipboard_dimming_entries,
1226 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1227 MODEST_WINDOW (obj));
1228 /* Insert dimming rules group for this window */
1229 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1230 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1231 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1232 /* Checks the dimming rules */
1233 g_object_unref (menu_rules_group);
1234 g_object_unref (toolbar_rules_group);
1235 g_object_unref (clipboard_rules_group);
1237 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1239 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1241 /* Set window icon */
1242 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1244 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1245 g_object_unref (window_icon);
1248 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1249 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1251 /* Dim at start clipboard actions */
1252 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1253 gtk_action_set_sensitive (action, FALSE);
1254 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1255 gtk_action_set_sensitive (action, FALSE);
1256 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1257 gtk_action_set_sensitive (action, FALSE);
1259 /* set initial state of cc and bcc */
1260 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1261 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1262 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1263 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1264 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1265 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1267 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1268 priv->update_caption_visibility = TRUE;
1270 reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1272 return (ModestWindow*) obj;
1276 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1278 GString **string_buffer = (GString **) user_data;
1280 *string_buffer = g_string_append (*string_buffer, buffer);
1286 * @result: A new string which should be freed with g_free().
1289 get_formatted_data (ModestMsgEditWindow *edit_window)
1291 ModestMsgEditWindowPrivate *priv;
1292 GString *string_buffer = g_string_new ("");
1294 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1296 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1298 return g_string_free (string_buffer, FALSE);
1303 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1306 const gchar *account_name;
1307 ModestMsgEditWindowPrivate *priv;
1309 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1311 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1313 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1314 g_return_val_if_fail (account_name, NULL);
1317 /* don't free these (except from) */
1318 data = g_slice_new0 (MsgData);
1319 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1321 data->account_name = g_strdup (account_name);
1322 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1323 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1324 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1325 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1326 if (priv->draft_msg) {
1327 data->draft_msg = g_object_ref (priv->draft_msg);
1328 } else if (priv->outbox_msg) {
1329 data->draft_msg = g_object_ref (priv->outbox_msg);
1331 data->draft_msg = NULL;
1334 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1336 gtk_text_buffer_get_bounds (buf, &b, &e);
1337 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1339 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1340 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1342 data->html_body = NULL;
1344 /* deep-copy the data */
1345 GList *cursor = priv->attachments;
1346 data->attachments = NULL;
1348 if (!(TNY_IS_MIME_PART(cursor->data))) {
1349 g_warning ("strange data in attachment list");
1350 cursor = g_list_next (cursor);
1353 data->attachments = g_list_append (data->attachments,
1354 g_object_ref (cursor->data));
1355 cursor = g_list_next (cursor);
1358 data->priority_flags = priv->priority_flags;
1365 unref_gobject (GObject *obj, gpointer data)
1367 if (!G_IS_OBJECT(obj))
1369 g_object_unref (obj);
1373 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1376 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1384 g_free (data->subject);
1385 g_free (data->plain_body);
1386 g_free (data->html_body);
1387 g_free (data->account_name);
1389 if (data->draft_msg != NULL) {
1390 g_object_unref (data->draft_msg);
1391 data->draft_msg = NULL;
1394 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1395 g_list_free (data->attachments);
1397 g_slice_free (MsgData, data);
1401 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1404 ModestMsgEditWindowPrivate *priv = NULL;
1405 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1407 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1409 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1411 return MODEST_MSG_EDIT_FORMAT_HTML;
1413 return MODEST_MSG_EDIT_FORMAT_TEXT;
1417 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1418 ModestMsgEditFormat format)
1420 ModestMsgEditWindowPrivate *priv;
1422 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1423 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1426 case MODEST_MSG_EDIT_FORMAT_HTML:
1427 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1429 case MODEST_MSG_EDIT_FORMAT_TEXT:
1430 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1433 g_return_if_reached ();
1437 ModestMsgEditFormatState *
1438 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1440 ModestMsgEditFormatState *format_state = NULL;
1441 ModestMsgEditWindowPrivate *priv;
1442 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1444 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1445 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1447 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1449 format_state = g_new0 (ModestMsgEditFormatState, 1);
1450 format_state->bold = buffer_format->bold&0x1;
1451 format_state->italics = buffer_format->italic&0x1;
1452 format_state->bullet = buffer_format->bullet&0x1;
1453 format_state->color = buffer_format->color;
1454 format_state->font_size = buffer_format->font_size;
1455 format_state->font_family = wp_get_font_name (buffer_format->font);
1456 format_state->justification = buffer_format->justification;
1457 g_free (buffer_format);
1459 return format_state;
1464 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1465 const ModestMsgEditFormatState *format_state)
1467 ModestMsgEditWindowPrivate *priv;
1468 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1469 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1470 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1471 g_return_if_fail (format_state != NULL);
1473 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1474 gtk_widget_grab_focus (priv->msg_body);
1475 buffer_format->bold = (format_state->bold != FALSE);
1476 buffer_format->italic = (format_state->italics != FALSE);
1477 buffer_format->color = format_state->color;
1478 buffer_format->font_size = format_state->font_size;
1479 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1480 buffer_format->justification = format_state->justification;
1481 buffer_format->bullet = format_state->bullet;
1483 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1485 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1486 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1487 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1488 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1489 buffer_format->cs.font = (buffer_format->font != current_format->font);
1490 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1491 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1493 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1494 if (buffer_format->cs.bold) {
1495 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1497 if (buffer_format->cs.italic) {
1498 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1500 if (buffer_format->cs.color) {
1501 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1503 if (buffer_format->cs.font_size) {
1504 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1506 if (buffer_format->cs.justification) {
1507 switch (buffer_format->justification) {
1508 case GTK_JUSTIFY_LEFT:
1509 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1511 case GTK_JUSTIFY_CENTER:
1512 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1514 case GTK_JUSTIFY_RIGHT:
1515 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1522 if (buffer_format->cs.font) {
1523 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1525 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1526 if (buffer_format->cs.bullet) {
1527 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1529 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1531 g_free (current_format);
1536 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1538 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1540 ModestWindowPrivate *parent_priv;
1541 ModestMsgEditWindowPrivate *priv;
1542 GtkWidget *new_size_menuitem;
1543 GtkWidget *new_font_menuitem;
1545 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1548 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1549 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1550 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1551 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1553 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1554 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1555 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1558 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1560 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1561 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1563 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1564 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1566 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1567 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1569 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1570 G_CALLBACK (modest_msg_edit_window_color_button_change),
1572 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1573 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1574 G_CALLBACK (modest_msg_edit_window_color_button_change),
1577 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1578 buffer_format->font_size))->data);
1579 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1583 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1584 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1585 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1587 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1588 G_CALLBACK (modest_msg_edit_window_size_change),
1590 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1591 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1592 G_CALLBACK (modest_msg_edit_window_size_change),
1596 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1597 buffer_format->font))->data);
1598 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1602 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1603 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1604 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1606 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1607 G_CALLBACK (modest_msg_edit_window_font_change),
1609 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1610 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1611 G_CALLBACK (modest_msg_edit_window_font_change),
1615 g_free (buffer_format);
1621 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1624 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1625 ModestMsgEditWindowPrivate *priv;
1626 GtkWidget *dialog = NULL;
1628 const GdkColor *new_color = NULL;
1630 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1631 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1633 #ifdef MODEST_HILDON_VERSION_0
1634 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1635 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1637 dialog = hildon_color_chooser_new ();
1638 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1639 #endif /*MODEST_HILDON_VERSION_0*/
1640 g_free (buffer_format);
1642 response = gtk_dialog_run (GTK_DIALOG (dialog));
1644 case GTK_RESPONSE_OK: {
1645 #ifdef MODEST_HILDON_VERSION_0
1646 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1649 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1651 #endif /*MODEST_HILDON_VERSION_0*/
1658 gtk_widget_destroy (dialog);
1660 if (new_color != NULL)
1661 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1666 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1669 ModestMsgEditWindowPrivate *priv;
1670 GtkWidget *dialog = NULL;
1672 GdkColor *old_color = NULL;
1673 const GdkColor *new_color = NULL;
1675 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1676 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1678 #ifdef MODEST_HILDON_VERSION_0
1679 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1680 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1682 dialog = hildon_color_chooser_new ();
1683 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1684 #endif /*MODEST_HILDON_VERSION_9*/
1686 response = gtk_dialog_run (GTK_DIALOG (dialog));
1688 case GTK_RESPONSE_OK: {
1689 #ifdef MODEST_HILDON_VERSION_0
1690 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1693 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1695 #endif /*MODEST_HILDON_VERSION_0*/
1701 gtk_widget_destroy (dialog);
1703 if (new_color != NULL)
1704 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1708 static TnyStream* create_stream_for_uri (const gchar* uri)
1713 TnyStream *result = NULL;
1715 GnomeVFSHandle *handle = NULL;
1716 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1717 if (test == GNOME_VFS_OK) {
1718 /* Create the tinymail stream: */
1719 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1720 result = TNY_STREAM (tny_vfs_stream_new (handle));
1727 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1730 ModestMsgEditWindowPrivate *priv;
1731 GtkWidget *dialog = NULL;
1733 GSList *uris = NULL;
1734 GSList *uri_node = NULL;
1736 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1738 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1739 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1740 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1742 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1744 response = gtk_dialog_run (GTK_DIALOG (dialog));
1746 case GTK_RESPONSE_OK:
1747 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1752 gtk_widget_destroy (dialog);
1754 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1756 GnomeVFSHandle *handle = NULL;
1757 GnomeVFSResult result;
1758 GtkTextIter position;
1759 GtkTextMark *insert_mark;
1761 uri = (const gchar *) uri_node->data;
1762 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1763 if (result == GNOME_VFS_OK) {
1765 GnomeVFSFileInfo info;
1766 gchar *filename, *basename, *escaped_filename;
1767 TnyMimePart *mime_part;
1769 const gchar *mime_type = NULL;
1770 GnomeVFSURI *vfs_uri;
1772 vfs_uri = gnome_vfs_uri_new (uri);
1774 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1775 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1776 g_free (escaped_filename);
1777 gnome_vfs_uri_unref (vfs_uri);
1779 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1780 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1782 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1784 mime_part = tny_platform_factory_new_mime_part
1785 (modest_runtime_get_platform_factory ());
1787 TnyStream *stream = create_stream_for_uri (uri);
1788 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1790 content_id = g_strdup_printf ("%d", priv->last_cid);
1791 tny_mime_part_set_content_id (mime_part, content_id);
1792 g_free (content_id);
1795 basename = g_path_get_basename (filename);
1796 tny_mime_part_set_filename (mime_part, basename);
1799 pixbuf = pixbuf_from_stream (stream, mime_type);
1801 if (pixbuf != NULL) {
1802 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1803 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1804 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1807 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1808 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1810 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1811 gtk_widget_show_all (priv->attachments_caption);
1812 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1822 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1825 ModestMsgEditWindowPrivate *priv;
1826 GtkWidget *dialog = NULL;
1828 GSList *uris = NULL;
1831 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1833 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1834 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1835 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1837 response = gtk_dialog_run (GTK_DIALOG (dialog));
1839 case GTK_RESPONSE_OK:
1840 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1845 gtk_widget_destroy (dialog);
1847 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1848 const gchar *uri = (const gchar *) uri_node->data;
1849 modest_msg_edit_window_attach_file_one (window, uri);
1851 g_slist_foreach (uris, (GFunc) g_free, NULL);
1852 g_slist_free (uris);
1856 modest_msg_edit_window_attach_file_one (
1857 ModestMsgEditWindow *window,
1860 g_return_if_fail (window);
1861 g_return_if_fail (uri);
1863 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1866 GnomeVFSHandle *handle = NULL;
1867 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1868 if (result == GNOME_VFS_OK) {
1869 TnyMimePart *mime_part;
1871 const gchar *mime_type = NULL;
1873 gchar *escaped_filename;
1876 GnomeVFSFileInfo info;
1877 GnomeVFSURI *vfs_uri;
1879 vfs_uri = gnome_vfs_uri_new (uri);
1882 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1883 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1884 g_free (escaped_filename);
1885 gnome_vfs_uri_unref (vfs_uri);
1887 if (gnome_vfs_get_file_info (uri,
1889 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1890 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1892 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1893 mime_part = tny_platform_factory_new_mime_part
1894 (modest_runtime_get_platform_factory ());
1895 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1897 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1899 content_id = g_strdup_printf ("%d", priv->last_cid);
1900 tny_mime_part_set_content_id (mime_part, content_id);
1901 g_free (content_id);
1904 basename = g_path_get_basename (filename);
1905 tny_mime_part_set_filename (mime_part, basename);
1908 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1909 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1911 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1912 gtk_widget_show_all (priv->attachments_caption);
1913 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1919 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1922 ModestMsgEditWindowPrivate *priv;
1923 gboolean clean_list = FALSE;
1925 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1926 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1928 if (att_list == NULL) {
1929 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1933 if (att_list == NULL) {
1934 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1936 GtkWidget *confirmation_dialog = NULL;
1937 gboolean dialog_response;
1939 gchar *message = NULL;
1940 const gchar *filename = NULL;
1942 if (att_list->next == NULL) {
1943 filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1947 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1948 att_list->next == NULL), filename);
1949 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1951 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1952 gtk_widget_destroy (confirmation_dialog);
1953 if (!dialog_response) {
1955 g_list_free (att_list);
1958 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1960 for (node = att_list; node != NULL; node = g_list_next (node)) {
1961 TnyMimePart *mime_part = (TnyMimePart *) node->data;
1962 const gchar *att_id;
1963 priv->attachments = g_list_remove (priv->attachments, mime_part);
1965 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1967 if (priv->attachments == NULL)
1968 gtk_widget_hide (priv->attachments_caption);
1969 att_id = tny_mime_part_get_content_id (mime_part);
1971 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1973 g_object_unref (mime_part);
1974 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1979 g_list_free (att_list);
1983 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1986 ModestMsgEditWindowPrivate *priv;
1987 GdkColor *new_color;
1988 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1990 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1991 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1994 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1996 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1998 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2000 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2005 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2008 ModestMsgEditWindowPrivate *priv;
2009 gint new_size_index;
2010 ModestMsgEditWindow *window;
2013 window = MODEST_MSG_EDIT_WINDOW (userdata);
2014 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2015 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2017 if (gtk_check_menu_item_get_active (menu_item)) {
2019 WPTextBufferFormat format;
2021 memset (&format, 0, sizeof (format));
2022 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2024 label = gtk_bin_get_child (GTK_BIN (menu_item));
2026 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2027 format.cs.font_size = TRUE;
2028 format.cs.text_position = TRUE;
2029 format.cs.font = TRUE;
2030 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2031 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2033 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2034 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2035 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2037 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2038 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2039 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2045 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2048 ModestMsgEditWindowPrivate *priv;
2049 gint new_font_index;
2050 ModestMsgEditWindow *window;
2053 window = MODEST_MSG_EDIT_WINDOW (userdata);
2054 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2055 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2057 if (gtk_check_menu_item_get_active (menu_item)) {
2060 label = gtk_bin_get_child (GTK_BIN (menu_item));
2062 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2064 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2065 (gpointer) new_font_index))
2066 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2068 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2069 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2070 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2076 modest_msg_edit_window_set_zoom (ModestWindow *window,
2079 ModestMsgEditWindowPrivate *priv;
2080 ModestWindowPrivate *parent_priv;
2081 GtkRadioAction *zoom_radio_action;
2083 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2085 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2086 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2087 priv->zoom_level = zoom;
2088 wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2090 /* Zoom level menu options should be updated with the current zoom level */
2091 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2092 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2093 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2094 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2095 /* FIXME: Not availible before Gtk 2.10 */
2097 gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2102 modest_msg_edit_window_get_zoom (ModestWindow *window)
2104 ModestMsgEditWindowPrivate *priv;
2106 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2108 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2109 return priv->zoom_level;
2113 zoom_allowed (ModestMsgEditWindow *window)
2117 focus = gtk_window_get_focus (GTK_WINDOW (window));
2118 return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2122 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2124 ModestWindowPrivate *parent_priv;
2125 GtkRadioAction *zoom_radio_action;
2126 GSList *group, *node;
2128 /* First we check if the text view is focused. If not, zooming is not allowed */
2129 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2130 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2134 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2135 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2136 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2138 group = gtk_radio_action_get_group (zoom_radio_action);
2140 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2141 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2145 for (node = group; node != NULL; node = g_slist_next (node)) {
2146 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2147 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2155 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2157 ModestWindowPrivate *parent_priv;
2158 GtkRadioAction *zoom_radio_action;
2159 GSList *group, *node;
2161 /* First we check if the text view is focused. If not, zooming is not allowed */
2162 if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2163 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2167 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2168 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
2169 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2171 group = gtk_radio_action_get_group (zoom_radio_action);
2173 for (node = group; node != NULL; node = g_slist_next (node)) {
2174 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2175 if (node->next != NULL) {
2176 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2179 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2187 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2189 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2190 ModestWindowPrivate *parent_priv;
2191 ModestWindowMgr *mgr;
2192 gboolean is_fullscreen;
2193 GtkAction *fs_toggle_action;
2196 mgr = modest_runtime_get_window_mgr ();
2197 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2199 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2201 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2202 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2203 if (is_fullscreen != active)
2204 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2212 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2215 ModestMsgEditWindowPrivate *priv = NULL;
2216 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2218 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2219 if (!priv->update_caption_visibility)
2222 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2224 gtk_widget_show (priv->cc_caption);
2226 gtk_widget_hide (priv->cc_caption);
2228 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2232 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2235 ModestMsgEditWindowPrivate *priv = NULL;
2236 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2238 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2239 if (!priv->update_caption_visibility)
2242 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2244 gtk_widget_show (priv->bcc_caption);
2246 gtk_widget_hide (priv->bcc_caption);
2248 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2252 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2253 ModestRecptEditor *editor)
2255 ModestMsgEditWindowPrivate *priv;
2257 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2258 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2259 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2261 if (editor == NULL) {
2262 GtkWidget *view_focus;
2263 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2265 /* This code should be kept in sync with ModestRecptEditor. The
2266 textview inside the recpt editor is the one that really gets the
2267 focus. As it's inside a scrolled window, and this one inside the
2268 hbox recpt editor inherits from, we'll need to go up in the
2269 hierarchy to know if the text view is part of the recpt editor
2270 or if it's a different text entry */
2272 if (gtk_widget_get_parent (view_focus)) {
2273 GtkWidget *first_parent;
2275 first_parent = gtk_widget_get_parent (view_focus);
2276 if (gtk_widget_get_parent (first_parent) &&
2277 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2278 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2283 editor = MODEST_RECPT_EDITOR (priv->to_field);
2287 modest_address_book_select_addresses (editor);
2292 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2294 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2296 modest_msg_edit_window_open_addressbook (window, NULL);
2300 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2301 gboolean show_toolbar)
2303 ModestWindowPrivate *parent_priv;
2304 const gchar *action_name;
2307 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2308 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2310 /* We can not just use the code of
2311 modest_msg_edit_window_setup_toolbar because it has a
2312 mixture of both initialization and creation code. */
2314 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2316 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2318 /* Update also the actions (to update the toggles in the
2319 menus), we have to do it manually because some other window
2320 of the same time could have changed it (remember that the
2321 toolbar fullscreen mode is shared by all the windows of the
2323 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2324 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2326 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2328 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2329 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2335 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2336 TnyHeaderFlags priority_flags)
2338 ModestMsgEditWindowPrivate *priv;
2339 ModestWindowPrivate *parent_priv;
2341 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2343 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2344 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2345 priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2347 if (priv->priority_flags != priority_flags) {
2348 GtkAction *priority_action = NULL;
2350 priv->priority_flags = priority_flags;
2352 switch (priority_flags) {
2353 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2354 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2355 gtk_widget_show (priv->priority_icon);
2356 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2357 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2359 case TNY_HEADER_FLAG_LOW_PRIORITY:
2360 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2361 gtk_widget_show (priv->priority_icon);
2362 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2363 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2366 gtk_widget_hide (priv->priority_icon);
2367 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2368 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2371 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2372 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2377 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2380 ModestMsgEditWindowPrivate *priv;
2381 ModestWindowPrivate *parent_priv;
2382 gint current_format;
2384 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2386 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2387 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2389 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2390 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2392 if (current_format != file_format) {
2393 switch (file_format) {
2394 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2395 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2396 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2398 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2402 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2403 response = gtk_dialog_run (GTK_DIALOG (dialog));
2404 gtk_widget_destroy (dialog);
2405 if (response == GTK_RESPONSE_OK) {
2406 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2408 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2409 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2414 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2419 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2422 ModestMsgEditWindowPrivate *priv;
2423 WPTextBufferFormat oldfmt, fmt;
2424 gint old_position = 0;
2428 GdkColor *color = NULL;
2429 gboolean bold, bold_set, italic, italic_set;
2430 gboolean underline, underline_set;
2431 gboolean strikethrough, strikethrough_set;
2432 gboolean position_set;
2433 gboolean font_size_set, font_set, color_set;
2436 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2437 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2439 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2441 /* First we get the currently selected font information */
2442 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2443 g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2445 switch (oldfmt.text_position) {
2446 case TEXT_POSITION_NORMAL:
2449 case TEXT_POSITION_SUPERSCRIPT:
2457 g_object_set (G_OBJECT (dialog),
2458 "bold", oldfmt.bold != FALSE,
2459 "bold-set", !oldfmt.cs.bold,
2460 "underline", oldfmt.underline != FALSE,
2461 "underline-set", !oldfmt.cs.underline,
2462 "italic", oldfmt.italic != FALSE,
2463 "italic-set", !oldfmt.cs.italic,
2464 "strikethrough", oldfmt.strikethrough != FALSE,
2465 "strikethrough-set", !oldfmt.cs.strikethrough,
2466 "color", &oldfmt.color,
2467 "color-set", !oldfmt.cs.color,
2468 "size", wp_font_size[oldfmt.font_size],
2469 "size-set", !oldfmt.cs.font_size,
2470 "position", old_position,
2471 "position-set", !oldfmt.cs.text_position,
2472 "family", wp_get_font_name (oldfmt.font),
2473 "family-set", !oldfmt.cs.font,
2476 gtk_widget_show_all (dialog);
2477 response = gtk_dialog_run (GTK_DIALOG (dialog));
2478 if (response == GTK_RESPONSE_OK) {
2480 g_object_get( dialog,
2482 "bold-set", &bold_set,
2483 "underline", &underline,
2484 "underline-set", &underline_set,
2486 "italic-set", &italic_set,
2487 "strikethrough", &strikethrough,
2488 "strikethrough-set", &strikethrough_set,
2490 "color-set", &color_set,
2492 "size-set", &font_size_set,
2493 "family", &font_name,
2494 "family-set", &font_set,
2495 "position", &position,
2496 "position-set", &position_set,
2501 if (response == GTK_RESPONSE_OK) {
2502 memset(&fmt, 0, sizeof(fmt));
2508 fmt.italic = italic;
2509 fmt.cs.italic = TRUE;
2511 if (underline_set) {
2512 fmt.underline = underline;
2513 fmt.cs.underline = TRUE;
2515 if (strikethrough_set) {
2516 fmt.strikethrough = strikethrough;
2517 fmt.cs.strikethrough = TRUE;
2522 ? TEXT_POSITION_NORMAL
2523 : ( ( position == 1 )
2524 ? TEXT_POSITION_SUPERSCRIPT
2525 : TEXT_POSITION_SUBSCRIPT );
2526 fmt.cs.text_position = TRUE;
2530 fmt.cs.color = TRUE;
2533 fmt.font = wp_get_font_index(font_name,
2538 if (font_size_set) {
2539 fmt.font_size = wp_get_font_size_index(
2540 font_size, DEFAULT_FONT_SIZE);
2541 fmt.cs.font_size = TRUE;
2543 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2544 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2546 gtk_widget_destroy (dialog);
2548 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2552 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2554 ModestMsgEditWindowPrivate *priv;
2556 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2557 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2559 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2561 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2566 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2568 ModestMsgEditWindowPrivate *priv;
2570 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2571 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2573 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2575 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2580 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2582 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2584 priv->can_undo = can_undo;
2588 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2590 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2592 priv->can_redo = can_redo;
2596 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2598 ModestMsgEditWindowPrivate *priv;
2599 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2600 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2602 return priv->can_undo;
2606 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2608 ModestMsgEditWindowPrivate *priv;
2609 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2610 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2612 return priv->can_redo;
2617 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2620 GtkTextIter match_start, match_end;
2622 if (image_id == NULL)
2625 gtk_text_buffer_get_start_iter (buffer, &iter);
2627 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2628 GSList *tags = gtk_text_iter_get_tags (&match_start);
2630 for (node = tags; node != NULL; node = g_slist_next (node)) {
2631 GtkTextTag *tag = (GtkTextTag *) node->data;
2632 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2633 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2634 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2636 offset = gtk_text_iter_get_offset (&match_start);
2637 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2638 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2642 gtk_text_iter_forward_char (&iter);
2647 message_is_empty (ModestMsgEditWindow *window)
2649 ModestMsgEditWindowPrivate *priv = NULL;
2651 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2652 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2654 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2655 * so we can ignore markup.
2657 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2660 count = gtk_text_buffer_get_char_count (buf);
2666 msg_body_focus (GtkWidget *focus,
2667 GdkEventFocus *event,
2671 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2676 recpt_field_changed (GtkTextBuffer *buffer,
2677 ModestMsgEditWindow *editor)
2679 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2683 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2685 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2689 reset_modified (ModestMsgEditWindow *editor)
2691 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2692 GtkTextBuffer *buffer;
2694 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2695 gtk_text_buffer_set_modified (buffer, FALSE);
2696 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2697 gtk_text_buffer_set_modified (buffer, FALSE);
2698 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2699 gtk_text_buffer_set_modified (buffer, FALSE);
2700 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2704 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2706 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2707 GtkTextBuffer *buffer;
2709 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2710 if (gtk_text_buffer_get_modified (buffer))
2712 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2713 if (gtk_text_buffer_get_modified (buffer))
2715 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2716 if (gtk_text_buffer_get_modified (buffer))
2718 if (gtk_text_buffer_get_modified (priv->text_buffer))
2728 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2730 ModestMsgEditWindowPrivate *priv = NULL;
2732 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2733 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2735 /* check if there's no recipient added */
2736 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2737 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2738 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2739 /* no recipient contents, then select contacts */
2740 modest_msg_edit_window_open_addressbook (window, NULL);
2744 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2745 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2748 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2749 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2752 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2753 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2757 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2758 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2759 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2766 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2767 ModestMsgEditWindow *window)
2769 modest_msg_edit_window_offer_attach_file (window);
2773 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2775 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2777 return priv->clipboard_text;
2781 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2783 ModestMsgEditWindow *window)
2785 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2786 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2788 if (!GTK_WIDGET_VISIBLE (window))
2791 text = gtk_clipboard_wait_for_text (selection_clipboard);
2793 if (priv->clipboard_text != NULL) {
2794 g_free (priv->clipboard_text);
2796 priv->clipboard_text = text;
2798 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2801 subject_field_move_cursor (GtkEntry *entry,
2802 GtkMovementStep step,
2807 if (!GTK_WIDGET_VISIBLE (window))
2810 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2814 update_window_title (ModestMsgEditWindow *window)
2816 ModestMsgEditWindowPrivate *priv = NULL;
2817 const gchar *subject;
2819 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2820 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2821 if (subject == NULL || subject[0] == '\0')
2822 subject = _("mail_va_new_email");
2824 gtk_window_set_title (GTK_WINDOW (window), subject);
2829 subject_field_changed (GtkEditable *editable,
2830 ModestMsgEditWindow *window)
2832 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2833 update_window_title (window);
2834 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2835 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2839 subject_field_insert_text (GtkEditable *editable,
2841 gint new_text_length,
2843 ModestMsgEditWindow *window)
2845 GString *result = g_string_new ("");
2847 gint result_len = 0;
2848 const gchar *entry_text = NULL;
2851 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2852 old_length = g_utf8_strlen (entry_text, -1);
2854 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2855 gunichar c = g_utf8_get_char_validated (current, 8);
2856 /* Invalid unichar, stop */
2862 result = g_string_append_unichar (result, c);
2866 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2867 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2870 /* Prevent endless recursion */
2871 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2872 g_signal_emit_by_name (editable, "insert-text",
2873 (gpointer) result->str, (gpointer) result->len,
2874 (gpointer) position, (gpointer) window);
2875 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2879 if (result_len + old_length > 1000) {
2880 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2881 dgettext("hildon-common-strings",
2882 "ckdg_ib_maximum_characters_reached"));
2885 g_string_free (result, TRUE);
2889 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2892 ModestMsgEditWindowPrivate *priv = NULL;
2894 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2895 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2897 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2900 gtk_widget_show_all (priv->find_toolbar);
2901 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2903 gtk_widget_hide_all (priv->find_toolbar);
2904 gtk_widget_grab_focus (priv->msg_body);
2910 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2912 GtkTextIter *match_start,
2913 GtkTextIter *match_end)
2915 GtkTextIter end_iter;
2916 gchar *str_casefold;
2919 gchar *range_casefold;
2922 gboolean result = FALSE;
2929 gtk_text_iter_forward_to_end (&end_iter);
2931 str_casefold = g_utf8_casefold (str, -1);
2932 str_chars_n = strlen (str);
2934 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2935 range_casefold = g_utf8_casefold (range_text, -1);
2936 range_chars_n = strlen (range_casefold);
2938 if (range_chars_n < str_chars_n) {
2939 g_free (str_casefold);
2940 g_free (range_text);
2941 g_free (range_casefold);
2945 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2946 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2947 if (!g_utf8_collate (range_subtext, str_casefold)) {
2948 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2950 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2951 match_start, match_end, NULL);
2952 g_free (found_text);
2954 g_free (range_subtext);
2958 g_free (str_casefold);
2959 g_free (range_text);
2960 g_free (range_casefold);
2967 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2968 ModestMsgEditWindow *window)
2970 gchar *current_search = NULL;
2971 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2973 GtkTextIter selection_start, selection_end;
2974 GtkTextIter match_start, match_end;
2975 gboolean continue_search = FALSE;
2977 if (message_is_empty (window)) {
2978 g_free (priv->last_search);
2979 priv->last_search = NULL;
2980 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
2984 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
2985 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2986 g_free (current_search);
2987 g_free (priv->last_search);
2988 priv->last_search = NULL;
2989 /* Information banner about empty search */
2990 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
2994 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
2995 continue_search = TRUE;
2997 g_free (priv->last_search);
2998 priv->last_search = g_strdup (current_search);
3001 if (continue_search) {
3002 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3003 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3004 &match_start, &match_end);
3006 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3008 GtkTextIter buffer_start;
3009 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3010 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3011 &match_start, &match_end);
3013 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3016 /* Mark as selected the string found in search */
3018 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3019 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3021 g_free (priv->last_search);
3022 priv->last_search = NULL;
3024 g_free (current_search);
3028 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3029 ModestMsgEditWindow *window)
3031 GtkToggleAction *toggle;
3032 ModestWindowPrivate *parent_priv;
3033 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3035 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3036 gtk_toggle_action_set_active (toggle, FALSE);
3040 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3042 ModestMsgEditWindowPrivate *priv;
3044 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3049 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3052 ModestMsgEditWindowPrivate *priv;
3054 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3060 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3063 ModestMsgEditWindowPrivate *priv;
3064 TnyHeader *header = NULL;
3066 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3067 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3069 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3070 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3072 if (priv->draft_msg != NULL) {
3073 header = tny_msg_get_header (priv->draft_msg);
3074 if (TNY_IS_HEADER (header)) {
3075 modest_window_mgr_unregister_header (mgr, header);
3077 g_object_unref (priv->draft_msg);
3080 if (draft != NULL) {
3081 g_object_ref (draft);
3082 header = tny_msg_get_header (draft);
3083 if (TNY_IS_HEADER (header))
3084 modest_window_mgr_register_header (mgr, header);
3085 if (priv->msg_uid) {
3086 g_free (priv->msg_uid);
3087 priv->msg_uid = NULL;
3089 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3092 priv->draft_msg = draft;
3096 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3097 GtkTextIter *start, GtkTextIter *end,
3100 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3101 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3104 if (tag == NULL+13) return;
3105 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3106 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3107 replace_with_attachments (window, priv->attachments);
3112 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3115 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3117 g_return_if_fail (TNY_IS_MIME_PART (part));
3118 priv->attachments = g_list_prepend (priv->attachments, part);
3119 g_object_ref (part);
3120 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3121 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3122 gtk_widget_show_all (priv->attachments_caption);
3123 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3127 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3129 ModestMsgEditWindowPrivate *priv;
3131 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3132 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3134 return priv->msg_uid;
3138 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3139 ModestMsgEditWindowWidgetType widget_type)
3141 ModestMsgEditWindowPrivate *priv;
3143 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3144 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3146 switch (widget_type) {
3147 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3148 return priv->msg_body;
3150 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3151 return priv->to_field;
3153 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3154 return priv->cc_field;
3156 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3157 return priv->bcc_field;
3159 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3160 return priv->subject_field;
3162 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3163 return priv->attachments_view;
3171 remove_tags (WPTextBuffer *buffer)
3173 GtkTextIter start, end;
3175 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3176 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3178 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);