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, (gpointer) (buffer_format->bold&0x1));
1625 if (buffer_format->cs.italic) {
1626 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1628 if (buffer_format->cs.color) {
1629 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1631 if (buffer_format->cs.font_size) {
1632 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1634 if (buffer_format->cs.justification) {
1635 switch (buffer_format->justification) {
1636 case GTK_JUSTIFY_LEFT:
1637 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1639 case GTK_JUSTIFY_CENTER:
1640 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1642 case GTK_JUSTIFY_RIGHT:
1643 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1650 if (buffer_format->cs.font) {
1651 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1653 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1654 if (buffer_format->cs.bullet) {
1655 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1657 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1659 g_free (current_format);
1664 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1666 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1668 ModestWindowPrivate *parent_priv;
1669 ModestMsgEditWindowPrivate *priv;
1670 GtkWidget *new_size_menuitem;
1671 GtkWidget *new_font_menuitem;
1673 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1674 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1676 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1677 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1678 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1679 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1681 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1682 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1683 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1686 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1688 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1689 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1691 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1692 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1694 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1695 /* modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1697 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1698 G_CALLBACK (modest_msg_edit_window_color_button_change),
1700 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1701 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1702 G_CALLBACK (modest_msg_edit_window_color_button_change),
1705 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1706 buffer_format->font_size))->data);
1707 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1711 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1712 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1713 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1715 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1716 G_CALLBACK (modest_msg_edit_window_size_change),
1718 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1719 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1720 G_CALLBACK (modest_msg_edit_window_size_change),
1724 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1725 buffer_format->font))->data);
1726 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1730 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1731 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1732 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1734 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1735 G_CALLBACK (modest_msg_edit_window_font_change),
1737 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1738 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1739 G_CALLBACK (modest_msg_edit_window_font_change),
1743 g_free (buffer_format);
1747 #ifdef MODEST_HILDON_VERSION_0
1749 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1752 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1753 ModestMsgEditWindowPrivate *priv;
1754 GtkWidget *dialog = NULL;
1756 GdkColor *new_color = NULL;
1758 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1759 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1761 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1762 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1763 g_free (buffer_format);
1765 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1766 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1767 if (new_color != NULL) {
1768 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1769 (gpointer) new_color);
1772 gtk_widget_destroy (dialog);
1777 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1780 ModestMsgEditWindowPrivate *priv;
1781 GtkWidget *dialog = NULL;
1783 GdkColor *old_color = NULL;
1784 const GdkColor *new_color = NULL;
1786 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1787 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1789 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1790 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1792 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1793 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1794 if (new_color != NULL)
1795 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1797 gtk_widget_destroy (dialog);
1803 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1806 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1807 ModestMsgEditWindowPrivate *priv;
1808 GtkWidget *dialog = NULL;
1810 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1811 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1813 dialog = hildon_color_chooser_new ();
1814 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1815 g_free (buffer_format);
1817 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1819 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1820 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1823 gtk_widget_destroy (dialog);
1828 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1831 ModestMsgEditWindowPrivate *priv;
1832 GtkWidget *dialog = NULL;
1833 GdkColor *old_color = NULL;
1835 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1836 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1838 dialog = hildon_color_chooser_new ();
1839 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1841 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1843 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1844 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1846 gtk_widget_destroy (dialog);
1849 #endif /*!MODEST_HILDON_VERSION_0*/
1853 static TnyStream* create_stream_for_uri (const gchar* uri)
1858 TnyStream *result = NULL;
1860 GnomeVFSHandle *handle = NULL;
1861 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1862 if (test == GNOME_VFS_OK) {
1863 /* Create the tinymail stream: */
1864 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1865 result = TNY_STREAM (tny_vfs_stream_new (handle));
1872 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1875 ModestMsgEditWindowPrivate *priv;
1876 GtkWidget *dialog = NULL;
1878 GSList *uris = NULL;
1879 GSList *uri_node = NULL;
1881 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1883 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1884 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1885 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1887 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1889 response = gtk_dialog_run (GTK_DIALOG (dialog));
1891 case GTK_RESPONSE_OK:
1892 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1897 gtk_widget_destroy (dialog);
1899 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1901 GnomeVFSHandle *handle = NULL;
1902 GnomeVFSResult result;
1903 GtkTextIter position;
1904 GtkTextMark *insert_mark;
1906 uri = (const gchar *) uri_node->data;
1907 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1908 if (result == GNOME_VFS_OK) {
1910 GnomeVFSFileInfo info;
1911 gchar *filename, *basename, *escaped_filename;
1912 TnyMimePart *mime_part;
1914 const gchar *mime_type = NULL;
1915 GnomeVFSURI *vfs_uri;
1917 vfs_uri = gnome_vfs_uri_new (uri);
1919 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1920 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1921 g_free (escaped_filename);
1922 gnome_vfs_uri_unref (vfs_uri);
1924 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1925 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1927 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1929 mime_part = tny_platform_factory_new_mime_part
1930 (modest_runtime_get_platform_factory ());
1932 TnyStream *stream = create_stream_for_uri (uri);
1933 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1935 content_id = g_strdup_printf ("%d", priv->last_cid);
1936 tny_mime_part_set_content_id (mime_part, content_id);
1937 g_free (content_id);
1940 basename = g_path_get_basename (filename);
1941 tny_mime_part_set_filename (mime_part, basename);
1944 pixbuf = pixbuf_from_stream (stream, mime_type);
1946 if (pixbuf != NULL) {
1947 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1948 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1949 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1952 priv->images = g_list_prepend (priv->images, mime_part);
1953 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1963 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1965 GtkWidget *dialog = NULL;
1967 GSList *uris = NULL;
1970 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1971 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1972 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1974 response = gtk_dialog_run (GTK_DIALOG (dialog));
1976 case GTK_RESPONSE_OK:
1977 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1982 gtk_widget_destroy (dialog);
1984 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1985 const gchar *uri = (const gchar *) uri_node->data;
1986 modest_msg_edit_window_attach_file_one (window, uri);
1988 g_slist_foreach (uris, (GFunc) g_free, NULL);
1989 g_slist_free (uris);
1993 modest_msg_edit_window_attach_file_one (
1994 ModestMsgEditWindow *window,
1997 g_return_if_fail (window);
1998 g_return_if_fail (uri);
2000 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2003 GnomeVFSHandle *handle = NULL;
2004 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2005 if (result == GNOME_VFS_OK) {
2006 TnyMimePart *mime_part;
2008 const gchar *mime_type = NULL;
2010 gchar *escaped_filename;
2013 GnomeVFSFileInfo info;
2014 GnomeVFSURI *vfs_uri;
2016 vfs_uri = gnome_vfs_uri_new (uri);
2019 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2020 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2021 g_free (escaped_filename);
2022 gnome_vfs_uri_unref (vfs_uri);
2024 if (gnome_vfs_get_file_info (uri,
2026 GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2027 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2029 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2030 mime_part = tny_platform_factory_new_mime_part
2031 (modest_runtime_get_platform_factory ());
2032 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2034 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2036 content_id = g_strdup_printf ("%d", priv->last_cid);
2037 tny_mime_part_set_content_id (mime_part, content_id);
2038 g_free (content_id);
2041 basename = g_path_get_basename (filename);
2042 tny_mime_part_set_filename (mime_part, basename);
2045 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2046 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2048 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2049 gtk_widget_show_all (priv->attachments_caption);
2050 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2056 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2059 ModestMsgEditWindowPrivate *priv;
2060 gboolean clean_list = FALSE;
2062 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2063 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2065 if (att_list == NULL) {
2066 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2070 if (att_list == NULL) {
2071 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2073 GtkWidget *confirmation_dialog = NULL;
2074 gboolean dialog_response;
2076 gchar *message = NULL;
2077 gchar *filename = NULL;
2079 if (att_list->next == NULL) {
2080 if (TNY_IS_MSG (att_list->data)) {
2081 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2083 filename = g_strdup (tny_header_get_subject (header));
2084 g_object_unref (header);
2086 if (filename == NULL) {
2087 filename = g_strdup (_("mail_va_no_subject"));
2090 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2093 filename = g_strdup ("");
2095 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2096 att_list->next == NULL), filename);
2098 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2100 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2101 gtk_widget_destroy (confirmation_dialog);
2102 if (!dialog_response) {
2104 g_list_free (att_list);
2107 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2109 for (node = att_list; node != NULL; node = g_list_next (node)) {
2110 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2111 const gchar *att_id;
2112 priv->attachments = g_list_remove (priv->attachments, mime_part);
2114 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2116 if (priv->attachments == NULL)
2117 gtk_widget_hide (priv->attachments_caption);
2118 att_id = tny_mime_part_get_content_id (mime_part);
2120 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2122 g_object_unref (mime_part);
2123 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2128 g_list_free (att_list);
2132 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2135 ModestMsgEditWindowPrivate *priv;
2136 GdkColor *new_color;
2137 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2139 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2140 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2143 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2145 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2147 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2149 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2154 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2157 ModestMsgEditWindowPrivate *priv;
2158 gint new_size_index;
2159 ModestMsgEditWindow *window;
2162 window = MODEST_MSG_EDIT_WINDOW (userdata);
2163 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2164 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2166 if (gtk_check_menu_item_get_active (menu_item)) {
2168 WPTextBufferFormat format;
2170 memset (&format, 0, sizeof (format));
2171 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2173 label = gtk_bin_get_child (GTK_BIN (menu_item));
2175 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2176 format.cs.font_size = TRUE;
2177 format.cs.text_position = TRUE;
2178 format.cs.font = TRUE;
2179 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2180 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2182 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2183 (gpointer) wp_get_font_size_index (new_size_index, 12)))
2184 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2186 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2187 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2188 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2194 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2197 ModestMsgEditWindowPrivate *priv;
2198 gint new_font_index;
2199 ModestMsgEditWindow *window;
2202 window = MODEST_MSG_EDIT_WINDOW (userdata);
2203 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2204 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2206 if (gtk_check_menu_item_get_active (menu_item)) {
2209 label = gtk_bin_get_child (GTK_BIN (menu_item));
2211 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2213 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2214 (gpointer) new_font_index))
2215 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2217 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2218 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2219 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2225 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2227 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2228 ModestWindowPrivate *parent_priv;
2229 ModestWindowMgr *mgr;
2230 gboolean is_fullscreen;
2231 GtkAction *fs_toggle_action;
2234 mgr = modest_runtime_get_window_mgr ();
2235 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2237 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2239 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2240 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2241 if (is_fullscreen != active)
2242 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2250 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2253 ModestMsgEditWindowPrivate *priv = NULL;
2254 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2256 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2257 if (!priv->update_caption_visibility)
2260 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2262 gtk_widget_show (priv->cc_caption);
2264 gtk_widget_hide (priv->cc_caption);
2266 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2270 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2273 ModestMsgEditWindowPrivate *priv = NULL;
2274 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2276 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2277 if (!priv->update_caption_visibility)
2280 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2282 gtk_widget_show (priv->bcc_caption);
2284 gtk_widget_hide (priv->bcc_caption);
2286 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2290 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2291 ModestRecptEditor *editor)
2293 ModestMsgEditWindowPrivate *priv;
2295 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2296 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2297 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2299 if (editor == NULL) {
2300 GtkWidget *view_focus;
2301 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2303 /* This code should be kept in sync with ModestRecptEditor. The
2304 textview inside the recpt editor is the one that really gets the
2305 focus. As it's inside a scrolled window, and this one inside the
2306 hbox recpt editor inherits from, we'll need to go up in the
2307 hierarchy to know if the text view is part of the recpt editor
2308 or if it's a different text entry */
2310 if (gtk_widget_get_parent (view_focus)) {
2311 GtkWidget *first_parent;
2313 first_parent = gtk_widget_get_parent (view_focus);
2314 if (gtk_widget_get_parent (first_parent) &&
2315 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2316 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2321 editor = MODEST_RECPT_EDITOR (priv->to_field);
2325 modest_address_book_select_addresses (editor);
2330 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2332 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2334 modest_msg_edit_window_open_addressbook (window, NULL);
2338 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2339 gboolean show_toolbar)
2341 ModestWindowPrivate *parent_priv;
2342 const gchar *action_name;
2345 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2346 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2348 /* We can not just use the code of
2349 modest_msg_edit_window_setup_toolbar because it has a
2350 mixture of both initialization and creation code. */
2352 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2354 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2356 /* Update also the actions (to update the toggles in the
2357 menus), we have to do it manually because some other window
2358 of the same time could have changed it (remember that the
2359 toolbar fullscreen mode is shared by all the windows of the
2361 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2362 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2364 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2366 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2367 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2373 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2374 TnyHeaderFlags priority_flags)
2376 ModestMsgEditWindowPrivate *priv;
2377 ModestWindowPrivate *parent_priv;
2379 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2381 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2382 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2384 if (priv->priority_flags != priority_flags) {
2385 GtkAction *priority_action = NULL;
2387 priv->priority_flags = priority_flags;
2389 switch (priority_flags) {
2390 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2391 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2392 gtk_widget_show (priv->priority_icon);
2393 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2394 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2396 case TNY_HEADER_FLAG_LOW_PRIORITY:
2397 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2398 gtk_widget_show (priv->priority_icon);
2399 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2400 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2403 gtk_widget_hide (priv->priority_icon);
2404 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2405 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2408 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2409 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2414 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2417 ModestMsgEditWindowPrivate *priv;
2418 ModestWindowPrivate *parent_priv;
2419 gint current_format;
2421 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2423 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2424 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2426 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2427 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2429 if (current_format != file_format) {
2430 switch (file_format) {
2431 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2432 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2433 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2435 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2439 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2440 response = gtk_dialog_run (GTK_DIALOG (dialog));
2441 gtk_widget_destroy (dialog);
2442 if (response == GTK_RESPONSE_OK) {
2443 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2445 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2446 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2451 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2456 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2459 ModestMsgEditWindowPrivate *priv;
2460 WPTextBufferFormat oldfmt, fmt;
2461 gint old_position = 0;
2465 GdkColor *color = NULL;
2466 gboolean bold, bold_set, italic, italic_set;
2467 gboolean underline, underline_set;
2468 gboolean strikethrough, strikethrough_set;
2469 gboolean position_set;
2470 gboolean font_size_set, font_set, color_set;
2473 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2474 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2476 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2478 /* First we get the currently selected font information */
2479 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2481 switch (oldfmt.text_position) {
2482 case TEXT_POSITION_NORMAL:
2485 case TEXT_POSITION_SUPERSCRIPT:
2493 g_object_set (G_OBJECT (dialog),
2494 "bold", oldfmt.bold != FALSE,
2495 "bold-set", !oldfmt.cs.bold,
2496 "underline", oldfmt.underline != FALSE,
2497 "underline-set", !oldfmt.cs.underline,
2498 "italic", oldfmt.italic != FALSE,
2499 "italic-set", !oldfmt.cs.italic,
2500 "strikethrough", oldfmt.strikethrough != FALSE,
2501 "strikethrough-set", !oldfmt.cs.strikethrough,
2502 "color", &oldfmt.color,
2503 "color-set", !oldfmt.cs.color,
2504 "size", wp_font_size[oldfmt.font_size],
2505 "size-set", !oldfmt.cs.font_size,
2506 "position", old_position,
2507 "position-set", !oldfmt.cs.text_position,
2508 "family", wp_get_font_name (oldfmt.font),
2509 "family-set", !oldfmt.cs.font,
2512 gtk_widget_show_all (dialog);
2513 response = gtk_dialog_run (GTK_DIALOG (dialog));
2514 if (response == GTK_RESPONSE_OK) {
2516 g_object_get( dialog,
2518 "bold-set", &bold_set,
2519 "underline", &underline,
2520 "underline-set", &underline_set,
2522 "italic-set", &italic_set,
2523 "strikethrough", &strikethrough,
2524 "strikethrough-set", &strikethrough_set,
2526 "color-set", &color_set,
2528 "size-set", &font_size_set,
2529 "family", &font_name,
2530 "family-set", &font_set,
2531 "position", &position,
2532 "position-set", &position_set,
2537 if (response == GTK_RESPONSE_OK) {
2538 memset(&fmt, 0, sizeof(fmt));
2544 fmt.italic = italic;
2545 fmt.cs.italic = TRUE;
2547 if (underline_set) {
2548 fmt.underline = underline;
2549 fmt.cs.underline = TRUE;
2551 if (strikethrough_set) {
2552 fmt.strikethrough = strikethrough;
2553 fmt.cs.strikethrough = TRUE;
2558 ? TEXT_POSITION_NORMAL
2559 : ( ( position == 1 )
2560 ? TEXT_POSITION_SUPERSCRIPT
2561 : TEXT_POSITION_SUBSCRIPT );
2562 fmt.cs.text_position = TRUE;
2566 fmt.cs.color = TRUE;
2569 fmt.font = wp_get_font_index(font_name,
2574 if (font_size_set) {
2575 fmt.font_size = wp_get_font_size_index(
2576 font_size, DEFAULT_FONT_SIZE);
2577 fmt.cs.font_size = TRUE;
2579 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2580 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2582 gtk_widget_destroy (dialog);
2584 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2588 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2590 ModestMsgEditWindowPrivate *priv;
2592 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2593 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2595 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2597 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2602 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2604 ModestMsgEditWindowPrivate *priv;
2606 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2607 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2609 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2611 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2616 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2618 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2620 priv->can_undo = can_undo;
2624 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2626 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2628 priv->can_redo = can_redo;
2632 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2634 ModestMsgEditWindowPrivate *priv;
2635 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2636 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2638 return priv->can_undo;
2642 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2644 ModestMsgEditWindowPrivate *priv;
2645 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2646 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2648 return priv->can_redo;
2653 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2656 GtkTextIter match_start, match_end;
2658 if (image_id == NULL)
2661 gtk_text_buffer_get_start_iter (buffer, &iter);
2663 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2664 GSList *tags = gtk_text_iter_get_tags (&match_start);
2666 for (node = tags; node != NULL; node = g_slist_next (node)) {
2667 GtkTextTag *tag = (GtkTextTag *) node->data;
2668 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2669 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2670 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2672 offset = gtk_text_iter_get_offset (&match_start);
2673 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2674 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2678 gtk_text_iter_forward_char (&iter);
2683 message_is_empty (ModestMsgEditWindow *window)
2685 ModestMsgEditWindowPrivate *priv = NULL;
2687 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2688 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2690 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2691 * so we can ignore markup.
2693 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2696 count = gtk_text_buffer_get_char_count (buf);
2702 msg_body_focus (GtkWidget *focus,
2703 GdkEventFocus *event,
2707 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2712 recpt_field_changed (GtkTextBuffer *buffer,
2713 ModestMsgEditWindow *editor)
2715 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2719 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2721 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2725 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2727 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2728 GtkTextBuffer *buffer;
2730 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2731 gtk_text_buffer_set_modified (buffer, FALSE);
2732 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2733 gtk_text_buffer_set_modified (buffer, FALSE);
2734 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2735 gtk_text_buffer_set_modified (buffer, FALSE);
2736 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2740 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2742 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2743 GtkTextBuffer *buffer;
2745 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2746 if (gtk_text_buffer_get_modified (buffer))
2748 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2749 if (gtk_text_buffer_get_modified (buffer))
2751 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2752 if (gtk_text_buffer_get_modified (buffer))
2754 if (gtk_text_buffer_get_modified (priv->text_buffer))
2764 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2766 ModestMsgEditWindowPrivate *priv = NULL;
2768 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2769 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2771 /* check if there's no recipient added */
2772 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2773 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2774 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2775 /* no recipient contents, then select contacts */
2776 modest_msg_edit_window_open_addressbook (window, NULL);
2780 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2781 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2784 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2785 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2788 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2789 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2793 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2794 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2795 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2802 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2803 ModestMsgEditWindow *window)
2805 modest_msg_edit_window_offer_attach_file (window);
2809 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2811 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2813 return priv->clipboard_text;
2817 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2819 ModestMsgEditWindow *window)
2821 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2822 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2824 if (!GTK_WIDGET_VISIBLE (window))
2827 text = gtk_clipboard_wait_for_text (selection_clipboard);
2829 if (priv->clipboard_text != NULL) {
2830 g_free (priv->clipboard_text);
2832 priv->clipboard_text = text;
2834 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2837 subject_field_move_cursor (GtkEntry *entry,
2838 GtkMovementStep step,
2843 if (!GTK_WIDGET_VISIBLE (window))
2846 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2850 update_window_title (ModestMsgEditWindow *window)
2852 ModestMsgEditWindowPrivate *priv = NULL;
2853 const gchar *subject;
2855 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2856 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2857 if (subject == NULL || subject[0] == '\0')
2858 subject = _("mail_va_new_email");
2860 gtk_window_set_title (GTK_WINDOW (window), subject);
2865 subject_field_changed (GtkEditable *editable,
2866 ModestMsgEditWindow *window)
2868 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2869 update_window_title (window);
2870 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2871 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2875 subject_field_insert_text (GtkEditable *editable,
2877 gint new_text_length,
2879 ModestMsgEditWindow *window)
2881 GString *result = g_string_new ("");
2883 gint result_len = 0;
2884 const gchar *entry_text = NULL;
2887 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2888 old_length = g_utf8_strlen (entry_text, -1);
2890 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2891 gunichar c = g_utf8_get_char_validated (current, 8);
2892 /* Invalid unichar, stop */
2898 result = g_string_append_unichar (result, c);
2902 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2903 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2906 /* Prevent endless recursion */
2907 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2908 g_signal_emit_by_name (editable, "insert-text",
2909 (gpointer) result->str, (gpointer) result->len,
2910 (gpointer) position, (gpointer) window);
2911 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2915 if (result_len + old_length > 1000) {
2916 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2917 dgettext("hildon-common-strings",
2918 "ckdg_ib_maximum_characters_reached"));
2921 g_string_free (result, TRUE);
2925 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2928 ModestMsgEditWindowPrivate *priv = NULL;
2930 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2931 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2933 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2936 gtk_widget_show_all (priv->find_toolbar);
2937 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2939 gtk_widget_hide_all (priv->find_toolbar);
2940 gtk_widget_grab_focus (priv->msg_body);
2946 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2948 GtkTextIter *match_start,
2949 GtkTextIter *match_end)
2951 GtkTextIter end_iter;
2952 gchar *str_casefold;
2955 gchar *range_casefold;
2958 gboolean result = FALSE;
2965 gtk_text_iter_forward_to_end (&end_iter);
2967 str_casefold = g_utf8_casefold (str, -1);
2968 str_chars_n = strlen (str);
2970 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2971 range_casefold = g_utf8_casefold (range_text, -1);
2972 range_chars_n = strlen (range_casefold);
2974 if (range_chars_n < str_chars_n) {
2975 g_free (str_casefold);
2976 g_free (range_text);
2977 g_free (range_casefold);
2981 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2982 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2983 if (!g_utf8_collate (range_subtext, str_casefold)) {
2984 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2986 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2987 match_start, match_end, NULL);
2988 g_free (found_text);
2990 g_free (range_subtext);
2994 g_free (str_casefold);
2995 g_free (range_text);
2996 g_free (range_casefold);
3003 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3004 ModestMsgEditWindow *window)
3006 gchar *current_search = NULL;
3007 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3009 GtkTextIter selection_start, selection_end;
3010 GtkTextIter match_start, match_end;
3011 gboolean continue_search = FALSE;
3013 if (message_is_empty (window)) {
3014 g_free (priv->last_search);
3015 priv->last_search = NULL;
3016 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3020 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3021 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3022 g_free (current_search);
3023 g_free (priv->last_search);
3024 priv->last_search = NULL;
3025 /* Information banner about empty search */
3026 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3030 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3031 continue_search = TRUE;
3033 g_free (priv->last_search);
3034 priv->last_search = g_strdup (current_search);
3037 if (continue_search) {
3038 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3039 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3040 &match_start, &match_end);
3042 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3044 GtkTextIter buffer_start;
3045 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3046 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3047 &match_start, &match_end);
3049 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3052 /* Mark as selected the string found in search */
3054 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3055 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3057 g_free (priv->last_search);
3058 priv->last_search = NULL;
3060 g_free (current_search);
3064 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3065 ModestMsgEditWindow *window)
3067 GtkToggleAction *toggle;
3068 ModestWindowPrivate *parent_priv;
3069 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3071 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3072 gtk_toggle_action_set_active (toggle, FALSE);
3076 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3078 ModestMsgEditWindowPrivate *priv;
3080 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3085 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3088 ModestMsgEditWindowPrivate *priv;
3090 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3096 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3099 ModestMsgEditWindowPrivate *priv;
3100 TnyHeader *header = NULL;
3102 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3103 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3105 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3106 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3108 if (priv->draft_msg != NULL) {
3109 g_object_unref (priv->draft_msg);
3112 if (draft != NULL) {
3113 g_object_ref (draft);
3114 header = tny_msg_get_header (draft);
3115 if (priv->msg_uid) {
3116 g_free (priv->msg_uid);
3117 priv->msg_uid = NULL;
3119 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3120 if (GTK_WIDGET_REALIZED (window))
3121 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3124 priv->draft_msg = draft;
3128 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3129 GtkTextIter *start, GtkTextIter *end,
3132 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3133 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3136 if (tag == NULL+13) return;
3137 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3138 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3139 replace_with_images (window, priv->images);
3144 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3147 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3149 g_return_if_fail (TNY_IS_MIME_PART (part));
3150 priv->attachments = g_list_prepend (priv->attachments, part);
3151 g_object_ref (part);
3152 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3153 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3154 gtk_widget_show_all (priv->attachments_caption);
3155 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3159 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3161 ModestMsgEditWindowPrivate *priv;
3163 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3164 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3166 return priv->msg_uid;
3170 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3171 ModestMsgEditWindowWidgetType widget_type)
3173 ModestMsgEditWindowPrivate *priv;
3175 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3176 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3178 switch (widget_type) {
3179 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3180 return priv->msg_body;
3182 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3183 return priv->to_field;
3185 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3186 return priv->cc_field;
3188 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3189 return priv->bcc_field;
3191 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3192 return priv->subject_field;
3194 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3195 return priv->attachments_view;
3203 remove_tags (WPTextBuffer *buffer)
3205 GtkTextIter start, end;
3207 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3208 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3210 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3214 on_account_removed (TnyAccountStore *account_store,
3215 TnyAccount *account,
3218 /* Do nothing if it's a store account, because we use the
3219 transport to send the messages */
3220 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3221 const gchar *parent_acc = NULL;
3222 const gchar *our_acc = NULL;
3224 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3225 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3226 /* Close this window if I'm showing a message of the removed account */
3227 if (strcmp (parent_acc, our_acc) == 0)
3228 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3233 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3235 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3237 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));