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-utils.h>
79 #include "modest-maemo-utils.h"
82 #define DEFAULT_FONT_SIZE 3
83 #define DEFAULT_FONT 2
84 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
85 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
86 #define DEFAULT_MAIN_VBOX_SPACING 6
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #define DEFAULT_FONT_SCALE 1.5
91 static gboolean is_wp_text_buffer_started = FALSE;
93 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
94 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
95 static void modest_msg_edit_window_finalize (GObject *obj);
97 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
98 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
99 static void attachments_selection_changed (ModestAttachmentsView *buffer, ModestMsgEditWindow *editor);
100 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
102 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
103 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
104 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
105 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
106 GtkTextIter *start, GtkTextIter *end,
108 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
109 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
110 static void subject_field_insert_text (GtkEditable *editable,
112 gint new_text_length,
114 ModestMsgEditWindow *window);
115 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
117 static void modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
119 static void modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
121 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
122 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget,
123 GdkEventWindowState *event,
125 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
126 ModestRecptEditor *editor);
127 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
128 ModestMsgEditWindow *window);
130 /* ModestWindow methods implementation */
131 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
132 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
133 gboolean show_toolbar);
134 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
136 ModestMsgEditWindow *window);
137 static void subject_field_move_cursor (GtkEntry *entry,
138 GtkMovementStep step,
142 static void update_window_title (ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
146 ModestMsgEditWindow *window);
147 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
148 ModestMsgEditWindow *window);
149 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
151 GtkTextIter *match_start,
152 GtkTextIter *match_end);
154 static void remove_tags (WPTextBuffer *buffer);
156 static void on_account_removed (TnyAccountStore *account_store,
160 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
162 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
164 static gdouble get_zoom_do_nothing (ModestWindow *window);
166 static void init_window (ModestMsgEditWindow *obj);
168 static void DEBUG_BUFFER (WPTextBuffer *buffer)
172 g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
174 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
175 while (!gtk_text_iter_is_end (&iter)) {
176 GString *output = g_string_new ("");
177 GSList *toggled_tags;
180 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
181 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
182 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
183 GtkTextTag *tag = (GtkTextTag *) node->data;
185 g_object_get (G_OBJECT (tag), "name", &name, NULL);
186 output = g_string_append (output, name);
187 g_string_append (output, " ");
189 output = g_string_append (output, "] OPENED [ ");
190 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
191 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
192 GtkTextTag *tag = (GtkTextTag *) node->data;
194 g_object_get (G_OBJECT (tag), "name", &name, NULL);
195 output = g_string_append (output, name);
196 g_string_append (output, " ");
198 output = g_string_append (output, "]\n");
199 g_message ("%s", output->str);
200 g_string_free (output, TRUE);
201 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
203 g_message ("END BUFFER");
208 /* static gboolean */
209 /* on_key_pressed (GtkWidget *self, */
210 /* GdkEventKey *event, */
211 /* gpointer user_data); */
213 /* list my signals */
220 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
221 struct _ModestMsgEditWindowPrivate {
223 GtkWidget *header_box;
225 ModestPairList *from_field_protos;
226 GtkWidget *from_field;
230 GtkWidget *bcc_field;
231 GtkWidget *subject_field;
232 GtkWidget *attachments_view;
233 GtkWidget *priority_icon;
234 GtkWidget *add_attachment_button;
236 GtkWidget *cc_caption;
237 GtkWidget *bcc_caption;
238 gboolean update_caption_visibility;
239 GtkWidget *attachments_caption;
241 GtkTextBuffer *text_buffer;
243 GtkWidget *font_size_toolitem;
244 GtkWidget *font_face_toolitem;
245 GtkWidget *font_color_button;
246 GSList *font_items_group;
247 GtkWidget *font_tool_button_label;
248 GSList *size_items_group;
249 GtkWidget *size_tool_button_label;
251 GtkWidget *find_toolbar;
255 GtkWidget *scroll_area;
256 gint last_vadj_upper;
259 TnyList *attachments;
262 TnyHeaderFlags priority_flags;
264 gboolean can_undo, can_redo;
265 gulong clipboard_change_handler_id;
266 gulong default_clipboard_change_handler_id;
267 gulong account_removed_handler_id;
268 gchar *clipboard_text;
277 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
278 MODEST_TYPE_MSG_EDIT_WINDOW, \
279 ModestMsgEditWindowPrivate))
281 static GtkWindowClass *parent_class = NULL;
283 /* uncomment the following if you have defined any signals */
284 /* static guint signals[LAST_SIGNAL] = {0}; */
287 modest_msg_edit_window_get_type (void)
289 static GType my_type = 0;
291 static const GTypeInfo my_info = {
292 sizeof(ModestMsgEditWindowClass),
293 NULL, /* base init */
294 NULL, /* base finalize */
295 (GClassInitFunc) modest_msg_edit_window_class_init,
296 NULL, /* class finalize */
297 NULL, /* class data */
298 sizeof(ModestMsgEditWindow),
300 (GInstanceInitFunc) modest_msg_edit_window_init,
303 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
304 "ModestMsgEditWindow",
312 save_state (ModestWindow *self)
314 modest_widget_memory_save (modest_runtime_get_conf(),
315 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
320 restore_settings (ModestMsgEditWindow *self)
322 ModestConf *conf = NULL;
324 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
326 conf = modest_runtime_get_conf ();
327 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
328 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
329 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
330 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL));
331 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
332 "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu");
333 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
334 modest_conf_get_bool (conf, MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
336 /* set initial state of cc and bcc */
337 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
338 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
339 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
340 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
341 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
342 modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
344 /* Dim at start clipboard actions */
345 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
346 gtk_action_set_sensitive (action, FALSE);
347 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
348 gtk_action_set_sensitive (action, FALSE);
349 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
350 gtk_action_set_sensitive (action, FALSE);
352 modest_widget_memory_restore (conf,
353 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
358 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
360 GObjectClass *gobject_class;
361 ModestWindowClass *modest_window_class;
362 gobject_class = (GObjectClass*) klass;
363 modest_window_class = (ModestWindowClass*) klass;
365 parent_class = g_type_class_peek_parent (klass);
366 gobject_class->finalize = modest_msg_edit_window_finalize;
368 modest_window_class->set_zoom_func = set_zoom_do_nothing;
369 modest_window_class->get_zoom_func = get_zoom_do_nothing;
370 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
371 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
372 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
373 modest_window_class->save_state_func = save_state;
374 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
376 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
380 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
382 ModestMsgEditWindowPrivate *priv;
383 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
385 priv->msg_body = NULL;
386 priv->from_field = NULL;
387 priv->to_field = NULL;
388 priv->cc_field = NULL;
389 priv->bcc_field = NULL;
390 priv->subject_field = NULL;
391 priv->attachments = TNY_LIST (tny_simple_list_new ());
392 priv->images = TNY_LIST (tny_simple_list_new ());
395 priv->cc_caption = NULL;
396 priv->bcc_caption = NULL;
397 priv->update_caption_visibility = FALSE;
399 priv->priority_flags = 0;
401 priv->find_toolbar = NULL;
402 priv->last_search = NULL;
404 priv->draft_msg = NULL;
405 priv->outbox_msg = NULL;
406 priv->msg_uid = NULL;
408 priv->can_undo = FALSE;
409 priv->can_redo = FALSE;
410 priv->clipboard_change_handler_id = 0;
411 priv->default_clipboard_change_handler_id = 0;
412 priv->account_removed_handler_id = 0;
413 priv->clipboard_text = NULL;
416 priv->last_vadj_upper = 0;
418 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
419 GTK_WINDOW(obj),"applications_email_editor");
421 if (!is_wp_text_buffer_started) {
422 is_wp_text_buffer_started = TRUE;
423 wp_text_buffer_library_init ();
428 hildon_program_add_window (hildon_program_get_instance(),
433 /* FIXME: this is a dup from the one in gtk/ */
436 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
438 static ModestPairList*
439 get_transports (void)
441 GSList *transports = NULL;
443 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
444 GSList *accounts = modest_account_mgr_account_names (account_mgr,
445 TRUE /* only enabled accounts. */);
447 GSList *cursor = accounts;
449 gchar *account_name = cursor->data;
450 gchar *from_string = NULL;
452 from_string = modest_account_mgr_get_from_string (account_mgr,
456 if (from_string && account_name) {
457 gchar *name = account_name;
458 ModestPair *pair = modest_pair_new ((gpointer) name,
459 (gpointer) from_string , TRUE);
460 transports = g_slist_prepend (transports, pair);
463 cursor = cursor->next;
465 g_slist_free (accounts); /* only free the accounts, not the elements,
466 * because they are used in the pairlist */
470 void vadj_changed (GtkAdjustment *adj,
471 ModestMsgEditWindow *window)
473 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
475 GdkRectangle rectangle, cursor_rectangle;
476 GtkTextIter position;
480 /* We detect if cursor is visible using the full height, not only the center. This
482 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
483 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
485 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
486 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
488 cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
489 visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
491 if (gtk_widget_is_focus (priv->msg_body) &&
493 if (priv->last_vadj_upper != adj->upper) {
496 insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
497 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body),
498 insert, 0.1, FALSE, 0.0, 0.0);
501 priv->last_vadj_upper = adj->upper;
504 static void window_focus (GtkWindow *window,
508 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), "ModestClipboardDimmingRules");
513 connect_signals (ModestMsgEditWindow *obj)
515 ModestMsgEditWindowPrivate *priv;
517 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
519 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
520 G_CALLBACK (text_buffer_refresh_attributes), obj);
521 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
522 G_CALLBACK (text_buffer_can_undo), obj);
523 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
524 G_CALLBACK (text_buffer_can_redo), obj);
525 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
526 G_CALLBACK (body_changed), obj);
527 g_signal_connect (G_OBJECT (priv->attachments_view), "selection-changed",
528 G_CALLBACK (attachments_selection_changed), obj);
529 g_signal_connect (G_OBJECT (obj), "window-state-event",
530 G_CALLBACK (modest_msg_edit_window_window_state_event),
532 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
533 G_CALLBACK (text_buffer_apply_tag), obj);
534 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
535 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
536 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
537 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
538 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
539 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
541 g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
542 G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
544 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
545 G_CALLBACK (msg_body_focus), obj);
546 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
547 G_CALLBACK (msg_body_focus), obj);
548 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
549 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
550 "changed", G_CALLBACK (recpt_field_changed), obj);
551 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
552 "changed", G_CALLBACK (recpt_field_changed), obj);
553 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
554 "changed", G_CALLBACK (recpt_field_changed), obj);
555 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
556 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
557 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
559 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
560 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
562 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
564 G_CALLBACK (vadj_changed),
567 priv->clipboard_change_handler_id =
568 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
569 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
570 priv->default_clipboard_change_handler_id =
571 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
572 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
577 init_window (ModestMsgEditWindow *obj)
579 GtkWidget *from_caption, *to_caption, *subject_caption;
580 GtkWidget *main_vbox;
581 ModestMsgEditWindowPrivate *priv;
582 GtkActionGroup *action_group;
583 ModestWindowPrivate *parent_priv;
584 GdkPixbuf *window_icon = NULL;
585 GError *error = NULL;
587 GtkSizeGroup *size_group;
589 GtkWidget *subject_box;
590 GtkWidget *attachment_icon;
591 GtkWidget *window_box;
592 #if (GTK_MINOR_VERSION >= 10)
593 GdkAtom deserialize_type;
595 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
596 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
598 parent_priv->ui_manager = gtk_ui_manager_new();
599 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
600 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
602 /* Add common actions */
603 gtk_action_group_add_actions (action_group,
604 modest_msg_edit_action_entries,
605 G_N_ELEMENTS (modest_msg_edit_action_entries),
607 gtk_action_group_add_toggle_actions (action_group,
608 modest_msg_edit_toggle_action_entries,
609 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
611 gtk_action_group_add_radio_actions (action_group,
612 modest_msg_edit_alignment_radio_action_entries,
613 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
615 G_CALLBACK (modest_ui_actions_on_change_justify),
617 gtk_action_group_add_radio_actions (action_group,
618 modest_msg_edit_priority_action_entries,
619 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
621 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
623 gtk_action_group_add_radio_actions (action_group,
624 modest_msg_edit_file_format_action_entries,
625 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
626 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
627 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
629 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
630 g_object_unref (action_group);
632 /* Load the UI definition */
633 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
636 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
637 g_clear_error (&error);
640 /* Add accelerators */
641 gtk_window_add_accel_group (GTK_WINDOW (obj),
642 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
644 parent_priv->menubar = NULL;
646 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
648 /* Note: This ModestPairList* must exist for as long as the combo
649 * that uses it, because the ModestComboBox uses the ID opaquely,
650 * so it can't know how to manage its memory. */
651 priv->from_field = modest_combo_box_new (NULL, g_str_equal);
653 priv->to_field = modest_recpt_editor_new ();
654 priv->cc_field = modest_recpt_editor_new ();
655 priv->bcc_field = modest_recpt_editor_new ();
656 subject_box = gtk_hbox_new (FALSE, 0);
657 priv->priority_icon = gtk_image_new ();
658 gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
659 priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
660 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
661 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
662 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
663 gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
664 priv->add_attachment_button = gtk_button_new ();
665 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
666 gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
667 gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
668 gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
669 attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
670 gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
671 gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
672 priv->attachments_view = modest_attachments_view_new (NULL);
674 priv->header_box = gtk_vbox_new (FALSE, 0);
676 from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
677 to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
678 priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
679 priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
680 subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
681 priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
682 g_object_unref (size_group);
684 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
685 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
686 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
687 modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
688 gtk_size_group_add_widget (size_group, priv->subject_field);
689 gtk_size_group_add_widget (size_group, priv->attachments_view);
690 g_object_unref (size_group);
692 gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
693 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
694 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
695 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
696 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
697 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
698 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
701 priv->msg_body = wp_text_view_new ();
702 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
703 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
704 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
705 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
706 #if (GTK_MINOR_VERSION >= 10)
707 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
708 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
710 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
711 deserialize_type, TRUE);
713 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
715 priv->find_toolbar = hildon_find_toolbar_new (NULL);
716 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
718 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
720 priv->scroll = gtk_scrolled_window_new (NULL, NULL);
721 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
722 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
723 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
725 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
727 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
728 frame = gtk_frame_new (NULL);
729 gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
731 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
732 gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
733 g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
735 G_CALLBACK (vadj_changed),
737 gtk_widget_show_all (GTK_WIDGET(priv->scroll));
739 window_box = gtk_vbox_new (FALSE, 0);
740 gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
741 gtk_container_add (GTK_CONTAINER(obj), window_box);
742 priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
743 gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
745 /* Set window icon */
746 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
748 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
749 g_object_unref (window_icon);
754 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
756 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
758 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
759 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
760 priv->clipboard_change_handler_id))
761 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
762 priv->clipboard_change_handler_id);
763 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
764 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
765 priv->default_clipboard_change_handler_id))
766 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
767 priv->default_clipboard_change_handler_id);
769 if (priv->account_removed_handler_id &&
770 g_signal_handler_is_connected (modest_runtime_get_account_store (),
771 priv->account_removed_handler_id))
772 g_signal_handler_disconnect(modest_runtime_get_account_store (),
773 priv->account_removed_handler_id);
777 modest_msg_edit_window_finalize (GObject *obj)
779 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
781 /* Sanity check: shouldn't be needed, the window mgr should
782 call this function before */
783 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
785 if (priv->clipboard_text != NULL) {
786 g_free (priv->clipboard_text);
787 priv->clipboard_text = NULL;
790 if (priv->draft_msg != NULL) {
791 TnyHeader *header = tny_msg_get_header (priv->draft_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->draft_msg);
797 priv->draft_msg = NULL;
799 if (priv->outbox_msg != NULL) {
800 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
801 if (TNY_IS_HEADER (header)) {
802 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
803 modest_window_mgr_unregister_header (mgr, header);
805 g_object_unref (priv->outbox_msg);
806 priv->outbox_msg = NULL;
808 g_free (priv->msg_uid);
809 g_free (priv->last_search);
810 g_slist_free (priv->font_items_group);
811 g_slist_free (priv->size_items_group);
812 g_object_unref (priv->attachments);
813 g_object_unref (priv->images);
815 /* This had to stay alive for as long as the combobox that used it: */
816 modest_pair_list_free (priv->from_field_protos);
818 G_OBJECT_CLASS(parent_class)->finalize (obj);
822 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
824 GdkPixbufLoader *loader;
827 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
832 tny_stream_reset (TNY_STREAM (stream));
833 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
834 unsigned char read_buffer[128];
836 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
837 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
841 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
842 g_object_ref (pixbuf);
843 gdk_pixbuf_loader_close (loader, NULL);
844 g_object_unref (loader);
846 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
847 GdkPixbuf *new_pixbuf;
849 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
850 gdk_pixbuf_get_width (pixbuf);
851 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
852 g_object_unref (pixbuf);
860 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
862 ModestMsgEditWindowPrivate *priv;
865 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
867 for (iter = tny_list_create_iterator (attachments);
868 !tny_iterator_is_done (iter);
869 tny_iterator_next (iter)) {
870 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
871 const gchar *cid = tny_mime_part_get_content_id (part);
872 const gchar *mime_type = tny_mime_part_get_content_type (part);
873 if ((cid != NULL)&&(mime_type != NULL)) {
874 TnyStream *stream = tny_mime_part_get_stream (part);
875 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
876 g_object_unref (stream);
878 if (pixbuf != NULL) {
879 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
880 g_object_unref (pixbuf);
883 g_object_unref (part);
888 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
890 TnyMimePart *parent = NULL;
891 const gchar *content_type = NULL;
892 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
894 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
896 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
897 parent = g_object_ref (msg);
898 } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
899 TnyList *parts = TNY_LIST (tny_simple_list_new ());
902 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
903 iter = tny_list_create_iterator (parts);
904 while (!tny_iterator_is_done (iter)) {
906 part = TNY_MIME_PART (tny_iterator_get_current (iter));
907 content_type = tny_mime_part_get_content_type (part);
908 if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
912 g_object_unref (part);
914 tny_iterator_next (iter);
916 g_object_unref (iter);
917 g_object_unref (parts);
920 if (parent != NULL) {
921 TnyList *parts = TNY_LIST (tny_simple_list_new ());
924 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
925 iter = tny_list_create_iterator (parts);
926 while (!tny_iterator_is_done (iter)) {
928 part = TNY_MIME_PART (tny_iterator_get_current (iter));
929 content_type = tny_mime_part_get_content_type (part);
930 if (content_type && g_str_has_prefix (content_type, "image/")) {
931 tny_list_prepend (priv->images, (GObject *) part);
933 g_object_unref (part);
934 tny_iterator_next (iter);
936 g_object_unref (iter);
937 g_object_unref (parts);
938 g_object_unref (parent);
943 update_last_cid (ModestMsgEditWindow *self, TnyList *attachments)
946 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
948 for (iter = tny_list_create_iterator (attachments) ;
949 !tny_iterator_is_done (iter);
950 tny_iterator_next (iter)) {
951 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
952 const gchar *cid = tny_mime_part_get_content_id (part);
954 char *invalid = NULL;
955 gint int_cid = strtol (cid, &invalid, 10);
956 if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
957 priv->last_cid = int_cid;
960 g_object_unref (part);
965 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
968 const gchar *to, *cc, *bcc, *subject;
970 ModestMsgEditWindowPrivate *priv;
972 TnyHeaderFlags priority_flags;
973 TnyFolder *msg_folder;
974 gboolean is_html = FALSE;
976 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
977 g_return_if_fail (TNY_IS_MSG (msg));
979 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
981 header = tny_msg_get_header (msg);
982 to = tny_header_get_to (header);
983 cc = tny_header_get_cc (header);
984 bcc = tny_header_get_bcc (header);
985 subject = tny_header_get_subject (header);
986 priority_flags = tny_header_get_priority (header);
989 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), to);
991 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), cc);
992 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
993 gtk_widget_show (priv->cc_caption);
994 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
995 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
996 gtk_widget_hide (priv->cc_caption);
999 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1000 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1001 gtk_widget_show (priv->bcc_caption);
1002 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1003 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1004 gtk_widget_hide (priv->bcc_caption);
1007 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1008 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1011 update_window_title (self);
1013 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1014 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1016 if ((body == NULL)||(body[0] == '\0')) {
1018 body = modest_text_utils_convert_to_html ("");
1021 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1022 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1025 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1028 /* Add attachments to the view */
1029 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1030 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1031 if (tny_list_get_length (priv->attachments) == 0) {
1032 gtk_widget_hide (priv->attachments_caption);
1034 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1035 gtk_widget_show_all (priv->attachments_caption);
1037 get_related_images (self, msg);
1038 update_last_cid (self, priv->attachments);
1039 update_last_cid (self, priv->images);
1040 replace_with_images (self, priv->images);
1042 if (preserve_is_rich && !is_html) {
1043 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1044 /* Get the default format required from configuration */
1045 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1046 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1049 /* Set the default focus depending on having already a To: field or not */
1050 if ((!to)||(*to == '\0')) {
1051 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1053 gtk_widget_grab_focus (priv->msg_body);
1056 /* TODO: lower priority, select in the From: combo to the
1057 value that comes from msg <- not sure, should it be
1060 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1062 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1063 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1065 modest_msg_edit_window_reset_modified (self);
1067 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (self));
1068 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1069 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1071 if (priv->msg_uid) {
1072 g_free (priv->msg_uid);
1073 priv->msg_uid = NULL;
1076 /* we should set a reference to the incoming message if it is a draft */
1077 msg_folder = tny_msg_get_folder (msg);
1079 if (modest_tny_folder_is_local_folder (msg_folder)) {
1080 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1081 if (type == TNY_FOLDER_TYPE_INVALID)
1082 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1084 if (type == TNY_FOLDER_TYPE_DRAFTS)
1085 priv->draft_msg = g_object_ref(msg);
1086 if (type == TNY_FOLDER_TYPE_OUTBOX)
1087 priv->outbox_msg = g_object_ref(msg);
1088 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1090 g_object_unref (msg_folder);
1095 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1098 GList *item_children, *node;
1099 GtkWidget *bin_child;
1101 bin_child = gtk_bin_get_child (GTK_BIN(item));
1103 item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1105 for (node = item_children; node != NULL; node = g_list_next (node)) {
1106 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1107 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1110 g_list_free (item_children);
1114 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1117 GList *item_children, *node;
1119 box = gtk_bin_get_child (GTK_BIN (item));
1120 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1121 item_children = gtk_container_get_children (GTK_CONTAINER (box));
1123 for (node = item_children; node != NULL; node = g_list_next (node)) {
1124 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1125 if (GTK_IS_TOGGLE_BUTTON (node->data))
1126 gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1127 else if (GTK_IS_BUTTON (node->data))
1128 gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1130 g_list_free (item_children);
1135 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1137 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1138 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1139 GtkWidget *placeholder;
1140 GtkWidget *tool_item;
1145 GtkWidget *sizes_menu;
1146 GtkWidget *fonts_menu;
1147 GSList *radio_group = NULL;
1148 GSList *node = NULL;
1152 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1153 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1155 /* Font color placeholder */
1156 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1157 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1160 tool_item = GTK_WIDGET (gtk_tool_item_new ());
1161 priv->font_color_button = hildon_color_button_new ();
1162 GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1163 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1164 gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1165 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1166 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1167 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1168 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1170 G_CALLBACK (modest_msg_edit_window_color_button_change),
1173 /* Font size and face placeholder */
1174 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1175 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1177 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1178 priv->size_tool_button_label = gtk_label_new (NULL);
1179 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1180 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1181 size_text,"</span>", NULL);
1182 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1184 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1185 sizes_menu = gtk_menu_new ();
1186 priv->size_items_group = NULL;
1188 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1189 GtkWidget *size_menu_item;
1191 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1192 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1193 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1194 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1195 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1196 gtk_widget_show (size_menu_item);
1198 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1202 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1203 GtkWidget *item = (GtkWidget *) node->data;
1204 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1208 priv->size_items_group = g_slist_reverse (priv->size_items_group);
1209 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1210 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1211 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1212 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1213 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1214 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1215 priv->font_size_toolitem = tool_item;
1218 tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1219 priv->font_tool_button_label = gtk_label_new (NULL);
1220 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1221 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1223 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1224 fonts_menu = gtk_menu_new ();
1225 priv->font_items_group = NULL;
1227 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1228 GtkWidget *font_menu_item;
1229 GtkWidget *child_label;
1231 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1232 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1233 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>",
1234 wp_get_font_name (font_index), "</span>", NULL);
1235 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1238 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1239 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1240 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1241 gtk_widget_show (font_menu_item);
1243 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1246 for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1247 GtkWidget *item = (GtkWidget *) node->data;
1248 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1251 priv->font_items_group = g_slist_reverse (priv->font_items_group);
1252 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1253 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1254 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1255 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1256 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1257 menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1258 priv->font_face_toolitem = tool_item;
1260 /* Set expand and homogeneous for remaining items */
1261 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1262 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1263 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1264 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1265 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1266 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1267 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1268 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1269 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1271 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1272 will not show the tool items added to the placeholders) */
1273 gtk_widget_show_all (parent_priv->toolbar);
1275 /* Set the no show all *after* showing all items. We do not
1276 want the toolbar to be shown with a show all because it
1277 could go agains the gconf setting regarding showing or not
1278 the toolbar of the editor window */
1279 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1285 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1288 ModestWindowPrivate *parent_priv;
1289 ModestMsgEditWindowPrivate *priv;
1290 ModestPair *account_pair = NULL;
1291 ModestDimmingRulesGroup *window_rules_group = NULL;
1292 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1293 ModestWindowMgr *mgr = NULL;
1295 g_return_val_if_fail (msg, NULL);
1296 g_return_val_if_fail (account_name, NULL);
1298 mgr = modest_runtime_get_window_mgr ();
1300 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1302 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1303 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1305 /* Menubar. Update the state of some toggles */
1306 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1307 hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1308 priv->from_field_protos = get_transports ();
1309 modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1310 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1311 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1314 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1316 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1318 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1320 account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1321 if (account_pair != NULL)
1322 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1324 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1325 window_rules_group = modest_dimming_rules_group_new ("ModestWindowDimmingRules", TRUE);
1326 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
1327 /* Add common dimming rules */
1328 modest_dimming_rules_group_add_rules (window_rules_group,
1329 modest_msg_edit_window_toolbar_dimming_entries,
1330 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1331 MODEST_WINDOW (obj));
1332 modest_dimming_rules_group_add_rules (window_rules_group,
1333 modest_msg_edit_window_menu_dimming_entries,
1334 G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1335 MODEST_WINDOW (obj));
1336 modest_dimming_rules_group_add_widget_rule (window_rules_group, priv->font_color_button,
1337 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1338 MODEST_WINDOW (obj));
1339 modest_dimming_rules_group_add_widget_rule (window_rules_group, priv->font_size_toolitem,
1340 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1341 MODEST_WINDOW (obj));
1342 modest_dimming_rules_group_add_widget_rule (window_rules_group, priv->font_face_toolitem,
1343 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1344 MODEST_WINDOW (obj));
1345 modest_dimming_rules_group_add_rules (clipboard_rules_group,
1346 modest_msg_edit_window_clipboard_dimming_entries,
1347 G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1348 MODEST_WINDOW (obj));
1349 /* Insert dimming rules group for this window */
1350 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, window_rules_group);
1351 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1352 /* Checks the dimming rules */
1353 g_object_unref (window_rules_group);
1354 g_object_unref (clipboard_rules_group);
1355 gtk_widget_show_all (GTK_WIDGET (obj));
1357 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1359 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1361 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (obj));
1362 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
1363 priv->update_caption_visibility = TRUE;
1365 modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1367 /* Track account-removed signal, this window should be closed
1368 in the case we're creating a mail associated to the account
1370 priv->account_removed_handler_id =
1371 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1373 G_CALLBACK(on_account_removed),
1376 return (ModestWindow*) obj;
1380 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1382 GString **string_buffer = (GString **) user_data;
1384 *string_buffer = g_string_append (*string_buffer, buffer);
1390 * @result: A new string which should be freed with g_free().
1393 get_formatted_data (ModestMsgEditWindow *edit_window)
1395 ModestMsgEditWindowPrivate *priv;
1396 GString *string_buffer = g_string_new ("");
1398 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1400 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1402 return g_string_free (string_buffer, FALSE);
1407 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1410 const gchar *account_name;
1411 ModestMsgEditWindowPrivate *priv;
1412 TnyIterator *att_iter;
1414 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1416 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1418 account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1419 g_return_val_if_fail (account_name, NULL);
1422 /* don't free these (except from) */
1423 data = g_slice_new0 (MsgData);
1424 data->from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1426 data->account_name = g_strdup (account_name);
1427 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1428 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1429 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1430 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1431 if (priv->draft_msg) {
1432 data->draft_msg = g_object_ref (priv->draft_msg);
1433 } else if (priv->outbox_msg) {
1434 data->draft_msg = g_object_ref (priv->outbox_msg);
1436 data->draft_msg = NULL;
1439 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1441 gtk_text_buffer_get_bounds (buf, &b, &e);
1442 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1444 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1445 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1447 data->html_body = NULL;
1449 /* deep-copy the data */
1450 att_iter = tny_list_create_iterator (priv->attachments);
1451 data->attachments = NULL;
1452 while (!tny_iterator_is_done (att_iter)) {
1453 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1454 if (!(TNY_IS_MIME_PART(part))) {
1455 g_warning ("strange data in attachment list");
1456 g_object_unref (part);
1457 tny_iterator_next (att_iter);
1460 data->attachments = g_list_append (data->attachments,
1462 tny_iterator_next (att_iter);
1464 g_object_unref (att_iter);
1466 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1467 att_iter = tny_list_create_iterator (priv->images);
1468 data->images = NULL;
1469 while (!tny_iterator_is_done (att_iter)) {
1470 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1472 if (!(TNY_IS_MIME_PART(part))) {
1473 g_warning ("strange data in attachment list");
1474 g_object_unref (part);
1475 tny_iterator_next (att_iter);
1478 cid = tny_mime_part_get_content_id (part);
1480 gchar *image_tag_id;
1481 GtkTextTag *image_tag;
1483 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1484 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1485 g_free (image_tag_id);
1487 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1489 ((gtk_text_iter_has_tag (&iter, image_tag))||
1490 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1491 data->images = g_list_append (data->images,
1492 g_object_ref (part));
1494 g_object_unref (part);
1495 tny_iterator_next (att_iter);
1498 data->priority_flags = priv->priority_flags;
1505 unref_gobject (GObject *obj, gpointer data)
1507 if (!G_IS_OBJECT(obj))
1509 g_object_unref (obj);
1513 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1516 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1524 g_free (data->from);
1525 g_free (data->subject);
1526 g_free (data->plain_body);
1527 g_free (data->html_body);
1528 g_free (data->account_name);
1530 if (data->draft_msg != NULL) {
1531 g_object_unref (data->draft_msg);
1532 data->draft_msg = NULL;
1535 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1536 g_list_free (data->attachments);
1537 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1538 g_list_free (data->images);
1540 g_slice_free (MsgData, data);
1544 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1547 ModestMsgEditWindowPrivate *priv = NULL;
1548 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1550 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1552 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1554 return MODEST_MSG_EDIT_FORMAT_HTML;
1556 return MODEST_MSG_EDIT_FORMAT_TEXT;
1560 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1561 ModestMsgEditFormat format)
1563 ModestMsgEditWindowPrivate *priv;
1565 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1566 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1569 case MODEST_MSG_EDIT_FORMAT_HTML:
1570 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1572 case MODEST_MSG_EDIT_FORMAT_TEXT:
1573 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1576 g_return_if_reached ();
1580 ModestMsgEditFormatState *
1581 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1583 ModestMsgEditFormatState *format_state = NULL;
1584 ModestMsgEditWindowPrivate *priv;
1585 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1587 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1588 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1590 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1592 format_state = g_new0 (ModestMsgEditFormatState, 1);
1593 format_state->bold = buffer_format->bold&0x1;
1594 format_state->italics = buffer_format->italic&0x1;
1595 format_state->bullet = buffer_format->bullet&0x1;
1596 format_state->color = buffer_format->color;
1597 format_state->font_size = buffer_format->font_size;
1598 format_state->font_family = wp_get_font_name (buffer_format->font);
1599 format_state->justification = buffer_format->justification;
1600 g_free (buffer_format);
1602 return format_state;
1607 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1608 const ModestMsgEditFormatState *format_state)
1610 ModestMsgEditWindowPrivate *priv;
1611 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1612 WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1613 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1614 g_return_if_fail (format_state != NULL);
1616 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1617 gtk_widget_grab_focus (priv->msg_body);
1618 buffer_format->bold = (format_state->bold != FALSE);
1619 buffer_format->italic = (format_state->italics != FALSE);
1620 buffer_format->color = format_state->color;
1621 buffer_format->font_size = format_state->font_size;
1622 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1623 buffer_format->justification = format_state->justification;
1624 buffer_format->bullet = format_state->bullet;
1626 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1628 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1629 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1630 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1631 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
1632 buffer_format->cs.font = (buffer_format->font != current_format->font);
1633 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1634 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1636 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1637 if (buffer_format->cs.bold) {
1638 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1639 GINT_TO_POINTER (buffer_format->bold&0x1));
1641 if (buffer_format->cs.italic) {
1642 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1643 GINT_TO_POINTER (buffer_format->italic&0x1));
1645 if (buffer_format->cs.color) {
1646 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1647 GINT_TO_POINTER (&(buffer_format->color)));
1649 if (buffer_format->cs.font_size) {
1650 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1651 GINT_TO_POINTER (buffer_format->font_size));
1653 if (buffer_format->cs.justification) {
1654 switch (buffer_format->justification) {
1655 case GTK_JUSTIFY_LEFT:
1656 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1657 GINT_TO_POINTER(TRUE));
1659 case GTK_JUSTIFY_CENTER:
1660 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1661 GINT_TO_POINTER(TRUE));
1663 case GTK_JUSTIFY_RIGHT:
1664 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1665 GINT_TO_POINTER(TRUE));
1672 if (buffer_format->cs.font) {
1673 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1674 GINT_TO_POINTER (buffer_format->font));
1676 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1677 if (buffer_format->cs.bullet) {
1678 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1679 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1681 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1683 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1685 g_free (current_format);
1690 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1692 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1694 ModestWindowPrivate *parent_priv;
1695 ModestMsgEditWindowPrivate *priv;
1696 GtkWidget *new_size_menuitem;
1697 GtkWidget *new_font_menuitem;
1699 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1700 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1702 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1703 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1704 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1705 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1707 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1708 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1709 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1712 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1714 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1715 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1717 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1718 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1720 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1721 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1724 switch (buffer_format->justification)
1726 case GTK_JUSTIFY_LEFT:
1727 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentLeftMenu");
1729 case GTK_JUSTIFY_CENTER:
1730 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentCenterMenu");
1732 case GTK_JUSTIFY_RIGHT:
1733 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentRightMenu");
1740 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1742 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
1743 G_CALLBACK (modest_msg_edit_window_color_button_change),
1745 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1746 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
1747 G_CALLBACK (modest_msg_edit_window_color_button_change),
1750 new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group,
1751 buffer_format->font_size))->data);
1752 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1756 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1757 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1758 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1760 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1761 G_CALLBACK (modest_msg_edit_window_size_change),
1763 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1764 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1765 G_CALLBACK (modest_msg_edit_window_size_change),
1769 new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group,
1770 buffer_format->font))->data);
1771 if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1775 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1776 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1777 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1779 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1780 G_CALLBACK (modest_msg_edit_window_font_change),
1782 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1783 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1784 G_CALLBACK (modest_msg_edit_window_font_change),
1788 g_free (buffer_format);
1792 #ifdef MODEST_HILDON_VERSION_0
1794 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1797 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1798 ModestMsgEditWindowPrivate *priv;
1799 GtkWidget *dialog = NULL;
1801 GdkColor *new_color = NULL;
1803 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1804 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1806 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1807 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1808 g_free (buffer_format);
1810 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1811 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1812 if (new_color != NULL) {
1813 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1814 (gpointer) new_color);
1817 gtk_widget_destroy (dialog);
1822 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1825 ModestMsgEditWindowPrivate *priv;
1826 GtkWidget *dialog = NULL;
1828 GdkColor *old_color = NULL;
1829 const GdkColor *new_color = NULL;
1831 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1832 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1834 dialog = hildon_color_selector_new (GTK_WINDOW (window));
1835 hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1837 if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1838 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1839 if (new_color != NULL)
1840 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1842 gtk_widget_destroy (dialog);
1848 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1851 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1852 ModestMsgEditWindowPrivate *priv;
1853 GtkWidget *dialog = NULL;
1855 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1856 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1858 dialog = hildon_color_chooser_new ();
1859 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1860 g_free (buffer_format);
1862 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1864 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1865 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1868 gtk_widget_destroy (dialog);
1873 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1876 ModestMsgEditWindowPrivate *priv;
1877 GtkWidget *dialog = NULL;
1878 GdkColor *old_color = NULL;
1880 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1881 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1883 dialog = hildon_color_chooser_new ();
1884 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1886 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1888 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1889 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1891 gtk_widget_destroy (dialog);
1894 #endif /*!MODEST_HILDON_VERSION_0*/
1898 static TnyStream* create_stream_for_uri (const gchar* uri)
1903 TnyStream *result = NULL;
1905 GnomeVFSHandle *handle = NULL;
1906 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1907 if (test == GNOME_VFS_OK) {
1908 /* Create the tinymail stream: */
1909 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1910 result = TNY_STREAM (tny_vfs_stream_new (handle));
1917 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1920 ModestMsgEditWindowPrivate *priv;
1921 GtkWidget *dialog = NULL;
1923 GSList *uris = NULL;
1924 GSList *uri_node = NULL;
1926 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1928 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1929 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1930 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1932 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1934 response = gtk_dialog_run (GTK_DIALOG (dialog));
1936 case GTK_RESPONSE_OK:
1937 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1942 gtk_widget_destroy (dialog);
1944 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1946 GnomeVFSHandle *handle = NULL;
1947 GnomeVFSResult result;
1948 GtkTextIter position;
1949 GtkTextMark *insert_mark;
1951 uri = (const gchar *) uri_node->data;
1952 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1953 if (result == GNOME_VFS_OK) {
1955 GnomeVFSFileInfo info;
1956 gchar *filename, *basename, *escaped_filename;
1957 TnyMimePart *mime_part;
1959 const gchar *mime_type = NULL;
1960 GnomeVFSURI *vfs_uri;
1962 vfs_uri = gnome_vfs_uri_new (uri);
1964 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1965 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1966 g_free (escaped_filename);
1967 gnome_vfs_uri_unref (vfs_uri);
1969 if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1970 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1972 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1974 mime_part = tny_platform_factory_new_mime_part
1975 (modest_runtime_get_platform_factory ());
1977 TnyStream *stream = create_stream_for_uri (uri);
1978 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
1980 content_id = g_strdup_printf ("%d", priv->last_cid);
1981 tny_mime_part_set_content_id (mime_part, content_id);
1982 g_free (content_id);
1985 basename = g_path_get_basename (filename);
1986 tny_mime_part_set_filename (mime_part, basename);
1989 pixbuf = pixbuf_from_stream (stream, mime_type);
1991 if (pixbuf != NULL) {
1992 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1993 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1994 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1997 tny_list_prepend (priv->images, (GObject *) mime_part);
1998 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2000 g_object_unref (mime_part);
2009 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2011 GtkWidget *dialog = NULL;
2013 GSList *uris = NULL;
2016 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2017 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2018 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2020 response = gtk_dialog_run (GTK_DIALOG (dialog));
2022 case GTK_RESPONSE_OK:
2023 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2028 gtk_widget_destroy (dialog);
2030 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2031 const gchar *uri = (const gchar *) uri_node->data;
2032 modest_msg_edit_window_attach_file_one (window, uri);
2034 g_slist_foreach (uris, (GFunc) g_free, NULL);
2035 g_slist_free (uris);
2039 modest_msg_edit_window_attach_file_one (
2040 ModestMsgEditWindow *window,
2043 g_return_if_fail (window);
2044 g_return_if_fail (uri);
2046 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2049 GnomeVFSHandle *handle = NULL;
2050 GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2051 if (result == GNOME_VFS_OK) {
2052 TnyMimePart *mime_part;
2054 const gchar *mime_type = NULL;
2056 gchar *escaped_filename;
2059 GnomeVFSFileInfo info;
2060 GnomeVFSURI *vfs_uri;
2062 vfs_uri = gnome_vfs_uri_new (uri);
2065 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2066 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2067 g_free (escaped_filename);
2068 gnome_vfs_uri_unref (vfs_uri);
2070 if (gnome_vfs_get_file_info (uri,
2072 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2074 mime_type = gnome_vfs_file_info_get_mime_type (&info);
2075 mime_part = tny_platform_factory_new_mime_part
2076 (modest_runtime_get_platform_factory ());
2077 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2079 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2081 g_object_unref (stream);
2083 content_id = g_strdup_printf ("%d", priv->last_cid);
2084 tny_mime_part_set_content_id (mime_part, content_id);
2085 g_free (content_id);
2088 basename = g_path_get_basename (filename);
2089 tny_mime_part_set_filename (mime_part, basename);
2092 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2093 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2095 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2096 gtk_widget_show_all (priv->attachments_caption);
2097 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2099 g_object_unref (mime_part);
2104 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2107 ModestMsgEditWindowPrivate *priv;
2110 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2111 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2113 if (att_list == NULL) {
2114 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2116 g_object_ref (att_list);
2119 if (tny_list_get_length (att_list) == 0) {
2120 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2122 GtkWidget *confirmation_dialog = NULL;
2123 gboolean dialog_response;
2124 gchar *message = NULL;
2125 gchar *filename = NULL;
2127 if (tny_list_get_length (att_list) == 1) {
2129 iter = tny_list_create_iterator (att_list);
2130 part = (TnyMimePart *) tny_iterator_get_current (iter);
2131 g_object_unref (iter);
2132 if (TNY_IS_MSG (part)) {
2133 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2135 filename = g_strdup (tny_header_get_subject (header));
2136 g_object_unref (header);
2138 if (filename == NULL) {
2139 filename = g_strdup (_("mail_va_no_subject"));
2142 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2144 g_object_unref (part);
2146 filename = g_strdup ("");
2148 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2149 (tny_list_get_length (att_list) == 1)), filename);
2151 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2153 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2154 gtk_widget_destroy (confirmation_dialog);
2155 if (!dialog_response) {
2156 g_object_unref (att_list);
2159 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2161 for (iter = tny_list_create_iterator (att_list);
2162 !tny_iterator_is_done (iter);
2163 tny_iterator_next (iter)) {
2164 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2165 const gchar *att_id;
2166 tny_list_remove (priv->attachments, (GObject *) mime_part);
2168 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2170 if (tny_list_get_length (priv->attachments) == 0)
2171 gtk_widget_hide (priv->attachments_caption);
2172 att_id = tny_mime_part_get_content_id (mime_part);
2174 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2176 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2177 g_object_unref (mime_part);
2181 g_object_unref (att_list);
2183 /* if the last attachment has been removed, focus the Subject: field */
2184 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2185 gtk_widget_grab_focus (priv->subject_field);
2189 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2192 ModestMsgEditWindowPrivate *priv;
2193 GdkColor *new_color;
2194 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2196 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2197 new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2200 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2202 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2204 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2206 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2211 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2214 ModestMsgEditWindowPrivate *priv;
2215 gint new_size_index;
2216 ModestMsgEditWindow *window;
2219 window = MODEST_MSG_EDIT_WINDOW (userdata);
2220 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2221 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2223 if (gtk_check_menu_item_get_active (menu_item)) {
2225 WPTextBufferFormat format;
2227 memset (&format, 0, sizeof (format));
2228 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2230 label = gtk_bin_get_child (GTK_BIN (menu_item));
2232 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2233 format.cs.font_size = TRUE;
2234 format.cs.text_position = TRUE;
2235 format.cs.font = TRUE;
2236 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2237 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2239 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2240 GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2241 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2243 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2244 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2245 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2251 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2254 ModestMsgEditWindowPrivate *priv;
2255 gint new_font_index;
2256 ModestMsgEditWindow *window;
2259 window = MODEST_MSG_EDIT_WINDOW (userdata);
2260 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2261 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2263 if (gtk_check_menu_item_get_active (menu_item)) {
2266 label = gtk_bin_get_child (GTK_BIN (menu_item));
2268 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2270 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2271 GINT_TO_POINTER(new_font_index)))
2272 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2274 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2275 markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2276 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2282 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2284 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2285 ModestWindowPrivate *parent_priv;
2286 ModestWindowMgr *mgr;
2287 gboolean is_fullscreen;
2288 GtkAction *fs_toggle_action;
2291 mgr = modest_runtime_get_window_mgr ();
2292 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2294 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2296 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2297 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2298 if (is_fullscreen != active)
2299 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2307 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2310 ModestMsgEditWindowPrivate *priv = NULL;
2311 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2313 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2314 if (!priv->update_caption_visibility)
2317 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2319 gtk_widget_show (priv->cc_caption);
2321 gtk_widget_hide (priv->cc_caption);
2323 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2327 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2330 ModestMsgEditWindowPrivate *priv = NULL;
2331 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2333 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2334 if (!priv->update_caption_visibility)
2337 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2339 gtk_widget_show (priv->bcc_caption);
2341 gtk_widget_hide (priv->bcc_caption);
2343 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2347 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2348 ModestRecptEditor *editor)
2350 ModestMsgEditWindowPrivate *priv;
2352 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2353 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2354 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2356 if (editor == NULL) {
2357 GtkWidget *view_focus;
2358 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2360 /* This code should be kept in sync with ModestRecptEditor. The
2361 textview inside the recpt editor is the one that really gets the
2362 focus. As it's inside a scrolled window, and this one inside the
2363 hbox recpt editor inherits from, we'll need to go up in the
2364 hierarchy to know if the text view is part of the recpt editor
2365 or if it's a different text entry */
2367 if (gtk_widget_get_parent (view_focus)) {
2368 GtkWidget *first_parent;
2370 first_parent = gtk_widget_get_parent (view_focus);
2371 if (gtk_widget_get_parent (first_parent) &&
2372 MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2373 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2378 editor = MODEST_RECPT_EDITOR (priv->to_field);
2382 modest_address_book_select_addresses (editor);
2387 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2389 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2391 modest_msg_edit_window_open_addressbook (window, NULL);
2395 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2396 gboolean show_toolbar)
2398 ModestWindowPrivate *parent_priv;
2399 const gchar *action_name;
2402 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2403 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2405 /* We can not just use the code of
2406 modest_msg_edit_window_setup_toolbar because it has a
2407 mixture of both initialization and creation code. */
2409 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2411 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2413 /* Update also the actions (to update the toggles in the
2414 menus), we have to do it manually because some other window
2415 of the same time could have changed it (remember that the
2416 toolbar fullscreen mode is shared by all the windows of the
2418 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2419 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2421 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2423 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2424 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2430 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2431 TnyHeaderFlags priority_flags)
2433 ModestMsgEditWindowPrivate *priv;
2434 ModestWindowPrivate *parent_priv;
2436 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2438 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2439 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2441 if (priv->priority_flags != priority_flags) {
2442 GtkAction *priority_action = NULL;
2444 priv->priority_flags = priority_flags;
2446 switch (priority_flags) {
2447 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2448 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2449 gtk_widget_show (priv->priority_icon);
2450 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2451 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2453 case TNY_HEADER_FLAG_LOW_PRIORITY:
2454 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2455 gtk_widget_show (priv->priority_icon);
2456 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2457 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2460 gtk_widget_hide (priv->priority_icon);
2461 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2462 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2465 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2466 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2471 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2474 ModestMsgEditWindowPrivate *priv;
2475 ModestWindowPrivate *parent_priv;
2476 gint current_format;
2478 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2480 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2481 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2483 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2484 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2486 if (current_format != file_format) {
2487 switch (file_format) {
2488 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2489 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2490 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2492 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2496 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2497 response = gtk_dialog_run (GTK_DIALOG (dialog));
2498 gtk_widget_destroy (dialog);
2499 if (response == GTK_RESPONSE_OK) {
2500 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2502 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2503 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2508 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2513 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2516 ModestMsgEditWindowPrivate *priv;
2517 WPTextBufferFormat oldfmt, fmt;
2518 gint old_position = 0;
2522 GdkColor *color = NULL;
2523 gboolean bold, bold_set, italic, italic_set;
2524 gboolean underline, underline_set;
2525 gboolean strikethrough, strikethrough_set;
2526 gboolean position_set;
2527 gboolean font_size_set, font_set, color_set;
2530 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2531 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2533 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2535 /* First we get the currently selected font information */
2536 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2538 switch (oldfmt.text_position) {
2539 case TEXT_POSITION_NORMAL:
2542 case TEXT_POSITION_SUPERSCRIPT:
2550 g_object_set (G_OBJECT (dialog),
2551 "bold", oldfmt.bold != FALSE,
2552 "bold-set", !oldfmt.cs.bold,
2553 "underline", oldfmt.underline != FALSE,
2554 "underline-set", !oldfmt.cs.underline,
2555 "italic", oldfmt.italic != FALSE,
2556 "italic-set", !oldfmt.cs.italic,
2557 "strikethrough", oldfmt.strikethrough != FALSE,
2558 "strikethrough-set", !oldfmt.cs.strikethrough,
2559 "color", &oldfmt.color,
2560 "color-set", !oldfmt.cs.color,
2561 "size", wp_font_size[oldfmt.font_size],
2562 "size-set", !oldfmt.cs.font_size,
2563 "position", old_position,
2564 "position-set", !oldfmt.cs.text_position,
2565 "family", wp_get_font_name (oldfmt.font),
2566 "family-set", !oldfmt.cs.font,
2569 gtk_widget_show_all (dialog);
2570 response = gtk_dialog_run (GTK_DIALOG (dialog));
2571 if (response == GTK_RESPONSE_OK) {
2573 g_object_get( dialog,
2575 "bold-set", &bold_set,
2576 "underline", &underline,
2577 "underline-set", &underline_set,
2579 "italic-set", &italic_set,
2580 "strikethrough", &strikethrough,
2581 "strikethrough-set", &strikethrough_set,
2583 "color-set", &color_set,
2585 "size-set", &font_size_set,
2586 "family", &font_name,
2587 "family-set", &font_set,
2588 "position", &position,
2589 "position-set", &position_set,
2594 if (response == GTK_RESPONSE_OK) {
2595 memset(&fmt, 0, sizeof(fmt));
2601 fmt.italic = italic;
2602 fmt.cs.italic = TRUE;
2604 if (underline_set) {
2605 fmt.underline = underline;
2606 fmt.cs.underline = TRUE;
2608 if (strikethrough_set) {
2609 fmt.strikethrough = strikethrough;
2610 fmt.cs.strikethrough = TRUE;
2615 ? TEXT_POSITION_NORMAL
2616 : ( ( position == 1 )
2617 ? TEXT_POSITION_SUPERSCRIPT
2618 : TEXT_POSITION_SUBSCRIPT );
2619 fmt.cs.text_position = TRUE;
2620 fmt.font_size = oldfmt.font_size;
2624 fmt.cs.color = TRUE;
2627 fmt.font = wp_get_font_index(font_name,
2632 if (font_size_set) {
2633 fmt.cs.font_size = TRUE;
2634 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2636 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2637 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2639 gtk_widget_destroy (dialog);
2641 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2645 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2647 ModestMsgEditWindowPrivate *priv;
2649 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2650 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2652 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2654 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2659 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2661 ModestMsgEditWindowPrivate *priv;
2663 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2664 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2666 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2668 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2673 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2675 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2677 priv->can_undo = can_undo;
2681 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2683 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2685 priv->can_redo = can_redo;
2689 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2691 ModestMsgEditWindowPrivate *priv;
2692 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2693 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2695 return priv->can_undo;
2699 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2701 ModestMsgEditWindowPrivate *priv;
2702 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2703 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2705 return priv->can_redo;
2710 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2713 GtkTextIter match_start, match_end;
2715 if (image_id == NULL)
2718 gtk_text_buffer_get_start_iter (buffer, &iter);
2720 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2721 GSList *tags = gtk_text_iter_get_tags (&match_start);
2723 for (node = tags; node != NULL; node = g_slist_next (node)) {
2724 GtkTextTag *tag = (GtkTextTag *) node->data;
2725 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2726 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2727 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2729 offset = gtk_text_iter_get_offset (&match_start);
2730 gtk_text_buffer_delete (buffer, &match_start, &match_end);
2731 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2735 gtk_text_iter_forward_char (&iter);
2740 message_is_empty (ModestMsgEditWindow *window)
2742 ModestMsgEditWindowPrivate *priv = NULL;
2744 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2745 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2747 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2748 * so we can ignore markup.
2750 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2753 count = gtk_text_buffer_get_char_count (buf);
2759 msg_body_focus (GtkWidget *focus,
2760 GdkEventFocus *event,
2764 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (userdata));
2765 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), "ModestClipboardDimmingRules");
2770 recpt_field_changed (GtkTextBuffer *buffer,
2771 ModestMsgEditWindow *editor)
2773 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (editor));
2777 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2779 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (editor));
2783 attachments_selection_changed (ModestAttachmentsView *atts_view, ModestMsgEditWindow *window)
2785 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2789 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2791 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2792 GtkTextBuffer *buffer;
2794 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2795 gtk_text_buffer_set_modified (buffer, FALSE);
2796 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2797 gtk_text_buffer_set_modified (buffer, FALSE);
2798 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2799 gtk_text_buffer_set_modified (buffer, FALSE);
2800 gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2804 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2806 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2807 GtkTextBuffer *buffer;
2809 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2810 if (gtk_text_buffer_get_modified (buffer))
2812 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2813 if (gtk_text_buffer_get_modified (buffer))
2815 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2816 if (gtk_text_buffer_get_modified (buffer))
2818 if (gtk_text_buffer_get_modified (priv->text_buffer))
2828 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2830 ModestMsgEditWindowPrivate *priv = NULL;
2832 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2833 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2835 /* check if there's no recipient added */
2836 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2837 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2838 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2839 /* no recipient contents, then select contacts */
2840 modest_msg_edit_window_open_addressbook (window, NULL);
2844 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field), add_to_addressbook)) {
2845 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2848 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field), add_to_addressbook)) {
2849 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2852 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2853 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2857 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2858 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2859 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2866 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2867 ModestMsgEditWindow *window)
2869 modest_msg_edit_window_offer_attach_file (window);
2873 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2875 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2877 return priv->clipboard_text;
2881 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2883 ModestMsgEditWindow *window)
2885 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2886 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2888 if (!GTK_WIDGET_VISIBLE (window))
2891 text = gtk_clipboard_wait_for_text (selection_clipboard);
2893 if (priv->clipboard_text != NULL) {
2894 g_free (priv->clipboard_text);
2896 priv->clipboard_text = text;
2898 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2901 subject_field_move_cursor (GtkEntry *entry,
2902 GtkMovementStep step,
2907 if (!GTK_WIDGET_VISIBLE (window))
2910 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2914 update_window_title (ModestMsgEditWindow *window)
2916 ModestMsgEditWindowPrivate *priv = NULL;
2917 const gchar *subject;
2919 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2920 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2921 if (subject == NULL || subject[0] == '\0')
2922 subject = _("mail_va_new_email");
2924 gtk_window_set_title (GTK_WINDOW (window), subject);
2929 subject_field_changed (GtkEditable *editable,
2930 ModestMsgEditWindow *window)
2932 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2933 update_window_title (window);
2934 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2935 modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (window));
2939 subject_field_insert_text (GtkEditable *editable,
2941 gint new_text_length,
2943 ModestMsgEditWindow *window)
2945 GString *result = g_string_new ("");
2947 gint result_len = 0;
2948 const gchar *entry_text = NULL;
2951 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2952 old_length = g_utf8_strlen (entry_text, -1);
2954 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2955 gunichar c = g_utf8_get_char_validated (current, 8);
2956 /* Invalid unichar, stop */
2962 result = g_string_append_unichar (result, c);
2966 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2967 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2970 /* Prevent endless recursion */
2971 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2972 g_signal_emit_by_name (editable, "insert-text",
2973 (gpointer) result->str, (gpointer) result->len,
2974 (gpointer) position, (gpointer) window);
2975 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2979 if (result_len + old_length > 1000) {
2980 hildon_banner_show_information (GTK_WIDGET (window), NULL,
2981 dgettext("hildon-common-strings",
2982 "ckdg_ib_maximum_characters_reached"));
2985 g_string_free (result, TRUE);
2989 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2992 ModestMsgEditWindowPrivate *priv = NULL;
2994 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2995 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2997 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3000 gtk_widget_show_all (priv->find_toolbar);
3001 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3003 gtk_widget_hide_all (priv->find_toolbar);
3004 gtk_widget_grab_focus (priv->msg_body);
3010 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3012 GtkTextIter *match_start,
3013 GtkTextIter *match_end)
3015 GtkTextIter end_iter;
3016 gchar *str_casefold;
3019 gchar *range_casefold;
3022 gboolean result = FALSE;
3029 gtk_text_iter_forward_to_end (&end_iter);
3031 str_casefold = g_utf8_casefold (str, -1);
3032 str_chars_n = strlen (str);
3034 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3035 range_casefold = g_utf8_casefold (range_text, -1);
3036 range_chars_n = strlen (range_casefold);
3038 if (range_chars_n < str_chars_n) {
3039 g_free (str_casefold);
3040 g_free (range_text);
3041 g_free (range_casefold);
3045 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3046 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3047 if (!g_utf8_collate (range_subtext, str_casefold)) {
3048 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3050 gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3051 match_start, match_end, NULL);
3052 g_free (found_text);
3054 g_free (range_subtext);
3058 g_free (str_casefold);
3059 g_free (range_text);
3060 g_free (range_casefold);
3067 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3068 ModestMsgEditWindow *window)
3070 gchar *current_search = NULL;
3071 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3073 GtkTextIter selection_start, selection_end;
3074 GtkTextIter match_start, match_end;
3075 gboolean continue_search = FALSE;
3077 if (message_is_empty (window)) {
3078 g_free (priv->last_search);
3079 priv->last_search = NULL;
3080 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3084 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3085 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3086 g_free (current_search);
3087 g_free (priv->last_search);
3088 priv->last_search = NULL;
3089 /* Information banner about empty search */
3090 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3094 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3095 continue_search = TRUE;
3097 g_free (priv->last_search);
3098 priv->last_search = g_strdup (current_search);
3101 if (continue_search) {
3102 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3103 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3104 &match_start, &match_end);
3106 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3108 GtkTextIter buffer_start;
3109 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3110 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3111 &match_start, &match_end);
3113 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3116 /* Mark as selected the string found in search */
3118 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3119 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3121 g_free (priv->last_search);
3122 priv->last_search = NULL;
3124 g_free (current_search);
3128 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3129 ModestMsgEditWindow *window)
3131 GtkToggleAction *toggle;
3132 ModestWindowPrivate *parent_priv;
3133 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3135 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3136 gtk_toggle_action_set_active (toggle, FALSE);
3140 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3142 ModestMsgEditWindowPrivate *priv;
3144 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3149 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3152 ModestMsgEditWindowPrivate *priv;
3154 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3160 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3163 ModestMsgEditWindowPrivate *priv;
3164 TnyHeader *header = NULL;
3166 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3167 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3169 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3170 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3172 if (priv->draft_msg != NULL) {
3173 g_object_unref (priv->draft_msg);
3176 if (draft != NULL) {
3177 g_object_ref (draft);
3178 header = tny_msg_get_header (draft);
3179 if (priv->msg_uid) {
3180 g_free (priv->msg_uid);
3181 priv->msg_uid = NULL;
3183 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3184 if (GTK_WIDGET_REALIZED (window))
3185 modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3188 priv->draft_msg = draft;
3192 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3193 GtkTextIter *start, GtkTextIter *end,
3196 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3197 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3200 if (tag == NULL+13) return;
3201 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3202 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3203 replace_with_images (window, priv->images);
3208 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3211 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3213 g_return_if_fail (TNY_IS_MIME_PART (part));
3214 tny_list_prepend (priv->attachments, (GObject *) part);
3215 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3216 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3217 gtk_widget_show_all (priv->attachments_caption);
3218 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3222 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3224 ModestMsgEditWindowPrivate *priv;
3226 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3227 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3229 return priv->msg_uid;
3233 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3234 ModestMsgEditWindowWidgetType widget_type)
3236 ModestMsgEditWindowPrivate *priv;
3238 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3239 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3241 switch (widget_type) {
3242 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3243 return priv->msg_body;
3245 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3246 return priv->to_field;
3248 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3249 return priv->cc_field;
3251 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3252 return priv->bcc_field;
3254 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3255 return priv->subject_field;
3257 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3258 return priv->attachments_view;
3266 remove_tags (WPTextBuffer *buffer)
3268 GtkTextIter start, end;
3270 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3271 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3273 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3277 on_account_removed (TnyAccountStore *account_store,
3278 TnyAccount *account,
3281 /* Do nothing if it's a store account, because we use the
3282 transport to send the messages */
3283 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3284 const gchar *parent_acc = NULL;
3285 const gchar *our_acc = NULL;
3287 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3288 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3289 /* Close this window if I'm showing a message of the removed account */
3290 if (strcmp (parent_acc, our_acc) == 0)
3291 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3296 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3298 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3300 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3306 set_zoom_do_nothing (ModestWindow *window,
3312 get_zoom_do_nothing (ModestWindow *window)