1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
49 #include <modest-runtime.h>
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-tny-account.h"
60 #include "modest-address-book.h"
61 #include "modest-text-utils.h"
62 #include <tny-simple-list.h>
63 #include <wptextview.h>
64 #include <wptextbuffer.h>
65 #include "modest-scroll-area.h"
66 #include "modest-msg-edit-window-ui-dimming.h"
68 #include "modest-hildon-includes.h"
69 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-color-chooser.h>
72 #include "widgets/modest-msg-edit-window-ui.h"
73 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #include <libgnomevfs/gnome-vfs-mime.h>
78 #include "modest-maemo-utils.h"
81 #define DEFAULT_FONT_SIZE 3
82 #define DEFAULT_FONT 2
83 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
84 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
85 #define DEFAULT_MAIN_VBOX_SPACING 6
86 #define SUBJECT_MAX_LENGTH 1000
87 #define IMAGE_MAX_WIDTH 560
88 #define DEFAULT_FONT_SCALE 1.5
90 static gboolean is_wp_text_buffer_started = FALSE;
92 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
93 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
94 static void modest_msg_edit_window_finalize (GObject *obj);
96 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
97 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
98 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
100 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
101 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
102 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
103 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
104 GtkTextIter *start, GtkTextIter *end,
106 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
107 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
108 static void subject_field_insert_text (GtkEditable *editable,
110 gint new_text_length,
112 ModestMsgEditWindow *window);
113 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
115 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
117 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
119 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
120 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
121 GdkEventWindowState *event,
123 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
124 ModestRecptEditor *editor);
125 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
126 ModestMsgEditWindow *window);
128 /* ModestWindow methods implementation */
129 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
130 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
131 gboolean show_toolbar);
132 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
134 ModestMsgEditWindow *window);
135 static void subject_field_move_cursor (GtkEntry *entry,
136 GtkMovementStep step,
140 static void update_window_title (ModestMsgEditWindow *window);
143 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
144 ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
149 GtkTextIter *match_start,
150 GtkTextIter *match_end);
152 static void remove_tags (WPTextBuffer *buffer);
154 static void on_account_removed (TnyAccountStore *account_store,
158 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
160 static void init_window (ModestMsgEditWindow *obj);
162 static void DEBUG_BUFFER (WPTextBuffer *buffer)
167 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
168 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
169 while (!gtk_text_iter_is_end (&iter)) {
170 GString *output = g_string_new ("");
171 GSList *toggled_tags;
174 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
175 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
176 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
177 GtkTextTag *tag = (GtkTextTag *) node->data;
179 g_object_get (G_OBJECT (tag), "name", &name, NULL);
180 output = g_string_append (output, name);
181 g_string_append (output, " ");
183 output = g_string_append (output, "] OPENED [ ");
184 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
185 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
186 GtkTextTag *tag = (GtkTextTag *) node->data;
188 g_object_get (G_OBJECT (tag), "name", &name, NULL);
189 output = g_string_append (output, name);
190 g_string_append (output, " ");
192 output = g_string_append (output, "]\n");
193 g_message ("%s", output->str);
194 g_string_free (output, TRUE);
195 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
197 g_message ("END BUFFER");
202 /* static gboolean */
203 /* on_key_pressed (GtkWidget *self, */
204 /* GdkEventKey *event, */
205 /* gpointer user_data); */
207 /* list my signals */
214 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
215 struct _ModestMsgEditWindowPrivate {
217 GtkWidget *header_box;
219 ModestPairList *from_field_protos;
220 GtkWidget *from_field;
224 GtkWidget *bcc_field;
225 GtkWidget *subject_field;
226 GtkWidget *attachments_view;
227 GtkWidget *priority_icon;
228 GtkWidget *add_attachment_button;
230 GtkWidget *cc_caption;
231 GtkWidget *bcc_caption;
232 gboolean update_caption_visibility;
233 GtkWidget *attachments_caption;
235 GtkTextBuffer *text_buffer;
237 GtkWidget *font_size_toolitem;
238 GtkWidget *font_face_toolitem;
239 GtkWidget *font_color_button;
240 GSList *font_items_group;
241 GtkWidget *font_tool_button_label;
242 GSList *size_items_group;
243 GtkWidget *size_tool_button_label;
245 GtkWidget *find_toolbar;
249 GtkWidget *scroll_area;
250 gint last_vadj_upper;
256 TnyHeaderFlags priority_flags;
258 gboolean can_undo, can_redo;
259 gulong clipboard_change_handler_id;
260 gulong default_clipboard_change_handler_id;
261 gulong account_removed_handler_id;
262 gchar *clipboard_text;
271 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
272 MODEST_TYPE_MSG_EDIT_WINDOW, \
273 ModestMsgEditWindowPrivate))
275 static GtkWindowClass *parent_class = NULL;
277 /* uncomment the following if you have defined any signals */
278 /* static guint signals[LAST_SIGNAL] = {0}; */
281 modest_msg_edit_window_get_type (void)
283 static GType my_type = 0;
285 static const GTypeInfo my_info = {
286 sizeof(ModestMsgEditWindowClass),
287 NULL, /* base init */
288 NULL, /* base finalize */
289 (GClassInitFunc) modest_msg_edit_window_class_init,
290 NULL, /* class finalize */
291 NULL, /* class data */
292 sizeof(ModestMsgEditWindow),
294 (GInstanceInitFunc) modest_msg_edit_window_init,
297 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
298 "ModestMsgEditWindow",
306 save_state (ModestWindow *self)
308 modest_widget_memory_save (modest_runtime_get_conf(),
309 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
314 restore_settings (ModestMsgEditWindow *self)
316 ModestConf *conf = NULL;
318 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
320 conf = modest_runtime_get_conf ();
321 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
322 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
323 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
324 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
325 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
326 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
327 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
328 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
330 /* set initial state of cc and bcc */
331 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
332 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
333 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
334 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
335 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
336 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
338 /* Dim at start clipboard actions */
339 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
340 gtk_action_set_sensitive (action, FALSE);
341 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
342 gtk_action_set_sensitive (action, FALSE);
343 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
344 gtk_action_set_sensitive (action, FALSE);
346 modest_widget_memory_restore (conf,
347 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
352 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
354 GObjectClass *gobject_class;
355 ModestWindowClass *modest_window_class;
356 gobject_class = (GObjectClass*) klass;
357 modest_window_class = (ModestWindowClass*) klass;
359 parent_class = g_type_class_peek_parent (klass);
360 gobject_class->finalize = modest_msg_edit_window_finalize;
362 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
363 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
364 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
365 modest_window_class->save_state_func = save_state;
366 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
368 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
372 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
374 ModestMsgEditWindowPrivate *priv;
375 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
377 priv->msg_body = NULL;
378 priv->from_field = NULL;
379 priv->to_field = NULL;
380 priv->cc_field = NULL;
381 priv->bcc_field = NULL;
382 priv->subject_field = NULL;
383 priv->attachments = NULL;
387 priv->cc_caption = NULL;
388 priv->bcc_caption = NULL;
389 priv->update_caption_visibility = FALSE;
391 priv->priority_flags = 0;
393 priv->find_toolbar = NULL;
394 priv->last_search = NULL;
396 priv->draft_msg = NULL;
397 priv->outbox_msg = NULL;
398 priv->msg_uid = NULL;
400 priv->can_undo = FALSE;
401 priv->can_redo = FALSE;
402 priv->clipboard_change_handler_id = 0;
403 priv->default_clipboard_change_handler_id = 0;
404 priv->account_removed_handler_id = 0;
405 priv->clipboard_text = NULL;
408 priv->last_vadj_upper = 0;
410 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
411 GTK_WINDOW(obj),"applications_email_editor");
413 if (!is_wp_text_buffer_started) {
414 is_wp_text_buffer_started = TRUE;
415 wp_text_buffer_library_init ();
422 /* FIXME: this is a dup from the one in gtk/ */
425 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
427 static ModestPairList*
428 get_transports (void)
430 GSList *transports = NULL;
432 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
433 GSList *accounts = modest_account_mgr_account_names (account_mgr,
434 TRUE /* only enabled accounts. */);
436 GSList *cursor = accounts;
438 gchar *account_name = cursor->data;
439 gchar *from_string = NULL;
441 from_string = modest_account_mgr_get_from_string (account_mgr,
445 if (from_string && account_name) {
446 gchar *name = account_name;
447 ModestPair *pair = modest_pair_new ((gpointer) name,
448 (gpointer) from_string , TRUE);
449 transports = g_slist_prepend (transports, pair);
452 cursor = cursor->next;
454 g_slist_free (accounts); /* only free the accounts, not the elements,
455 * because they are used in the pairlist */
459 void vadj_changed (GtkAdjustment *adj,
460 ModestMsgEditWindow *window)
462 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
464 GdkRectangle rectangle, cursor_rectangle;
465 GtkTextIter position;
469 /* We detect if cursor is visible using the full height, not only the center. This
471 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
472 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
474 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
475 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
477 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
478 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
480 if (gtk_widget_is_focus (priv->msg_body) &&
482 if (priv->last_vadj_upper != adj->upper) {
485 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
486 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
487 insert, 0.1, FALSE, 0.0, 0.0);
490 priv->last_vadj_upper = adj->upper;
495 connect_signals (ModestMsgEditWindow *obj)
497 ModestMsgEditWindowPrivate *priv;
499 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
501 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
502 G_CALLBACK (text_buffer_refresh_attributes), obj);
503 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
504 G_CALLBACK (text_buffer_can_undo), obj);
505 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
506 G_CALLBACK (text_buffer_can_redo), obj);
507 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
508 G_CALLBACK (body_changed), obj);
509 g_signal_connect (G_OBJECT (obj), "window-state-event",
510 G_CALLBACK (modest_msg_edit_window_window_state_event),
512 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
513 G_CALLBACK (text_buffer_apply_tag), obj);
514 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
515 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
516 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
517 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
518 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
519 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
521 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
522 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
524 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
525 G_CALLBACK (msg_body_focus), obj);
526 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
527 G_CALLBACK (msg_body_focus), obj);
528 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
529 "changed", G_CALLBACK (recpt_field_changed), obj);
530 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
531 "changed", G_CALLBACK (recpt_field_changed), obj);
532 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
533 "changed", G_CALLBACK (recpt_field_changed), obj);
534 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
535 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
536 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
538 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
539 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
541 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
543 G_CALLBACK (vadj_changed),
546 priv->clipboard_change_handler_id =
547 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
548 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
549 priv->default_clipboard_change_handler_id =
550 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
551 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
556 menubar_to_menu (GtkUIManager *ui_manager)
558 GtkWidget *main_menu;
560 /* Get the menubar from the UI manager */
561 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
567 init_window (ModestMsgEditWindow *obj)
569 GtkWidget *from_caption, *to_caption, *subject_caption;
570 GtkWidget *main_vbox;
571 ModestMsgEditWindowPrivate *priv;
572 GtkActionGroup *action_group;
573 ModestWindowPrivate *parent_priv;
574 GdkPixbuf *window_icon = NULL;
575 GError *error = NULL;
577 GtkSizeGroup *size_group;
579 GtkWidget *subject_box;
580 GtkWidget *attachment_icon;
581 GtkWidget *window_box;
582 #if (GTK_MINOR_VERSION >= 10)
583 GdkAtom deserialize_type;
585 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
586 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
588 parent_priv->ui_manager = gtk_ui_manager_new();
589 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
590 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
592 /* Add common actions */
593 gtk_action_group_add_actions (action_group,
594 modest_msg_edit_action_entries,
595 G_N_ELEMENTS (modest_msg_edit_action_entries),
597 gtk_action_group_add_toggle_actions (action_group,
598 modest_msg_edit_toggle_action_entries,
599 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
601 gtk_action_group_add_radio_actions (action_group,
602 modest_msg_edit_alignment_radio_action_entries,
603 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
605 G_CALLBACK (modest_ui_actions_on_change_justify),
607 gtk_action_group_add_radio_actions (action_group,
608 modest_msg_edit_priority_action_entries,
609 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
611 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
613 gtk_action_group_add_radio_actions (action_group,
614 modest_msg_edit_file_format_action_entries,
615 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
616 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
617 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
619 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
620 g_object_unref (action_group);
622 /* Load the UI definition */
623 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
626 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
627 g_clear_error (&error);
630 /* Add accelerators */
631 gtk_window_add_accel_group (GTK_WINDOW (obj),
632 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
634 parent_priv->menubar = NULL;
636 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
638 /* Note: This ModestPairList* must exist for as long as the combo
639 * that uses it, because the ModestComboBox uses the ID opaquely,
640 * so it can't know how to manage its memory. */
641 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
643 priv->to_field = modest_recpt_editor_new ();
644 priv->cc_field = modest_recpt_editor_new ();
645 priv->bcc_field = modest_recpt_editor_new ();
646 subject_box = gtk_hbox_new (FALSE, 0);
647 priv->priority_icon = gtk_image_new ();
648 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
649 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
650 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
651 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
652 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
653 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
654 priv->add_attachment_button = gtk_button_new ();
655 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
656 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
657 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
658 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
659 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
660 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
661 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
662 priv->attachments_view = modest_attachments_view_new (NULL);
664 priv->header_box = gtk_vbox_new (FALSE, 0);
666 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
667 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
668 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
669 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
670 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
671 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
672 g_object_unref (size_group);
674 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
675 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
676 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
677 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
678 gtk_size_group_add_widget (size_group, priv->subject_field);
679 gtk_size_group_add_widget (size_group, priv->attachments_view);
680 g_object_unref (size_group);
682 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
683 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
684 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
685 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
686 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
687 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
688 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
691 priv->msg_body = wp_text_view_new ();
692 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
693 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
694 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
695 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
696 #if (GTK_MINOR_VERSION >= 10)
697 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
698 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
700 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
701 deserialize_type, TRUE);
703 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
705 priv->find_toolbar = hildon_find_toolbar_new (NULL);
706 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
708 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
710 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
711 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
712 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
713 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
715 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
717 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
718 frame = gtk_frame_new (NULL);
719 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
721 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
722 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
723 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
725 G_CALLBACK (vadj_changed),
727 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
729 window_box = gtk_vbox_new (FALSE, 0);
730 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
731 gtk_container_add (GTK_CONTAINER(obj), window_box);
732 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
733 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
735 /* Set window icon */
736 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
738 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
739 g_object_unref (window_icon);
745 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
747 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
749 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
750 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
751 priv->clipboard_change_handler_id))
752 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
753 priv->clipboard_change_handler_id);
754 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
755 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
756 priv->default_clipboard_change_handler_id))
757 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
758 priv->default_clipboard_change_handler_id);
760 if (priv->account_removed_handler_id &&
761 g_signal_handler_is_connected (modest_runtime_get_account_store (),
762 priv->account_removed_handler_id))
763 g_signal_handler_disconnect(modest_runtime_get_account_store (),
764 priv->account_removed_handler_id);
768 modest_msg_edit_window_finalize (GObject *obj)
770 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
772 /* Sanity check: shouldn't be needed, the window mgr should
773 call this function before */
774 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
776 if (priv->clipboard_text != NULL) {
777 g_free (priv->clipboard_text);
778 priv->clipboard_text = NULL;
781 if (priv->draft_msg != NULL) {
782 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
783 if (TNY_IS_HEADER (header)) {
784 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
785 modest_window_mgr_unregister_header (mgr, header);
787 g_object_unref (priv->draft_msg);
788 priv->draft_msg = NULL;
790 if (priv->outbox_msg != NULL) {
791 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
792 if (TNY_IS_HEADER (header)) {
793 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
794 modest_window_mgr_unregister_header (mgr, header);
796 g_object_unref (priv->outbox_msg);
797 priv->outbox_msg = NULL;
799 g_free (priv->msg_uid);
800 g_free (priv->last_search);
801 g_slist_free (priv->font_items_group);
802 g_slist_free (priv->size_items_group);
803 g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
804 g_list_free (priv->attachments);
805 g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
806 g_list_free (priv->images);
808 /* This had to stay alive for as long as the combobox that used it: */
809 modest_pair_list_free (priv->from_field_protos);
811 G_OBJECT_CLASS(parent_class)->finalize (obj);
815 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
817 GdkPixbufLoader *loader;
820 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
825 tny_stream_reset (TNY_STREAM (stream));
826 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
827 unsigned char read_buffer[128];
829 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
830 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
834 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
835 g_object_ref (pixbuf);
836 gdk_pixbuf_loader_close (loader, NULL);
837 g_object_unref (loader);
839 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
840 GdkPixbuf *new_pixbuf;
842 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
843 gdk_pixbuf_get_width (pixbuf);
844 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
845 g_object_unref (pixbuf);
853 replace_with_images (ModestMsgEditWindow *self, GList *attachments)
855 ModestMsgEditWindowPrivate *priv;
858 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
860 for (node = attachments; node != NULL; node = g_list_next (node)) {
861 TnyMimePart *part = (TnyMimePart *) node->data;
862 const gchar *cid = tny_mime_part_get_content_id (part);
863 const gchar *mime_type = tny_mime_part_get_content_type (part);
864 if ((cid != NULL)&&(mime_type != NULL)) {
865 TnyStream *stream = tny_mime_part_get_stream (part);
866 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
867 g_object_unref (stream);
869 if (pixbuf != NULL) {
870 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
871 g_object_unref (pixbuf);
878 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
880 TnyMimePart *parent = NULL;
881 const gchar *content_type = NULL;
882 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
884 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
886 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
887 parent = g_object_ref (msg);
888 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
889 TnyList *parts = TNY_LIST (tny_simple_list_new ());
892 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
893 iter = tny_list_create_iterator (parts);
894 while (!tny_iterator_is_done (iter)) {
896 part = TNY_MIME_PART (tny_iterator_get_current (iter));
897 content_type = tny_mime_part_get_content_type (part);
898 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
902 g_object_unref (part);
904 tny_iterator_next (iter);
906 g_object_unref (iter);
907 g_object_unref (parts);
910 if (parent != NULL) {
911 TnyList *parts = TNY_LIST (tny_simple_list_new ());
914 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
915 iter = tny_list_create_iterator (parts);
916 while (!tny_iterator_is_done (iter)) {
918 part = TNY_MIME_PART (tny_iterator_get_current (iter));
919 content_type = tny_mime_part_get_content_type (part);
920 if (content_type && g_str_has_prefix (content_type, "image/")) {
921 priv->images = g_list_prepend (priv->images, part);
923 g_object_unref (part);
925 tny_iterator_next (iter);
927 g_object_unref (iter);
928 g_object_unref (parts);
929 g_object_unref (parent);
934 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
937 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
939 for (node = attachments; node != NULL; node = g_list_next (node)) {
940 TnyMimePart *part = (TnyMimePart *) node->data;
941 const gchar *cid = tny_mime_part_get_content_id (part);
943 char *invalid = NULL;
944 gint int_cid = strtol (cid, &invalid, 10);
945 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
946 priv->last_cid = int_cid;
954 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
957 const gchar *to, *cc, *bcc, *subject;
959 ModestMsgEditWindowPrivate *priv;
961 TnyHeaderFlags priority_flags;
962 TnyFolder *msg_folder;
963 gboolean is_html = FALSE;
965 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
966 g_return_if_fail (TNY_IS_MSG (msg));
968 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
970 header = tny_msg_get_header (msg);
971 to = tny_header_get_to (header);
972 cc = tny_header_get_cc (header);
973 bcc = tny_header_get_bcc (header);
974 subject = tny_header_get_subject (header);
975 priority_flags = tny_header_get_priority (header);
978 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
980 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
981 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
982 gtk_widget_show (priv->cc_caption);
983 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
984 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
985 gtk_widget_hide (priv->cc_caption);
988 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
989 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
990 gtk_widget_show (priv->bcc_caption);
991 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
992 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
993 gtk_widget_hide (priv->bcc_caption);
996 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
997 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1000 update_window_title (self);
1002 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1003 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1005 if ((body == NULL)||(body[0] == '\0')) {
1007 body = modest_text_utils_convert_to_html ("");
1010 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1011 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1014 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1017 /* Add attachments to the view */
1018 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1019 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1020 if (priv->attachments == NULL) {
1021 gtk_widget_hide (priv->attachments_caption);
1023 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1024 gtk_widget_show_all (priv->attachments_caption);
1026 get_related_images (self, msg);
1027 update_last_cid (self, priv->attachments);
1028 update_last_cid (self, priv->images);
1029 replace_with_images (self, priv->images);
1031 if (preserve_is_rich && !is_html) {
1032 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1033 /* Get the default format required from configuration */
1034 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1035 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1038 /* Set the default focus depending on having already a To: field or not */
1039 if ((!to)||(*to == '\0')) {
1040 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1042 gtk_widget_grab_focus (priv->msg_body);
1045 /* TODO: lower priority, select in the From: combo to the
1046 value that comes from msg <- not sure, should it be
1049 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1051 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1052 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1054 modest_msg_edit_window_reset_modified (self);
1056 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1057 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1058 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1060 if (priv->msg_uid) {
1061 g_free (priv->msg_uid);
1062 priv->msg_uid = NULL;
1065 /* we should set a reference to the incoming message if it is a draft */
1066 msg_folder = tny_msg_get_folder (msg);
1068 if (modest_tny_folder_is_local_folder (msg_folder)) {
1069 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1070 if (type == TNY_FOLDER_TYPE_INVALID)
1071 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1073 if (type == TNY_FOLDER_TYPE_DRAFTS)
1074 priv->draft_msg = g_object_ref(msg);
1075 if (type == TNY_FOLDER_TYPE_OUTBOX)
1076 priv->outbox_msg = g_object_ref(msg);
1077 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1079 g_object_unref (msg_folder);
1084 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1087 GList *item_children, *node;
1088 GtkWidget *bin_child;
1090 bin_child = gtk_bin_get_child (GTK_BIN(item));
1092 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1094 for (node = item_children; node != NULL; node = g_list_next (node)) {
1095 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1096 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1099 g_list_free (item_children);
1103 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1106 GList *item_children, *node;
1108 box = gtk_bin_get_child (GTK_BIN (item));
1109 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1110 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1112 for (node = item_children; node != NULL; node = g_list_next (node)) {
1113 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1114 if (GTK_IS_TOGGLE_BUTTON (node->data))
1115 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1116 else if (GTK_IS_BUTTON (node->data))
1117 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1119 g_list_free (item_children);
1124 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1126 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1127 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1128 GtkWidget *placeholder;
1129 GtkWidget *tool_item;
1134 GtkWidget *sizes_menu;
1135 GtkWidget *fonts_menu;
1136 GSList *radio_group = NULL;
1137 GSList *node = NULL;
1141 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1142 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1144 /* Font color placeholder */
1145 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1146 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1149 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1150 priv->font_color_button = hildon_color_button_new ();
1151 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1152 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1153 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1154 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1155 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1156 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1157 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1159 G_CALLBACK (modest_msg_edit_window_color_button_change),
1162 /* Font size and face placeholder */
1163 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1164 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1166 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1167 priv->size_tool_button_label = gtk_label_new (NULL);
1168 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1169 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1170 size_text,"</span>", NULL);
1171 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1173 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1174 sizes_menu = gtk_menu_new ();
1175 priv->size_items_group = NULL;
1177 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1178 GtkWidget *size_menu_item;
1180 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1181 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1182 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1183 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1184 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1185 gtk_widget_show (size_menu_item);
1187 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1191 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1192 GtkWidget *item = (GtkWidget *) node->data;
1193 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1197 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1198 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1199 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1200 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1201 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1202 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1203 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1204 priv->font_size_toolitem = tool_item;
1207 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1208 priv->font_tool_button_label = gtk_label_new (NULL);
1209 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1210 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1212 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1213 fonts_menu = gtk_menu_new ();
1214 priv->font_items_group = NULL;
1216 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1217 GtkWidget *font_menu_item;
1218 GtkWidget *child_label;
1220 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1221 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1222 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1223 wp_get_font_name (font_index), "</span>", NULL);
1224 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1227 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1228 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1229 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1230 gtk_widget_show (font_menu_item);
1232 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1235 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1236 GtkWidget *item = (GtkWidget *) node->data;
1237 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1240 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1241 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1242 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1243 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1244 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1245 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1246 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1247 priv->font_face_toolitem = tool_item;
1249 /* Set expand and homogeneous for remaining items */
1250 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1251 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1252 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1253 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1254 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1255 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1256 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1257 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1258 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1260 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1261 will not show the tool items added to the placeholders) */
1262 gtk_widget_show_all (parent_priv->toolbar);
1264 /* Set the no show all *after* showing all items. We do not
1265 want the toolbar to be shown with a show all because it
1266 could go agains the gconf setting regarding showing or not
1267 the toolbar of the editor window */
1268 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1274 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1277 ModestWindowPrivate *parent_priv;
1278 ModestMsgEditWindowPrivate *priv;
1279 ModestPair *account_pair = NULL;
1280 ModestDimmingRulesGroup *menu_rules_group = NULL;
1281 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1282 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1283 ModestWindowMgr *mgr = NULL;
1285 g_return_val_if_fail (msg, NULL);
1286 g_return_val_if_fail (account_name, NULL);
1288 mgr = modest_runtime_get_window_mgr ();
1290 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1292 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1293 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1295 /* Menubar. Update the state of some toggles */
1296 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1297 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1298 priv->from_field_protos = get_transports ();
1299 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1300 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1301 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1304 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1306 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1308 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1310 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1311 if (account_pair != NULL)
1312 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1314 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1315 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1316 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1317 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1318 /* Add common dimming rules */
1319 modest_dimming_rules_group_add_rules (menu_rules_group,
1320 modest_msg_edit_window_menu_dimming_entries,
1321 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1322 MODEST_WINDOW (obj));
1323 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1324 modest_msg_edit_window_toolbar_dimming_entries,
1325 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1326 MODEST_WINDOW (obj));
1327 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1328 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1329 MODEST_WINDOW (obj));
1330 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1331 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1332 MODEST_WINDOW (obj));
1333 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1334 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1335 MODEST_WINDOW (obj));
1336 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1337 modest_msg_edit_window_clipboard_dimming_entries,
1338 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1339 MODEST_WINDOW (obj));
1340 /* Insert dimming rules group for this window */
1341 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1342 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1343 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1344 /* Checks the dimming rules */
1345 g_object_unref (menu_rules_group);
1346 g_object_unref (toolbar_rules_group);
1347 g_object_unref (clipboard_rules_group);
1349 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1351 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1353 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1354 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1355 priv->update_caption_visibility = TRUE;
1357 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1359 /* Track account-removed signal, this window should be closed
1360 in the case we're creating a mail associated to the account
1362 priv->account_removed_handler_id =
1363 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1365 G_CALLBACK(on_account_removed),
1368 return (ModestWindow*) obj;
1372 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1374 GString **string_buffer = (GString **) user_data;
1376 *string_buffer = g_string_append (*string_buffer, buffer);
1382 * @result: A new string which should be freed with g_free().
1385 get_formatted_data (ModestMsgEditWindow *edit_window)
1387 ModestMsgEditWindowPrivate *priv;
1388 GString *string_buffer = g_string_new ("");
1390 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1392 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1394 return g_string_free (string_buffer, FALSE);
1399 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1402 const gchar *account_name;
1403 ModestMsgEditWindowPrivate *priv;
1405 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1407 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1409 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1410 g_return_val_if_fail (account_name, NULL);
1413 /* don't free these (except from) */
1414 data = g_slice_new0 (MsgData);
1415 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1417 data->account_name = g_strdup (account_name);
1418 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1419 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1420 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1421 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1422 if (priv->draft_msg) {
1423 data->draft_msg = g_object_ref (priv->draft_msg);
1424 } else if (priv->outbox_msg) {
1425 data->draft_msg = g_object_ref (priv->outbox_msg);
1427 data->draft_msg = NULL;
1430 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1432 gtk_text_buffer_get_bounds (buf, &b, &e);
1433 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1435 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1436 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1438 data->html_body = NULL;
1440 /* deep-copy the data */
1441 GList *cursor = priv->attachments;
1442 data->attachments = NULL;
1444 if (!(TNY_IS_MIME_PART(cursor->data))) {
1445 g_warning ("strange data in attachment list");
1446 cursor = g_list_next (cursor);
1449 data->attachments = g_list_append (data->attachments,
1450 g_object_ref (cursor->data));
1451 cursor = g_list_next (cursor);
1454 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1455 cursor = priv->images;
1456 data->images = NULL;
1459 if (!(TNY_IS_MIME_PART(cursor->data))) {
1460 g_warning ("strange data in attachment list");
1461 cursor = g_list_next (cursor);
1464 cid = tny_mime_part_get_content_id (cursor->data);
1466 gchar *image_tag_id;
1467 GtkTextTag *image_tag;
1469 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1470 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1471 g_free (image_tag_id);
1473 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1475 ((gtk_text_iter_has_tag (&iter, image_tag))||
1476 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1477 data->images = g_list_append (data->images,
1478 g_object_ref (cursor->data));
1480 cursor = g_list_next (cursor);
1483 data->priority_flags = priv->priority_flags;
1490 unref_gobject (GObject *obj, gpointer data)
1492 if (!G_IS_OBJECT(obj))
1494 g_object_unref (obj);
1498 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1501 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1509 g_free (data->from);
1510 g_free (data->subject);
1511 g_free (data->plain_body);
1512 g_free (data->html_body);
1513 g_free (data->account_name);
1515 if (data->draft_msg != NULL) {
1516 g_object_unref (data->draft_msg);
1517 data->draft_msg = NULL;
1520 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1521 g_list_free (data->attachments);
1522 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1523 g_list_free (data->images);
1525 g_slice_free (MsgData, data);
1529 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1532 ModestMsgEditWindowPrivate *priv = NULL;
1533 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1535 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1537 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1539 return MODEST_MSG_EDIT_FORMAT_HTML;
1541 return MODEST_MSG_EDIT_FORMAT_TEXT;
1545 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1546 ModestMsgEditFormat format)
1548 ModestMsgEditWindowPrivate *priv;
1550 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1551 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1554 case MODEST_MSG_EDIT_FORMAT_HTML:
1555 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1557 case MODEST_MSG_EDIT_FORMAT_TEXT:
1558 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1561 g_return_if_reached ();
1565 ModestMsgEditFormatState *
1566 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1568 ModestMsgEditFormatState *format_state = NULL;
1569 ModestMsgEditWindowPrivate *priv;
1570 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1572 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1573 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1575 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1577 format_state = g_new0 (ModestMsgEditFormatState, 1);
1578 format_state->bold = buffer_format->bold&0x1;
1579 format_state->italics = buffer_format->italic&0x1;
1580 format_state->bullet = buffer_format->bullet&0x1;
1581 format_state->color = buffer_format->color;
1582 format_state->font_size = buffer_format->font_size;
1583 format_state->font_family = wp_get_font_name (buffer_format->font);
1584 format_state->justification = buffer_format->justification;
1585 g_free (buffer_format);
1587 return format_state;
1592 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1593 const ModestMsgEditFormatState *format_state)
1595 ModestMsgEditWindowPrivate *priv;
1596 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1597 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1598 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1599 g_return_if_fail (format_state != NULL);
1601 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1602 gtk_widget_grab_focus (priv->msg_body);
1603 buffer_format->bold = (format_state->bold != FALSE);
1604 buffer_format->italic = (format_state->italics != FALSE);
1605 buffer_format->color = format_state->color;
1606 buffer_format->font_size = format_state->font_size;
1607 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1608 buffer_format->justification = format_state->justification;
1609 buffer_format->bullet = format_state->bullet;
1611 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1613 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1614 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1615 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1616 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1617 buffer_format->cs.font = (buffer_format->font != current_format->font);
1618 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1619 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1621 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1622 if (buffer_format->cs.bold) {
1623 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1624 GINT_TO_POINTER (buffer_format->bold&0x1));
1626 if (buffer_format->cs.italic) {
1627 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1628 GINT_TO_POINTER (buffer_format->italic&0x1));
1630 if (buffer_format->cs.color) {
1631 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1632 GINT_TO_POINTER (&(buffer_format->color)));
1634 if (buffer_format->cs.font_size) {
1635 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1636 GINT_TO_POINTER (buffer_format->font_size));
1638 if (buffer_format->cs.justification) {
1639 switch (buffer_format->justification) {
1640 case GTK_JUSTIFY_LEFT:
1641 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1642 GINT_TO_POINTER(TRUE));
1644 case GTK_JUSTIFY_CENTER:
1645 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1646 GINT_TO_POINTER(TRUE));
1648 case GTK_JUSTIFY_RIGHT:
1649 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1650 GINT_TO_POINTER(TRUE));
1657 if (buffer_format->cs.font) {
1658 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1659 GINT_TO_POINTER (buffer_format->font));
1661 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1662 if (buffer_format->cs.bullet) {
1663 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1664 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1666 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1668 g_free (current_format);
1673 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1675 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1677 ModestWindowPrivate *parent_priv;
1678 ModestMsgEditWindowPrivate *priv;
1679 GtkWidget *new_size_menuitem;
1680 GtkWidget *new_font_menuitem;
1682 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1683 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1685 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1686 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1687 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1688 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1690 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1691 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1692 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1695 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1697 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1698 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1700 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1701 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1703 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1704 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1706 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1707 G_CALLBACK (modest_msg_edit_window_color_button_change),
1709 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1710 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1711 G_CALLBACK (modest_msg_edit_window_color_button_change),
1714 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1715 buffer_format->font_size))->data);
1716 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1720 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1721 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1722 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1724 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1725 G_CALLBACK (modest_msg_edit_window_size_change),
1727 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1728 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1729 G_CALLBACK (modest_msg_edit_window_size_change),
1733 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1734 buffer_format->font))->data);
1735 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1739 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1740 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1741 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1743 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1744 G_CALLBACK (modest_msg_edit_window_font_change),
1746 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1747 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1748 G_CALLBACK (modest_msg_edit_window_font_change),
1752 g_free (buffer_format);
1756 #ifdef MODEST_HILDON_VERSION_0
1758 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1761 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1762 ModestMsgEditWindowPrivate *priv;
1763 GtkWidget *dialog = NULL;
1765 GdkColor *new_color = NULL;
1767 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1768 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1770 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1771 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1772 g_free (buffer_format);
1774 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1775 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1776 if (new_color != NULL) {
1777 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1778 (gpointer) new_color);
1781 gtk_widget_destroy (dialog);
1786 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1789 ModestMsgEditWindowPrivate *priv;
1790 GtkWidget *dialog = NULL;
1792 GdkColor *old_color = NULL;
1793 const GdkColor *new_color = NULL;
1795 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1796 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1798 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1799 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1801 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1802 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1803 if (new_color != NULL)
1804 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1806 gtk_widget_destroy (dialog);
1812 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1815 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1816 ModestMsgEditWindowPrivate *priv;
1817 GtkWidget *dialog = NULL;
1819 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1820 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1822 dialog = hildon_color_chooser_new ();
1823 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1824 g_free (buffer_format);
1826 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1828 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1829 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1832 gtk_widget_destroy (dialog);
1837 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1840 ModestMsgEditWindowPrivate *priv;
1841 GtkWidget *dialog = NULL;
1842 GdkColor *old_color = NULL;
1844 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1845 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1847 dialog = hildon_color_chooser_new ();
1848 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1850 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1852 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1853 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1855 gtk_widget_destroy (dialog);
1858 #endif /*!MODEST_HILDON_VERSION_0*/
1862 static TnyStream* create_stream_for_uri (const gchar* uri)
1867 TnyStream *result = NULL;
1869 GnomeVFSHandle *handle = NULL;
1870 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1871 if (test == GNOME_VFS_OK) {
1872 /* Create the tinymail stream: */
1873 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1874 result = TNY_STREAM (tny_vfs_stream_new (handle));
1881 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1884 ModestMsgEditWindowPrivate *priv;
1885 GtkWidget *dialog = NULL;
1887 GSList *uris = NULL;
1888 GSList *uri_node = NULL;
1890 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1892 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1893 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1894 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1896 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1898 response = gtk_dialog_run (GTK_DIALOG (dialog));
1900 case GTK_RESPONSE_OK:
1901 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1906 gtk_widget_destroy (dialog);
1908 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1910 GnomeVFSHandle *handle = NULL;
1911 GnomeVFSResult result;
1912 GtkTextIter position;
1913 GtkTextMark *insert_mark;
1915 uri = (const gchar *) uri_node->data;
1916 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1917 if (result == GNOME_VFS_OK) {
1919 GnomeVFSFileInfo info;
1920 gchar *filename, *basename, *escaped_filename;
1921 TnyMimePart *mime_part;
1923 const gchar *mime_type = NULL;
1924 GnomeVFSURI *vfs_uri;
1926 vfs_uri = gnome_vfs_uri_new (uri);
1928 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1929 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1930 g_free (escaped_filename);
1931 gnome_vfs_uri_unref (vfs_uri);
1933 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1934 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1936 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1938 mime_part = tny_platform_factory_new_mime_part
1939 (modest_runtime_get_platform_factory ());
1941 TnyStream *stream = create_stream_for_uri (uri);
1942 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1944 content_id = g_strdup_printf ("%d", priv->last_cid);
1945 tny_mime_part_set_content_id (mime_part, content_id);
1946 g_free (content_id);
1949 basename = g_path_get_basename (filename);
1950 tny_mime_part_set_filename (mime_part, basename);
1953 pixbuf = pixbuf_from_stream (stream, mime_type);
1955 if (pixbuf != NULL) {
1956 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1957 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1958 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1961 priv->images = g_list_prepend (priv->images, mime_part);
1962 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1972 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1974 GtkWidget *dialog = NULL;
1976 GSList *uris = NULL;
1979 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1980 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1981 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1983 response = gtk_dialog_run (GTK_DIALOG (dialog));
1985 case GTK_RESPONSE_OK:
1986 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1991 gtk_widget_destroy (dialog);
1993 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1994 const gchar *uri = (const gchar *) uri_node->data;
1995 modest_msg_edit_window_attach_file_one (window, uri);
1997 g_slist_foreach (uris, (GFunc) g_free, NULL);
1998 g_slist_free (uris);
2002 modest_msg_edit_window_attach_file_one (
2003 ModestMsgEditWindow *window,
2006 g_return_if_fail (window);
2007 g_return_if_fail (uri);
2009 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2012 GnomeVFSHandle *handle = NULL;
2013 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2014 if (result == GNOME_VFS_OK) {
2015 TnyMimePart *mime_part;
2017 const gchar *mime_type = NULL;
2019 gchar *escaped_filename;
2022 GnomeVFSFileInfo info;
2023 GnomeVFSURI *vfs_uri;
2025 vfs_uri = gnome_vfs_uri_new (uri);
2028 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2029 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2030 g_free (escaped_filename);
2031 gnome_vfs_uri_unref (vfs_uri);
2033 if (gnome_vfs_get_file_info (uri,
2035 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2036 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2038 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2039 mime_part = tny_platform_factory_new_mime_part
2040 (modest_runtime_get_platform_factory ());
2041 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2043 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2045 content_id = g_strdup_printf ("%d", priv->last_cid);
2046 tny_mime_part_set_content_id (mime_part, content_id);
2047 g_free (content_id);
2050 basename = g_path_get_basename (filename);
2051 tny_mime_part_set_filename (mime_part, basename);
2054 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2055 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2057 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2058 gtk_widget_show_all (priv->attachments_caption);
2059 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2065 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2068 ModestMsgEditWindowPrivate *priv;
2069 gboolean clean_list = FALSE;
2071 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2072 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2074 if (att_list == NULL) {
2075 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2079 if (att_list == NULL) {
2080 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2082 GtkWidget *confirmation_dialog = NULL;
2083 gboolean dialog_response;
2085 gchar *message = NULL;
2086 gchar *filename = NULL;
2088 if (att_list->next == NULL) {
2089 if (TNY_IS_MSG (att_list->data)) {
2090 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2092 filename = g_strdup (tny_header_get_subject (header));
2093 g_object_unref (header);
2095 if (filename == NULL) {
2096 filename = g_strdup (_("mail_va_no_subject"));
2099 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2102 filename = g_strdup ("");
2104 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2105 att_list->next == NULL), filename);
2107 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2109 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2110 gtk_widget_destroy (confirmation_dialog);
2111 if (!dialog_response) {
2113 g_list_free (att_list);
2116 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2118 for (node = att_list; node != NULL; node = g_list_next (node)) {
2119 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2120 const gchar *att_id;
2121 priv->attachments = g_list_remove (priv->attachments, mime_part);
2123 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2125 if (priv->attachments == NULL)
2126 gtk_widget_hide (priv->attachments_caption);
2127 att_id = tny_mime_part_get_content_id (mime_part);
2129 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2131 g_object_unref (mime_part);
2132 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2137 g_list_free (att_list);
2141 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2144 ModestMsgEditWindowPrivate *priv;
2145 GdkColor *new_color;
2146 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2148 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2149 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2152 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2154 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2156 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2158 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2163 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2166 ModestMsgEditWindowPrivate *priv;
2167 gint new_size_index;
2168 ModestMsgEditWindow *window;
2171 window = MODEST_MSG_EDIT_WINDOW (userdata);
2172 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2173 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2175 if (gtk_check_menu_item_get_active (menu_item)) {
2177 WPTextBufferFormat format;
2179 memset (&format, 0, sizeof (format));
2180 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2182 label = gtk_bin_get_child (GTK_BIN (menu_item));
2184 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2185 format.cs.font_size = TRUE;
2186 format.cs.text_position = TRUE;
2187 format.cs.font = TRUE;
2188 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2189 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2191 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2192 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2193 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2195 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2196 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2197 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2203 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2206 ModestMsgEditWindowPrivate *priv;
2207 gint new_font_index;
2208 ModestMsgEditWindow *window;
2211 window = MODEST_MSG_EDIT_WINDOW (userdata);
2212 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2213 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2215 if (gtk_check_menu_item_get_active (menu_item)) {
2218 label = gtk_bin_get_child (GTK_BIN (menu_item));
2220 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2222 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2223 GINT_TO_POINTER(new_font_index)))
2224 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2226 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2227 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2228 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2234 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2236 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2237 ModestWindowPrivate *parent_priv;
2238 ModestWindowMgr *mgr;
2239 gboolean is_fullscreen;
2240 GtkAction *fs_toggle_action;
2243 mgr = modest_runtime_get_window_mgr ();
2244 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2246 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2248 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2249 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2250 if (is_fullscreen != active)
2251 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2259 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2262 ModestMsgEditWindowPrivate *priv = NULL;
2263 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2265 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2266 if (!priv->update_caption_visibility)
2269 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2271 gtk_widget_show (priv->cc_caption);
2273 gtk_widget_hide (priv->cc_caption);
2275 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2279 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2282 ModestMsgEditWindowPrivate *priv = NULL;
2283 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2285 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2286 if (!priv->update_caption_visibility)
2289 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2291 gtk_widget_show (priv->bcc_caption);
2293 gtk_widget_hide (priv->bcc_caption);
2295 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2299 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2300 ModestRecptEditor *editor)
2302 ModestMsgEditWindowPrivate *priv;
2304 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2305 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2306 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2308 if (editor == NULL) {
2309 GtkWidget *view_focus;
2310 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2312 /* This code should be kept in sync with ModestRecptEditor. The
2313 textview inside the recpt editor is the one that really gets the
2314 focus. As it's inside a scrolled window, and this one inside the
2315 hbox recpt editor inherits from, we'll need to go up in the
2316 hierarchy to know if the text view is part of the recpt editor
2317 or if it's a different text entry */
2319 if (gtk_widget_get_parent (view_focus)) {
2320 GtkWidget *first_parent;
2322 first_parent = gtk_widget_get_parent (view_focus);
2323 if (gtk_widget_get_parent (first_parent) &&
2324 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2325 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2330 editor = MODEST_RECPT_EDITOR (priv->to_field);
2334 modest_address_book_select_addresses (editor);
2339 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2341 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2343 modest_msg_edit_window_open_addressbook (window, NULL);
2347 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2348 gboolean show_toolbar)
2350 ModestWindowPrivate *parent_priv;
2351 const gchar *action_name;
2354 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2355 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2357 /* We can not just use the code of
2358 modest_msg_edit_window_setup_toolbar because it has a
2359 mixture of both initialization and creation code. */
2361 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2363 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2365 /* Update also the actions (to update the toggles in the
2366 menus), we have to do it manually because some other window
2367 of the same time could have changed it (remember that the
2368 toolbar fullscreen mode is shared by all the windows of the
2370 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2371 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2373 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2375 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2376 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2382 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2383 TnyHeaderFlags priority_flags)
2385 ModestMsgEditWindowPrivate *priv;
2386 ModestWindowPrivate *parent_priv;
2388 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2390 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2391 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2393 if (priv->priority_flags != priority_flags) {
2394 GtkAction *priority_action = NULL;
2396 priv->priority_flags = priority_flags;
2398 switch (priority_flags) {
2399 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2400 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2401 gtk_widget_show (priv->priority_icon);
2402 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2403 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2405 case TNY_HEADER_FLAG_LOW_PRIORITY:
2406 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2407 gtk_widget_show (priv->priority_icon);
2408 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2409 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2412 gtk_widget_hide (priv->priority_icon);
2413 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2414 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2417 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2418 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2423 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2426 ModestMsgEditWindowPrivate *priv;
2427 ModestWindowPrivate *parent_priv;
2428 gint current_format;
2430 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2432 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2433 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2435 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2436 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2438 if (current_format != file_format) {
2439 switch (file_format) {
2440 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2441 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2442 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2444 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2448 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2449 response = gtk_dialog_run (GTK_DIALOG (dialog));
2450 gtk_widget_destroy (dialog);
2451 if (response == GTK_RESPONSE_OK) {
2452 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2454 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2455 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2460 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2465 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2468 ModestMsgEditWindowPrivate *priv;
2469 WPTextBufferFormat oldfmt, fmt;
2470 gint old_position = 0;
2474 GdkColor *color = NULL;
2475 gboolean bold, bold_set, italic, italic_set;
2476 gboolean underline, underline_set;
2477 gboolean strikethrough, strikethrough_set;
2478 gboolean position_set;
2479 gboolean font_size_set, font_set, color_set;
2482 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2483 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2485 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2487 /* First we get the currently selected font information */
2488 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2490 switch (oldfmt.text_position) {
2491 case TEXT_POSITION_NORMAL:
2494 case TEXT_POSITION_SUPERSCRIPT:
2502 g_object_set (G_OBJECT (dialog),
2503 "bold", oldfmt.bold != FALSE,
2504 "bold-set", !oldfmt.cs.bold,
2505 "underline", oldfmt.underline != FALSE,
2506 "underline-set", !oldfmt.cs.underline,
2507 "italic", oldfmt.italic != FALSE,
2508 "italic-set", !oldfmt.cs.italic,
2509 "strikethrough", oldfmt.strikethrough != FALSE,
2510 "strikethrough-set", !oldfmt.cs.strikethrough,
2511 "color", &oldfmt.color,
2512 "color-set", !oldfmt.cs.color,
2513 "size", wp_font_size[oldfmt.font_size],
2514 "size-set", !oldfmt.cs.font_size,
2515 "position", old_position,
2516 "position-set", !oldfmt.cs.text_position,
2517 "family", wp_get_font_name (oldfmt.font),
2518 "family-set", !oldfmt.cs.font,
2521 gtk_widget_show_all (dialog);
2522 response = gtk_dialog_run (GTK_DIALOG (dialog));
2523 if (response == GTK_RESPONSE_OK) {
2525 g_object_get( dialog,
2527 "bold-set", &bold_set,
2528 "underline", &underline,
2529 "underline-set", &underline_set,
2531 "italic-set", &italic_set,
2532 "strikethrough", &strikethrough,
2533 "strikethrough-set", &strikethrough_set,
2535 "color-set", &color_set,
2537 "size-set", &font_size_set,
2538 "family", &font_name,
2539 "family-set", &font_set,
2540 "position", &position,
2541 "position-set", &position_set,
2546 if (response == GTK_RESPONSE_OK) {
2547 memset(&fmt, 0, sizeof(fmt));
2553 fmt.italic = italic;
2554 fmt.cs.italic = TRUE;
2556 if (underline_set) {
2557 fmt.underline = underline;
2558 fmt.cs.underline = TRUE;
2560 if (strikethrough_set) {
2561 fmt.strikethrough = strikethrough;
2562 fmt.cs.strikethrough = TRUE;
2567 ? TEXT_POSITION_NORMAL
2568 : ( ( position == 1 )
2569 ? TEXT_POSITION_SUPERSCRIPT
2570 : TEXT_POSITION_SUBSCRIPT );
2571 fmt.cs.text_position = TRUE;
2575 fmt.cs.color = TRUE;
2578 fmt.font = wp_get_font_index(font_name,
2583 if (font_size_set) {
2584 fmt.font_size = wp_get_font_size_index(
2585 font_size, DEFAULT_FONT_SIZE);
2586 fmt.cs.font_size = TRUE;
2588 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2589 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2591 gtk_widget_destroy (dialog);
2593 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2597 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2599 ModestMsgEditWindowPrivate *priv;
2601 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2602 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2604 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2606 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2611 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2613 ModestMsgEditWindowPrivate *priv;
2615 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2616 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2618 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2620 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2625 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2627 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2629 priv->can_undo = can_undo;
2633 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2635 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2637 priv->can_redo = can_redo;
2641 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2643 ModestMsgEditWindowPrivate *priv;
2644 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2645 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2647 return priv->can_undo;
2651 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2653 ModestMsgEditWindowPrivate *priv;
2654 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2655 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2657 return priv->can_redo;
2662 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2665 GtkTextIter match_start, match_end;
2667 if (image_id == NULL)
2670 gtk_text_buffer_get_start_iter (buffer, &iter);
2672 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2673 GSList *tags = gtk_text_iter_get_tags (&match_start);
2675 for (node = tags; node != NULL; node = g_slist_next (node)) {
2676 GtkTextTag *tag = (GtkTextTag *) node->data;
2677 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2678 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2679 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2681 offset = gtk_text_iter_get_offset (&match_start);
2682 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2683 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2687 gtk_text_iter_forward_char (&iter);
2692 message_is_empty (ModestMsgEditWindow *window)
2694 ModestMsgEditWindowPrivate *priv = NULL;
2696 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2697 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2699 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2700 * so we can ignore markup.
2702 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2705 count = gtk_text_buffer_get_char_count (buf);
2711 msg_body_focus (GtkWidget *focus,
2712 GdkEventFocus *event,
2716 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2721 recpt_field_changed (GtkTextBuffer *buffer,
2722 ModestMsgEditWindow *editor)
2724 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2728 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2730 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2734 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2736 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2737 GtkTextBuffer *buffer;
2739 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2740 gtk_text_buffer_set_modified (buffer, FALSE);
2741 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2742 gtk_text_buffer_set_modified (buffer, FALSE);
2743 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2744 gtk_text_buffer_set_modified (buffer, FALSE);
2745 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2749 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2751 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2752 GtkTextBuffer *buffer;
2754 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2755 if (gtk_text_buffer_get_modified (buffer))
2757 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2758 if (gtk_text_buffer_get_modified (buffer))
2760 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2761 if (gtk_text_buffer_get_modified (buffer))
2763 if (gtk_text_buffer_get_modified (priv->text_buffer))
2773 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2775 ModestMsgEditWindowPrivate *priv = NULL;
2777 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2778 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2780 /* check if there's no recipient added */
2781 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2782 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2783 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2784 /* no recipient contents, then select contacts */
2785 modest_msg_edit_window_open_addressbook (window, NULL);
2789 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2790 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2793 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2794 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2797 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2798 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2802 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2803 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2804 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2811 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2812 ModestMsgEditWindow *window)
2814 modest_msg_edit_window_offer_attach_file (window);
2818 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2820 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2822 return priv->clipboard_text;
2826 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2828 ModestMsgEditWindow *window)
2830 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2831 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2833 if (!GTK_WIDGET_VISIBLE (window))
2836 text = gtk_clipboard_wait_for_text (selection_clipboard);
2838 if (priv->clipboard_text != NULL) {
2839 g_free (priv->clipboard_text);
2841 priv->clipboard_text = text;
2843 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2846 subject_field_move_cursor (GtkEntry *entry,
2847 GtkMovementStep step,
2852 if (!GTK_WIDGET_VISIBLE (window))
2855 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2859 update_window_title (ModestMsgEditWindow *window)
2861 ModestMsgEditWindowPrivate *priv = NULL;
2862 const gchar *subject;
2864 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2865 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2866 if (subject == NULL || subject[0] == '\0')
2867 subject = _("mail_va_new_email");
2869 gtk_window_set_title (GTK_WINDOW (window), subject);
2874 subject_field_changed (GtkEditable *editable,
2875 ModestMsgEditWindow *window)
2877 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2878 update_window_title (window);
2879 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2880 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2884 subject_field_insert_text (GtkEditable *editable,
2886 gint new_text_length,
2888 ModestMsgEditWindow *window)
2890 GString *result = g_string_new ("");
2892 gint result_len = 0;
2893 const gchar *entry_text = NULL;
2896 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2897 old_length = g_utf8_strlen (entry_text, -1);
2899 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2900 gunichar c = g_utf8_get_char_validated (current, 8);
2901 /* Invalid unichar, stop */
2907 result = g_string_append_unichar (result, c);
2911 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2912 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2915 /* Prevent endless recursion */
2916 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2917 g_signal_emit_by_name (editable, "insert-text",
2918 (gpointer) result->str, (gpointer) result->len,
2919 (gpointer) position, (gpointer) window);
2920 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2924 if (result_len + old_length > 1000) {
2925 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2926 dgettext("hildon-common-strings",
2927 "ckdg_ib_maximum_characters_reached"));
2930 g_string_free (result, TRUE);
2934 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2937 ModestMsgEditWindowPrivate *priv = NULL;
2939 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2940 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2942 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2945 gtk_widget_show_all (priv->find_toolbar);
2946 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2948 gtk_widget_hide_all (priv->find_toolbar);
2949 gtk_widget_grab_focus (priv->msg_body);
2955 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2957 GtkTextIter *match_start,
2958 GtkTextIter *match_end)
2960 GtkTextIter end_iter;
2961 gchar *str_casefold;
2964 gchar *range_casefold;
2967 gboolean result = FALSE;
2974 gtk_text_iter_forward_to_end (&end_iter);
2976 str_casefold = g_utf8_casefold (str, -1);
2977 str_chars_n = strlen (str);
2979 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2980 range_casefold = g_utf8_casefold (range_text, -1);
2981 range_chars_n = strlen (range_casefold);
2983 if (range_chars_n < str_chars_n) {
2984 g_free (str_casefold);
2985 g_free (range_text);
2986 g_free (range_casefold);
2990 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2991 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2992 if (!g_utf8_collate (range_subtext, str_casefold)) {
2993 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2995 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2996 match_start, match_end, NULL);
2997 g_free (found_text);
2999 g_free (range_subtext);
3003 g_free (str_casefold);
3004 g_free (range_text);
3005 g_free (range_casefold);
3012 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3013 ModestMsgEditWindow *window)
3015 gchar *current_search = NULL;
3016 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3018 GtkTextIter selection_start, selection_end;
3019 GtkTextIter match_start, match_end;
3020 gboolean continue_search = FALSE;
3022 if (message_is_empty (window)) {
3023 g_free (priv->last_search);
3024 priv->last_search = NULL;
3025 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3029 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3030 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3031 g_free (current_search);
3032 g_free (priv->last_search);
3033 priv->last_search = NULL;
3034 /* Information banner about empty search */
3035 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3039 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3040 continue_search = TRUE;
3042 g_free (priv->last_search);
3043 priv->last_search = g_strdup (current_search);
3046 if (continue_search) {
3047 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3048 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3049 &match_start, &match_end);
3051 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3053 GtkTextIter buffer_start;
3054 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3055 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3056 &match_start, &match_end);
3058 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3061 /* Mark as selected the string found in search */
3063 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3064 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3066 g_free (priv->last_search);
3067 priv->last_search = NULL;
3069 g_free (current_search);
3073 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3074 ModestMsgEditWindow *window)
3076 GtkToggleAction *toggle;
3077 ModestWindowPrivate *parent_priv;
3078 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3080 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3081 gtk_toggle_action_set_active (toggle, FALSE);
3085 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3087 ModestMsgEditWindowPrivate *priv;
3089 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3094 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3097 ModestMsgEditWindowPrivate *priv;
3099 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3105 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3108 ModestMsgEditWindowPrivate *priv;
3109 TnyHeader *header = NULL;
3111 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3112 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3114 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3115 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3117 if (priv->draft_msg != NULL) {
3118 g_object_unref (priv->draft_msg);
3121 if (draft != NULL) {
3122 g_object_ref (draft);
3123 header = tny_msg_get_header (draft);
3124 if (priv->msg_uid) {
3125 g_free (priv->msg_uid);
3126 priv->msg_uid = NULL;
3128 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3129 if (GTK_WIDGET_REALIZED (window))
3130 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3133 priv->draft_msg = draft;
3137 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3138 GtkTextIter *start, GtkTextIter *end,
3141 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3142 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3145 if (tag == NULL+13) return;
3146 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3147 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3148 replace_with_images (window, priv->images);
3153 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3156 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3158 g_return_if_fail (TNY_IS_MIME_PART (part));
3159 priv->attachments = g_list_prepend (priv->attachments, part);
3160 g_object_ref (part);
3161 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3162 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3163 gtk_widget_show_all (priv->attachments_caption);
3164 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3168 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3170 ModestMsgEditWindowPrivate *priv;
3172 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3173 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3175 return priv->msg_uid;
3179 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3180 ModestMsgEditWindowWidgetType widget_type)
3182 ModestMsgEditWindowPrivate *priv;
3184 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3185 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3187 switch (widget_type) {
3188 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3189 return priv->msg_body;
3191 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3192 return priv->to_field;
3194 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3195 return priv->cc_field;
3197 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3198 return priv->bcc_field;
3200 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3201 return priv->subject_field;
3203 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3204 return priv->attachments_view;
3212 remove_tags (WPTextBuffer *buffer)
3214 GtkTextIter start, end;
3216 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3217 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3219 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3223 on_account_removed (TnyAccountStore *account_store,
3224 TnyAccount *account,
3227 /* Do nothing if it's a store account, because we use the
3228 transport to send the messages */
3229 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3230 const gchar *parent_acc = NULL;
3231 const gchar *our_acc = NULL;
3233 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3234 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3235 /* Close this window if I'm showing a message of the removed account */
3236 if (strcmp (parent_acc, our_acc) == 0)
3237 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3242 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3244 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3246 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));