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>
38 #include <tny-camel-mem-stream.h>
39 #include <modest-account-protocol.h>
43 #include <modest-account-mgr.h>
44 #include <modest-account-mgr-helpers.h>
46 #include <widgets/modest-msg-edit-window.h>
47 #include <modest-selector-picker.h>
48 #include <widgets/modest-recpt-editor.h>
49 #include <widgets/modest-attachments-view.h>
51 #include <modest-runtime.h>
53 #include "modest-platform.h"
54 #include "modest-icon-names.h"
55 #include "modest-widget-memory.h"
56 #include "modest-window-priv.h"
57 #include "modest-mail-operation.h"
58 #include "modest-tny-platform-factory.h"
59 #include "modest-tny-msg.h"
60 #include "modest-tny-folder.h"
61 #include "modest-tny-account.h"
62 #include "modest-address-book.h"
63 #include "modest-text-utils.h"
64 #include <tny-simple-list.h>
65 #include <modest-wp-text-view.h>
66 #include <wptextbuffer.h>
67 #include <hildon/hildon-pannable-area.h>
68 #include <hildon/hildon-touch-selector.h>
69 #include <hildon/hildon-picker-dialog.h>
70 #include "modest-msg-edit-window-ui-dimming.h"
72 #include "modest-hildon-includes.h"
73 #include "widgets/modest-msg-edit-window-ui.h"
74 #include <libgnomevfs/gnome-vfs-mime.h>
75 #include <modest-utils.h>
76 #include "modest-maemo-utils.h"
77 #include <modest-ui-constants.h>
79 #ifdef MODEST_USE_CALENDAR_WIDGETS
80 #include <calendar-ui-widgets.h>
83 #define DEFAULT_FONT_SIZE 3
84 #define DEFAULT_FONT 2
85 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
86 #define DEFAULT_MAIN_VBOX_SPACING 0
87 #define SUBJECT_MAX_LENGTH 1000
88 #define IMAGE_MAX_WIDTH 560
89 #define DEFAULT_FONT_SCALE 1.5
90 #define ATTACHMENT_BUTTON_WIDTH 118
91 #define MAX_FROM_VALUE 36
92 #define MAX_BODY_LENGTH 128*1024
93 #define MAX_BODY_LINES 2048
95 static gboolean is_wp_text_buffer_started = FALSE;
97 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
98 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
99 static void modest_msg_edit_window_finalize (GObject *obj);
101 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
102 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
103 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
105 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
106 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
107 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
108 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
109 GtkTextIter *start, GtkTextIter *end,
111 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
112 static void body_insert_text (GtkTextBuffer *buffer,
113 GtkTextIter *location,
116 ModestMsgEditWindow *window);
117 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
118 static void subject_field_insert_text (GtkEditable *editable,
120 gint new_text_length,
122 ModestMsgEditWindow *window);
123 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
125 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
127 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
128 ModestRecptEditor *editor);
129 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
130 ModestMsgEditWindow *window);
132 /* ModestWindow methods implementation */
133 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
134 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
135 gboolean show_toolbar);
136 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
138 ModestMsgEditWindow *window);
139 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
140 static void subject_field_move_cursor (GtkEntry *entry,
141 GtkMovementStep step,
145 static void update_window_title (ModestMsgEditWindow *window);
148 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
149 ModestMsgEditWindow *window);
150 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
151 ModestMsgEditWindow *window);
152 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
154 GtkTextIter *match_start,
155 GtkTextIter *match_end);
157 static void remove_tags (WPTextBuffer *buffer);
159 static void on_account_removed (TnyAccountStore *account_store,
163 static void init_window (ModestMsgEditWindow *obj);
165 gboolean scroll_drag_timeout (gpointer userdata);
166 static void correct_scroll (ModestMsgEditWindow *w);
167 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
168 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
169 ModestMsgEditWindow *userdata);
170 static void text_buffer_mark_set (GtkTextBuffer *buffer,
173 ModestMsgEditWindow *userdata);
174 static void on_message_settings (GtkAction *action,
175 ModestMsgEditWindow *window);
176 static void setup_menu (ModestMsgEditWindow *self);
178 static void from_field_changed (HildonPickerButton *button,
179 ModestMsgEditWindow *self);
180 static void font_size_clicked (GtkToolButton *button,
181 ModestMsgEditWindow *window);
182 static void font_face_clicked (GtkToolButton *button,
183 ModestMsgEditWindow *window);
184 static void update_signature (ModestMsgEditWindow *self,
185 const gchar *old_account,
186 const gchar *new_account);
187 static void update_branding (ModestMsgEditWindow *self,
188 const gchar *new_account);
189 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
190 const gchar *label, GtkWidget *control);
191 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
192 static void DEBUG_BUFFER (WPTextBuffer *buffer)
196 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
198 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
199 while (!gtk_text_iter_is_end (&iter)) {
200 GString *output = g_string_new ("");
201 GSList *toggled_tags;
204 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
205 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
206 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
207 GtkTextTag *tag = (GtkTextTag *) node->data;
209 g_object_get (G_OBJECT (tag), "name", &name, NULL);
210 output = g_string_append (output, name);
211 g_string_append (output, " ");
213 output = g_string_append (output, "] OPENED [ ");
214 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
215 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
216 GtkTextTag *tag = (GtkTextTag *) node->data;
218 g_object_get (G_OBJECT (tag), "name", &name, NULL);
219 output = g_string_append (output, name);
220 g_string_append (output, " ");
222 output = g_string_append (output, "]\n");
223 g_debug ("%s", output->str);
224 g_string_free (output, TRUE);
225 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
227 g_debug ("END BUFFER");
231 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
232 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
236 /* static gboolean */
237 /* on_key_pressed (GtkWidget *self, */
238 /* GdkEventKey *event, */
239 /* gpointer user_data); */
241 /* list my signals */
248 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
249 struct _ModestMsgEditWindowPrivate {
251 GtkWidget *header_box;
253 ModestPairList *from_field_protos;
254 GtkWidget *from_field;
255 gchar *last_from_account;
256 gchar *original_account_name;
261 gchar *original_mailbox;
265 GtkWidget *bcc_field;
266 GtkWidget *subject_field;
267 GtkWidget *attachments_view;
268 GtkWidget *priority_icon;
269 GtkWidget *subject_box;
270 GtkWidget *send_button;
272 GtkWidget *cc_caption;
273 GtkWidget *bcc_caption;
274 gboolean update_caption_visibility;
275 GtkWidget *attachments_caption;
277 GtkTextBuffer *text_buffer;
279 GtkWidget *font_size_toolitem;
280 GtkWidget *font_face_toolitem;
281 GtkWidget *font_color_button;
282 GtkWidget *font_color_toolitem;
283 GSList *font_items_group;
284 GtkTreeModel *faces_model;
285 gint current_face_index;
286 GtkWidget *font_tool_button_label;
287 GtkTreeModel *sizes_model;
288 gint current_size_index;
289 GtkWidget *size_tool_button_label;
291 GtkWidget *find_toolbar;
294 GtkWidget *font_dialog;
297 guint correct_scroll_idle;
298 guint scroll_drag_timeout_id;
302 TnyList *attachments;
307 TnyHeaderFlags priority_flags;
309 gboolean can_undo, can_redo;
310 gulong clipboard_change_handler_id;
311 gulong default_clipboard_change_handler_id;
312 gulong account_removed_handler_id;
313 guint clipboard_owner_idle;
314 gchar *clipboard_text;
323 GtkWidget *cc_button;
324 GtkWidget *bcc_button;
326 GtkWidget *max_chars_banner;
328 GtkWidget *brand_icon;
329 GtkWidget *brand_label;
330 GtkWidget *brand_container;
333 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
334 MODEST_TYPE_MSG_EDIT_WINDOW, \
335 ModestMsgEditWindowPrivate))
337 static GtkWindowClass *parent_class = NULL;
339 /* uncomment the following if you have defined any signals */
340 /* static guint signals[LAST_SIGNAL] = {0}; */
343 modest_msg_edit_window_get_type (void)
345 static GType my_type = 0;
347 static const GTypeInfo my_info = {
348 sizeof(ModestMsgEditWindowClass),
349 NULL, /* base init */
350 NULL, /* base finalize */
351 (GClassInitFunc) modest_msg_edit_window_class_init,
352 NULL, /* class finalize */
353 NULL, /* class data */
354 sizeof(ModestMsgEditWindow),
356 (GInstanceInitFunc) modest_msg_edit_window_init,
359 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
360 "ModestMsgEditWindow",
368 save_state (ModestWindow *self)
370 modest_widget_memory_save (modest_runtime_get_conf(),
371 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
376 restore_settings (ModestMsgEditWindow *self)
378 ModestConf *conf = NULL;
380 conf = modest_runtime_get_conf ();
382 /* Dim at start clipboard actions */
383 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
388 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
390 GObjectClass *gobject_class;
391 ModestWindowClass *modest_window_class;
392 gobject_class = (GObjectClass*) klass;
393 modest_window_class = (ModestWindowClass*) klass;
395 parent_class = g_type_class_peek_parent (klass);
396 gobject_class->finalize = modest_msg_edit_window_finalize;
398 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
399 modest_window_class->save_state_func = save_state;
400 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
402 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
406 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
408 ModestMsgEditWindowPrivate *priv;
409 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
411 priv->msg_body = NULL;
412 priv->from_field = NULL;
413 priv->to_field = NULL;
414 priv->cc_field = NULL;
415 priv->bcc_field = NULL;
416 priv->subject_field = NULL;
417 priv->attachments = TNY_LIST (tny_simple_list_new ());
418 priv->images = TNY_LIST (tny_simple_list_new ());
419 priv->images_size = 0;
420 priv->images_count = 0;
423 priv->cc_caption = NULL;
424 priv->bcc_caption = NULL;
425 priv->update_caption_visibility = FALSE;
427 priv->priority_flags = 0;
429 priv->find_toolbar = NULL;
430 priv->last_search = NULL;
432 priv->draft_msg = NULL;
433 priv->outbox_msg = NULL;
434 priv->msg_uid = NULL;
436 priv->can_undo = FALSE;
437 priv->can_redo = FALSE;
438 priv->clipboard_change_handler_id = 0;
439 priv->default_clipboard_change_handler_id = 0;
440 priv->account_removed_handler_id = 0;
441 priv->clipboard_owner_idle = 0;
442 priv->clipboard_text = NULL;
445 priv->scroll_drag_timeout_id = 0;
446 priv->correct_scroll_idle = 0;
447 priv->last_upper = 0.0;
449 priv->font_dialog = NULL;
450 priv->app_menu = NULL;
452 priv->references = NULL;
453 priv->in_reply_to = NULL;
454 priv->max_chars_banner = NULL;
456 if (!is_wp_text_buffer_started) {
457 is_wp_text_buffer_started = TRUE;
458 wp_text_buffer_library_init ();
463 hildon_program_add_window (hildon_program_get_instance(),
468 multimailbox_get_default_mailbox (const gchar *account_name)
470 gchar *transport_account;
471 gchar *result = NULL;
473 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
475 TNY_ACCOUNT_TYPE_TRANSPORT);
476 if (transport_account) {
478 ModestProtocolRegistry *registry;
480 registry = modest_runtime_get_protocol_registry ();
482 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
483 MODEST_ACCOUNT_PROTO, TRUE);
485 ModestProtocol *protocol =
486 modest_protocol_registry_get_protocol_by_name (registry,
487 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
489 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
490 ModestPairList *pair_list;
492 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
495 ModestPair *pair = (ModestPair *) pair_list->data;
496 result = g_strdup ((const gchar *) pair->first);
497 modest_pair_list_free (pair_list);
508 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
510 static ModestPairList*
511 get_transports (void)
513 GSList *transports = NULL;
515 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
516 GSList *accounts = modest_account_mgr_account_names (account_mgr,
517 TRUE /* only enabled accounts. */);
519 GSList *cursor = accounts;
521 gchar *account_name = cursor->data;
524 gchar *transport_account;
525 gboolean multi_mailbox = FALSE;
526 ModestProtocol *protocol = NULL;
528 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
530 transport_account = modest_account_mgr_get_server_account_name
531 (modest_runtime_get_account_mgr (),
533 TNY_ACCOUNT_TYPE_TRANSPORT);
534 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
535 ModestPairList *pair_list;
536 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
539 transports = g_slist_concat (transports, pair_list);
540 multi_mailbox = TRUE;
545 if (!multi_mailbox) {
546 gchar *from_string = NULL;
548 from_string = modest_account_mgr_get_from_string (account_mgr,
550 if (from_string && account_name) {
551 gchar *name = account_name;
552 ModestPair *pair = modest_pair_new ((gpointer) name,
553 (gpointer) from_string , TRUE);
554 transports = g_slist_prepend (transports, pair);
559 cursor = cursor->next;
561 g_slist_free (accounts); /* only free the accounts, not the elements,
562 * because they are used in the pairlist */
566 static void window_focus (GtkWindow *window,
570 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
574 scroll_drag_timeout (gpointer userdata)
576 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
577 ModestMsgEditWindowPrivate *priv;
579 /* It could happen that the window was already closed */
580 if (!GTK_WIDGET_VISIBLE (win))
583 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
585 correct_scroll_without_drag_check (win, TRUE);
587 priv->scroll_drag_timeout_id = 0;
593 correct_scroll_without_drag_check_idle (gpointer userdata)
595 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
596 ModestMsgEditWindowPrivate *priv;
598 GdkRectangle rectangle;
599 gint offset_min, offset_max;
603 /* It could happen that the window was already closed */
604 if (!GTK_WIDGET_VISIBLE (w))
607 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
609 insert = gtk_text_buffer_get_insert (priv->text_buffer);
610 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
612 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
613 offset_min = priv->msg_body->allocation.y + rectangle.y;
614 offset_max = offset_min + rectangle.height;
616 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
617 offset_min = MAX (offset_min - 48, 0);
618 offset_max = MIN (offset_max + 48, vadj->upper);
620 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
622 priv->correct_scroll_idle = 0;
627 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
629 ModestMsgEditWindowPrivate *priv;
631 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
633 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
636 if (priv->correct_scroll_idle > 0) {
640 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
641 (GSourceFunc) correct_scroll_without_drag_check_idle,
647 correct_scroll (ModestMsgEditWindow *w)
649 ModestMsgEditWindowPrivate *priv;
651 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
652 if (gtk_grab_get_current () == priv->msg_body) {
653 if (priv->scroll_drag_timeout_id == 0) {
654 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
656 (GSourceFunc) scroll_drag_timeout,
663 correct_scroll_without_drag_check (w, TRUE);
667 text_buffer_end_user_action (GtkTextBuffer *buffer,
668 ModestMsgEditWindow *userdata)
671 correct_scroll (userdata);
675 text_buffer_mark_set (GtkTextBuffer *buffer,
678 ModestMsgEditWindow *userdata)
680 gtk_text_buffer_begin_user_action (buffer);
681 gtk_text_buffer_end_user_action (buffer);
685 cut_clipboard_check (GtkTextView *text_view,
688 GtkTextBuffer *buffer;
690 buffer = gtk_text_view_get_buffer (text_view);
691 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
692 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
697 copy_clipboard_check (GtkTextView *text_view,
700 GtkTextBuffer *buffer;
702 buffer = gtk_text_view_get_buffer (text_view);
703 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
704 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
709 attachment_deleted (ModestAttachmentsView *attachments_view,
712 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
717 body_size_request (GtkWidget *body,
721 /* Make sure the body always get at least 70 pixels */
722 if (req->height < 70)
727 connect_signals (ModestMsgEditWindow *obj)
729 ModestMsgEditWindowPrivate *priv;
731 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
733 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
734 G_CALLBACK (text_buffer_refresh_attributes), obj);
735 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
736 G_CALLBACK (text_buffer_can_undo), obj);
737 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
738 G_CALLBACK (text_buffer_can_redo), obj);
739 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
740 G_CALLBACK (body_changed), obj);
741 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
742 G_CALLBACK (body_insert_text), obj);
743 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
744 G_CALLBACK (body_changed), obj);
745 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
746 G_CALLBACK (text_buffer_end_user_action), obj);
747 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
748 G_CALLBACK (text_buffer_mark_set), obj);
749 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
750 G_CALLBACK (text_buffer_apply_tag), obj);
751 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
752 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
753 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
754 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
755 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
756 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
758 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
759 G_CALLBACK (modest_ui_actions_on_send), obj);
761 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
762 G_CALLBACK (from_field_changed), obj);
764 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
765 G_CALLBACK (msg_body_focus), obj);
766 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
767 G_CALLBACK (msg_body_focus), obj);
768 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
769 G_CALLBACK (body_size_request), obj);
770 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
771 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
772 "changed", G_CALLBACK (recpt_field_changed), obj);
773 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
774 "changed", G_CALLBACK (recpt_field_changed), obj);
775 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
776 "changed", G_CALLBACK (recpt_field_changed), obj);
777 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
778 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
779 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
781 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
782 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
784 priv->clipboard_change_handler_id =
785 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
786 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
787 priv->default_clipboard_change_handler_id =
788 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
789 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
791 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
792 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
793 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
797 init_wp_text_view_style ()
799 static gboolean initialized = FALSE;
802 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
808 init_window (ModestMsgEditWindow *obj)
810 GtkWidget *to_caption, *subject_caption;
811 GtkWidget *main_vbox;
812 ModestMsgEditWindowPrivate *priv;
813 GtkActionGroup *action_group;
814 ModestWindowPrivate *parent_priv;
815 GdkPixbuf *window_icon = NULL;
816 GError *error = NULL;
818 GtkSizeGroup *title_size_group;
819 GtkSizeGroup *value_size_group;
820 GtkWidget *window_box;
821 GtkWidget *window_align;
822 #if (GTK_MINOR_VERSION >= 10)
823 GdkAtom deserialize_type;
825 GtkWidget *from_send_hbox;
826 GtkWidget *send_icon;
827 GtkWidget *attachments_label;
828 GtkWidget *branding_box;
830 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
831 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
833 parent_priv->ui_manager = gtk_ui_manager_new();
834 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
835 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
837 /* Add common actions */
838 gtk_action_group_add_actions (action_group,
839 modest_msg_edit_action_entries,
840 G_N_ELEMENTS (modest_msg_edit_action_entries),
842 gtk_action_group_add_actions (action_group,
843 hildon2_msg_edit_action_entries,
844 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
846 gtk_action_group_add_toggle_actions (action_group,
847 modest_msg_edit_toggle_action_entries,
848 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
850 gtk_action_group_add_radio_actions (action_group,
851 modest_msg_edit_alignment_radio_action_entries,
852 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
854 G_CALLBACK (modest_ui_actions_on_change_justify),
856 gtk_action_group_add_radio_actions (action_group,
857 modest_msg_edit_priority_action_entries,
858 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
860 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
862 gtk_action_group_add_radio_actions (action_group,
863 modest_msg_edit_file_format_action_entries,
864 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
865 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
866 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
868 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
869 g_object_unref (action_group);
871 /* Load the UI definition */
872 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
875 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
876 g_clear_error (&error);
879 /* Add accelerators */
880 gtk_window_add_accel_group (GTK_WINDOW (obj),
881 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
883 parent_priv->menubar = NULL;
885 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
886 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
888 /* Note: This ModestPairList* must exist for as long as the picker
889 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
890 * so it can't know how to manage its memory. */
891 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
892 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
894 modest_selector_picker_set_value_max_chars (MODEST_SELECTOR_PICKER (priv->from_field), MAX_FROM_VALUE);
895 modest_maemo_utils_set_hbutton_layout (title_size_group, NULL,
896 _("mail_va_from"), priv->from_field);
897 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
898 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
899 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
901 priv->to_field = modest_recpt_editor_new ();
902 priv->cc_field = modest_recpt_editor_new ();
903 priv->bcc_field = modest_recpt_editor_new ();
904 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
905 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
906 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
907 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
908 priv->priority_icon = gtk_image_new ();
909 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
910 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
911 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
912 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
913 hildon_entry_set_placeholder ((HildonEntry *) priv->subject_field, _("mail_va_no_subject"));
914 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
915 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
916 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
917 priv->attachments_view = modest_attachments_view_new (NULL);
918 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
919 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
921 priv->header_box = gtk_vbox_new (FALSE, 0);
923 to_caption = _create_addressbook_box
924 (title_size_group, value_size_group,
925 _("mail_va_to"), priv->to_field);
926 priv->cc_caption = _create_addressbook_box
927 (title_size_group, value_size_group,
928 _("mail_va_cc"), priv->cc_field);
929 priv->bcc_caption = _create_addressbook_box
930 (title_size_group, value_size_group,
931 _("mail_va_hotfix1"), priv->bcc_field);
932 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
933 _("mail_va_subject"), FALSE, priv->subject_box);
934 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (NULL, NULL,
935 _("mail_va_attachment"),
937 priv->attachments_view,
938 HILDON_SIZE_AUTO_WIDTH |
939 HILDON_SIZE_AUTO_HEIGHT);
940 attachments_label = modest_maemo_utils_captioned_get_label_widget (priv->attachments_caption);
941 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
944 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
945 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
946 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
947 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
949 g_object_unref (title_size_group);
950 g_object_unref (value_size_group);
952 priv->brand_icon = gtk_image_new ();
953 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
954 priv->brand_label = gtk_label_new (NULL);
955 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
956 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
957 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
958 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
960 from_send_hbox = gtk_hbox_new (FALSE, 0);
961 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->from_field, TRUE, TRUE, 0);
962 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
964 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
965 gtk_widget_show (branding_box);
966 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
967 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
969 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
970 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
971 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
972 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
975 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
976 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
977 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
978 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
979 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
980 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
981 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
982 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
984 init_wp_text_view_style ();
986 priv->msg_body = modest_wp_text_view_new ();
989 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
990 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
991 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
992 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
993 #if (GTK_MINOR_VERSION >= 10)
994 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
995 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
997 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
998 deserialize_type, TRUE);
1000 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1002 priv->find_toolbar = hildon_find_toolbar_new (NULL);
1003 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
1005 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1007 priv->pannable = hildon_pannable_area_new ();
1009 g_object_set (G_OBJECT (priv->pannable), "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
1011 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1012 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1013 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1015 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1016 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1017 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1019 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
1020 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
1022 window_box = gtk_vbox_new (FALSE, 0);
1023 gtk_container_add (GTK_CONTAINER(obj), window_box);
1025 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
1027 /* Set window icon */
1028 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1030 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1031 g_object_unref (window_icon);
1036 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1038 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1040 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1041 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1042 priv->clipboard_change_handler_id))
1043 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1044 priv->clipboard_change_handler_id);
1045 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1046 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1047 priv->default_clipboard_change_handler_id))
1048 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1049 priv->default_clipboard_change_handler_id);
1051 if (priv->account_removed_handler_id &&
1052 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1053 priv->account_removed_handler_id))
1054 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1055 priv->account_removed_handler_id);
1059 modest_msg_edit_window_finalize (GObject *obj)
1061 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1063 if (priv->max_chars_banner) {
1064 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1065 priv->max_chars_banner = FALSE;
1068 /* Sanity check: shouldn't be needed, the window mgr should
1069 call this function before */
1070 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1072 if (priv->font_dialog != NULL) {
1073 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1076 if (priv->clipboard_text != NULL) {
1077 g_free (priv->clipboard_text);
1078 priv->clipboard_text = NULL;
1081 if (priv->draft_msg != NULL) {
1082 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1083 if (TNY_IS_HEADER (header)) {
1084 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1085 modest_window_mgr_unregister_header (mgr, header);
1087 g_object_unref (priv->draft_msg);
1088 priv->draft_msg = NULL;
1090 if (priv->outbox_msg != NULL) {
1091 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1092 if (TNY_IS_HEADER (header)) {
1093 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1094 modest_window_mgr_unregister_header (mgr, header);
1096 g_object_unref (priv->outbox_msg);
1097 priv->outbox_msg = NULL;
1099 if (priv->correct_scroll_idle > 0) {
1100 g_source_remove (priv->correct_scroll_idle);
1101 priv->correct_scroll_idle = 0;
1103 if (priv->scroll_drag_timeout_id > 0) {
1104 g_source_remove (priv->scroll_drag_timeout_id);
1105 priv->scroll_drag_timeout_id = 0;
1107 if (priv->clipboard_owner_idle > 0) {
1108 g_source_remove (priv->clipboard_owner_idle);
1109 priv->clipboard_owner_idle = 0;
1111 if (priv->original_account_name)
1112 g_free (priv->original_account_name);
1113 if (priv->original_mailbox)
1114 g_free (priv->original_mailbox);
1115 g_free (priv->msg_uid);
1116 g_free (priv->last_search);
1117 g_free (priv->references);
1118 g_free (priv->in_reply_to);
1119 g_object_unref (priv->attachments);
1120 g_object_unref (priv->images);
1122 /* This had to stay alive for as long as the picker that used it: */
1123 modest_pair_list_free (priv->from_field_protos);
1125 G_OBJECT_CLASS(parent_class)->finalize (obj);
1129 pixbuf_size_prepared (GdkPixbufLoader *loader,
1132 ModestMsgEditWindow *self)
1134 gint new_height, new_width;
1137 new_height = height;
1141 if (width > IMAGE_MAX_WIDTH) {
1142 new_height = height * IMAGE_MAX_WIDTH / width;
1143 new_width = IMAGE_MAX_WIDTH;
1146 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1150 pixbuf_from_stream (TnyStream *stream,
1151 const gchar *mime_type,
1152 guint64 *stream_size,
1153 ModestMsgEditWindow *self)
1155 GdkPixbufLoader *loader;
1158 GError *error = NULL;
1162 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1164 if (loader == NULL) {
1169 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1171 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1173 tny_stream_reset (TNY_STREAM (stream));
1174 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1175 unsigned char read_buffer[128];
1177 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1179 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1182 /* Allow some UI responsiveness */
1183 while (gtk_events_pending ())
1184 gtk_main_iteration ();
1186 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1188 gdk_pixbuf_loader_close (loader, &error);
1191 g_error_free (error);
1192 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1194 g_object_ref (pixbuf);
1195 g_object_unref (loader);
1200 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1201 GdkPixbuf *new_pixbuf;
1203 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1204 gdk_pixbuf_get_width (pixbuf);
1205 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1206 g_object_unref (pixbuf);
1207 pixbuf = new_pixbuf;
1211 *stream_size = size;
1217 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1219 ModestMsgEditWindowPrivate *priv;
1222 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1224 g_object_ref (self);
1225 for (iter = tny_list_create_iterator (attachments);
1226 !tny_iterator_is_done (iter);
1227 tny_iterator_next (iter)) {
1228 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1229 const gchar *cid = tny_mime_part_get_content_id (part);
1230 const gchar *mime_type = tny_mime_part_get_content_type (part);
1231 if ((cid != NULL)&&(mime_type != NULL)) {
1232 guint64 stream_size;
1233 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1234 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1237 g_object_unref (stream);
1239 if (pixbuf != NULL) {
1240 priv->images_count ++;
1241 priv->images_size += stream_size;
1242 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1243 g_object_unref (pixbuf);
1246 g_object_unref (part);
1248 g_object_unref (iter);
1249 g_object_unref (self);
1253 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1255 TnyMimePart *parent = NULL;
1256 const gchar *content_type = NULL;
1257 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1259 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1261 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1262 parent = g_object_ref (msg);
1263 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1264 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1267 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1268 iter = tny_list_create_iterator (parts);
1269 while (!tny_iterator_is_done (iter)) {
1271 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1272 content_type = tny_mime_part_get_content_type (part);
1273 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1277 g_object_unref (part);
1279 tny_iterator_next (iter);
1281 g_object_unref (iter);
1282 g_object_unref (parts);
1285 if (parent != NULL) {
1286 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1289 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1290 iter = tny_list_create_iterator (parts);
1291 while (!tny_iterator_is_done (iter)) {
1293 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1294 content_type = tny_mime_part_get_content_type (part);
1295 if (content_type && g_str_has_prefix (content_type, "image/")) {
1296 tny_list_prepend (priv->images, (GObject *) part);
1298 g_object_unref (part);
1299 tny_iterator_next (iter);
1301 g_object_unref (iter);
1302 g_object_unref (parts);
1303 g_object_unref (parent);
1308 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1311 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1313 for (iter = tny_list_create_iterator (attachments) ;
1314 !tny_iterator_is_done (iter);
1315 tny_iterator_next (iter)) {
1316 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1317 const gchar *cid = tny_mime_part_get_content_id (part);
1319 char *invalid = NULL;
1320 gint int_cid = strtol (cid, &invalid, 10);
1321 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1322 priv->next_cid = int_cid + 1;
1325 g_object_unref (part);
1327 g_object_unref (iter);
1331 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1334 gchar *to, *cc, *bcc, *subject;
1336 ModestMsgEditWindowPrivate *priv;
1337 ModestWindowPrivate *parent_priv;
1339 TnyHeaderFlags priority_flags;
1340 TnyFolder *msg_folder;
1341 gboolean is_html = FALSE;
1342 gboolean field_view_set;
1344 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1345 g_return_if_fail (TNY_IS_MSG (msg));
1347 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1348 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1350 header = tny_msg_get_header (msg);
1351 to = tny_header_dup_to (header);
1352 cc = tny_header_dup_cc (header);
1353 bcc = tny_header_dup_bcc (header);
1354 subject = tny_header_dup_subject (header);
1356 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1357 priority_flags = tny_header_get_priority (header);
1360 gchar *quoted_names = modest_text_utils_quote_names (to);
1361 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1362 g_free (quoted_names);
1365 field_view_set = TRUE;
1367 gchar *quoted_names = modest_text_utils_quote_names (cc);
1368 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1369 g_free (quoted_names);
1370 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1371 gtk_widget_show (priv->cc_caption);
1372 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1373 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1374 gtk_widget_hide (priv->cc_caption);
1375 field_view_set = FALSE;
1377 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1379 field_view_set = TRUE;
1381 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1382 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1383 g_free (quoted_names);
1384 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1385 gtk_widget_show (priv->bcc_caption);
1386 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1387 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1388 gtk_widget_hide (priv->bcc_caption);
1389 field_view_set = FALSE;
1391 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1395 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1396 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1399 update_window_title (self);
1401 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1402 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1404 if ((body == NULL)||(body[0] == '\0')) {
1406 body = modest_text_utils_convert_to_html ("");
1409 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1410 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1413 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1416 /* Add attachments to the view */
1417 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1418 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1419 if (tny_list_get_length (priv->attachments) == 0) {
1420 gtk_widget_hide (priv->attachments_caption);
1422 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1423 gtk_widget_show_all (priv->attachments_caption);
1425 get_related_images (self, msg);
1426 update_next_cid (self, priv->attachments);
1427 update_next_cid (self, priv->images);
1428 replace_with_images (self, priv->images);
1430 if (preserve_is_rich && !is_html) {
1431 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1432 /* Get the default format required from configuration */
1433 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1434 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1437 /* Set the default focus depending on having already a To: field or not */
1438 if ((!to)||(*to == '\0')) {
1439 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1441 gtk_widget_grab_focus (priv->msg_body);
1444 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1446 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1447 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1449 modest_msg_edit_window_set_modified (self, FALSE);
1451 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1452 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1453 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1454 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1456 if (priv->msg_uid) {
1457 g_free (priv->msg_uid);
1458 priv->msg_uid = NULL;
1461 /* we should set a reference to the incoming message if it is a draft */
1462 msg_folder = tny_msg_get_folder (msg);
1464 if (modest_tny_folder_is_local_folder (msg_folder)) {
1465 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1466 if (type == TNY_FOLDER_TYPE_INVALID)
1467 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1469 if (type == TNY_FOLDER_TYPE_DRAFTS)
1470 priv->draft_msg = g_object_ref(msg);
1471 if (type == TNY_FOLDER_TYPE_OUTBOX)
1472 priv->outbox_msg = g_object_ref(msg);
1473 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1475 g_object_unref (msg_folder);
1484 #ifdef MODEST_USE_CALENDAR_WIDGETS
1486 color_button_clicked (GtkButton *button)
1488 /* Show ColorPicker dialog */
1489 PipCalendarColor color = pip_color_picker_select_color(PipTextColorRed, PipColorPickerText);
1491 /* Check if some color is selected rather than dialog is dismissed */
1492 if (color != PipCalendarColorInvalid) {
1493 GdkColor *gdk_color = (GdkColor *) pip_calendar_color_get_gdkcolor(color);
1495 hildon_color_button_set_color ((HildonColorButton *) button, gdk_color);
1501 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1503 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1504 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1505 GtkWidget *placeholder;
1506 GtkWidget *tool_item;
1511 GtkWidget *sizes_menu;
1512 GtkWidget *fonts_menu;
1518 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1519 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1520 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1521 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1523 /* Font color placeholder */
1524 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1525 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1528 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1529 priv->font_color_button = hildon_color_button_new ();
1530 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1531 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1532 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1533 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1534 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1535 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1536 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1537 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1539 G_CALLBACK (modest_msg_edit_window_color_button_change),
1542 /* Yes I know this is a horrible hack, but it works for the
1543 moment while we don't create a ModestColorButton */
1544 #ifdef MODEST_USE_CALENDAR_WIDGETS
1545 GtkButtonClass *button_class = GTK_BUTTON_CLASS (HILDON_COLOR_BUTTON_GET_CLASS (priv->font_color_button));
1546 button_class->clicked = color_button_clicked;
1549 /* Font size and face placeholder */
1550 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1551 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1553 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1554 priv->size_tool_button_label = gtk_label_new (NULL);
1555 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1556 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1557 size_text, "</span>", NULL);
1558 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1559 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1561 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1562 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1563 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1564 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1565 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1566 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1567 gtk_widget_set_sensitive (arrow, FALSE);
1568 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1569 sizes_menu = gtk_menu_new ();
1570 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1571 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1574 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1575 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1577 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1581 if (wp_font_size[size_index] == 12)
1582 priv->current_size_index = size_index;
1586 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1587 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1588 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1589 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1590 priv->font_size_toolitem = tool_item;
1593 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1594 priv->font_tool_button_label = gtk_label_new (NULL);
1595 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1596 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1597 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1599 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1600 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1601 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1602 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1603 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1604 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1605 gtk_widget_set_sensitive (arrow, FALSE);
1606 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1607 fonts_menu = gtk_menu_new ();
1608 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1609 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1612 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1614 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1615 0, wp_get_font_name (font_index),
1618 if (font_index == DEFAULT_FONT)
1619 priv->current_face_index = font_index;
1621 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1622 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1623 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1624 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1625 priv->font_face_toolitem = tool_item;
1627 /* Set expand and homogeneous for remaining items */
1628 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1629 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1630 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1631 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1632 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1633 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1635 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1636 will not show the tool items added to the placeholders) */
1637 gtk_widget_show_all (parent_priv->toolbar);
1639 /* Set the no show all *after* showing all items. We do not
1640 want the toolbar to be shown with a show all because it
1641 could go agains the gconf setting regarding showing or not
1642 the toolbar of the editor window */
1643 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1649 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1652 ModestWindowPrivate *parent_priv;
1653 ModestMsgEditWindowPrivate *priv;
1654 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1655 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1656 ModestWindowMgr *mgr = NULL;
1658 g_return_val_if_fail (msg, NULL);
1659 g_return_val_if_fail (account_name, NULL);
1661 mgr = modest_runtime_get_window_mgr ();
1663 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1665 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1666 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1668 /* Menubar. Update the state of some toggles */
1669 priv->from_field_protos = get_transports ();
1670 priv->original_mailbox = NULL;
1671 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1672 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1673 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1674 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1675 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) mailbox);
1676 priv->original_mailbox = g_strdup (mailbox);
1677 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1678 /* We set the first mailbox as the active mailbox */
1679 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1680 if (priv->original_mailbox != NULL)
1681 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1682 (gpointer) priv->original_mailbox);
1684 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1685 (gpointer) account_name);
1687 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1689 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1690 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1691 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1693 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1694 hildon_touch_selector_get_current_text
1695 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1696 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1697 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1700 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1702 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1704 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1705 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1707 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1709 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1710 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1711 /* Add common dimming rules */
1712 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1713 modest_msg_edit_window_toolbar_dimming_entries,
1714 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1715 MODEST_WINDOW (obj));
1716 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1717 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1718 MODEST_WINDOW (obj));
1719 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1720 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1721 MODEST_WINDOW (obj));
1722 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1723 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1724 MODEST_WINDOW (obj));
1725 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1726 G_CALLBACK (modest_ui_dimming_rules_on_send),
1727 MODEST_WINDOW (obj));
1728 /* Insert dimming rules group for this window */
1729 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1730 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1732 /* Setup app menu */
1733 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1735 /* Checks the dimming rules */
1736 g_object_unref (toolbar_rules_group);
1737 g_object_unref (clipboard_rules_group);
1738 gtk_widget_hide (priv->priority_icon);
1739 gtk_widget_queue_resize (priv->subject_box);
1740 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1742 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1744 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1745 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1746 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1747 priv->update_caption_visibility = TRUE;
1749 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1751 /* Track account-removed signal, this window should be closed
1752 in the case we're creating a mail associated to the account
1754 priv->account_removed_handler_id =
1755 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1757 G_CALLBACK(on_account_removed),
1760 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1762 return (ModestWindow*) obj;
1766 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1768 GString **string_buffer = (GString **) user_data;
1770 *string_buffer = g_string_append (*string_buffer, buffer);
1776 * @result: A new string which should be freed with g_free().
1779 get_formatted_data (ModestMsgEditWindow *edit_window)
1781 ModestMsgEditWindowPrivate *priv;
1782 GString *string_buffer = g_string_new ("");
1784 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1786 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1788 modest_text_utils_hyperlinkify (string_buffer);
1790 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1792 return g_string_free (string_buffer, FALSE);
1797 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1800 const gchar *account_name;
1801 ModestMsgEditWindowPrivate *priv;
1802 TnyIterator *att_iter;
1803 const gchar *picker_active_id;
1805 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1807 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1809 picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1810 g_return_val_if_fail (picker_active_id, NULL);
1811 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1813 /* don't free these (except from) */
1814 data = g_slice_new0 (MsgData);
1815 data->from = g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1816 data->account_name = g_strdup (account_name);
1817 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1818 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1819 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1820 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1821 data->references = g_strdup (priv->references);
1822 data->in_reply_to = g_strdup (priv->in_reply_to);
1823 if (priv->draft_msg) {
1824 data->draft_msg = g_object_ref (priv->draft_msg);
1825 } else if (priv->outbox_msg) {
1826 data->draft_msg = g_object_ref (priv->outbox_msg);
1828 data->draft_msg = NULL;
1831 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1833 gtk_text_buffer_get_bounds (buf, &b, &e);
1834 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1836 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1837 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1839 data->html_body = NULL;
1841 /* deep-copy the data */
1842 att_iter = tny_list_create_iterator (priv->attachments);
1843 data->attachments = NULL;
1844 while (!tny_iterator_is_done (att_iter)) {
1845 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1846 if (!(TNY_IS_MIME_PART(part))) {
1847 g_warning ("strange data in attachment list");
1848 g_object_unref (part);
1849 tny_iterator_next (att_iter);
1852 data->attachments = g_list_append (data->attachments,
1854 tny_iterator_next (att_iter);
1856 g_object_unref (att_iter);
1858 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1859 att_iter = tny_list_create_iterator (priv->images);
1860 data->images = NULL;
1861 while (!tny_iterator_is_done (att_iter)) {
1862 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1864 if (!(TNY_IS_MIME_PART(part))) {
1865 g_warning ("strange data in attachment list");
1866 g_object_unref (part);
1867 tny_iterator_next (att_iter);
1870 cid = tny_mime_part_get_content_id (part);
1872 gchar *image_tag_id;
1873 GtkTextTag *image_tag;
1875 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1876 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1877 g_free (image_tag_id);
1879 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1881 ((gtk_text_iter_has_tag (&iter, image_tag))||
1882 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1883 data->images = g_list_append (data->images,
1884 g_object_ref (part));
1886 g_object_unref (part);
1887 tny_iterator_next (att_iter);
1889 g_object_unref (att_iter);
1891 data->priority_flags = priv->priority_flags;
1898 unref_gobject (GObject *obj, gpointer data)
1900 if (!G_IS_OBJECT(obj))
1902 g_object_unref (obj);
1906 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1909 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1917 g_free (data->from);
1918 g_free (data->subject);
1919 g_free (data->plain_body);
1920 g_free (data->html_body);
1921 g_free (data->account_name);
1922 g_free (data->references);
1923 g_free (data->in_reply_to);
1925 if (data->draft_msg != NULL) {
1926 g_object_unref (data->draft_msg);
1927 data->draft_msg = NULL;
1930 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1931 g_list_free (data->attachments);
1932 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1933 g_list_free (data->images);
1935 g_slice_free (MsgData, data);
1939 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1941 guint64 *parts_size)
1943 ModestMsgEditWindowPrivate *priv;
1945 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1947 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1949 /* TODO: add images */
1950 *parts_size += priv->images_size;
1951 *parts_count += priv->images_count;
1956 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1959 ModestMsgEditWindowPrivate *priv = NULL;
1960 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1962 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1964 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1966 return MODEST_MSG_EDIT_FORMAT_HTML;
1968 return MODEST_MSG_EDIT_FORMAT_TEXT;
1972 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1973 ModestMsgEditFormat format)
1975 ModestMsgEditWindowPrivate *priv;
1976 ModestWindowPrivate *parent_priv;
1978 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1979 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1980 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1983 case MODEST_MSG_EDIT_FORMAT_HTML:
1984 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1985 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
1987 case MODEST_MSG_EDIT_FORMAT_TEXT:
1988 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1989 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
1992 g_return_if_reached ();
1996 ModestMsgEditFormatState *
1997 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1999 ModestMsgEditFormatState *format_state = NULL;
2000 ModestMsgEditWindowPrivate *priv;
2001 WPTextBufferFormat *buffer_format;
2003 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2005 buffer_format = g_new0 (WPTextBufferFormat, 1);
2006 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2008 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2010 format_state = g_new0 (ModestMsgEditFormatState, 1);
2011 format_state->bold = buffer_format->bold&0x1;
2012 format_state->italics = buffer_format->italic&0x1;
2013 format_state->bullet = buffer_format->bullet&0x1;
2014 format_state->color = buffer_format->color;
2015 format_state->font_size = buffer_format->font_size;
2016 format_state->font_family = wp_get_font_name (buffer_format->font);
2017 format_state->justification = buffer_format->justification;
2018 g_free (buffer_format);
2020 return format_state;
2025 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2026 const ModestMsgEditFormatState *format_state)
2028 ModestMsgEditWindowPrivate *priv;
2029 WPTextBufferFormat *buffer_format;
2030 WPTextBufferFormat *current_format;
2032 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2033 g_return_if_fail (format_state != NULL);
2035 buffer_format = g_new0 (WPTextBufferFormat, 1);
2036 current_format = g_new0 (WPTextBufferFormat, 1);
2038 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2039 gtk_widget_grab_focus (priv->msg_body);
2040 buffer_format->bold = (format_state->bold != FALSE);
2041 buffer_format->italic = (format_state->italics != FALSE);
2042 buffer_format->color = format_state->color;
2043 buffer_format->font_size = format_state->font_size;
2044 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2045 buffer_format->justification = format_state->justification;
2046 buffer_format->bullet = format_state->bullet;
2048 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2050 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2051 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2052 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2053 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2054 buffer_format->cs.font = (buffer_format->font != current_format->font);
2055 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2056 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2058 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2059 if (buffer_format->cs.bold) {
2060 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2061 GINT_TO_POINTER (buffer_format->bold&0x1));
2063 if (buffer_format->cs.italic) {
2064 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2065 GINT_TO_POINTER (buffer_format->italic&0x1));
2067 if (buffer_format->cs.color) {
2068 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2069 GINT_TO_POINTER (&(buffer_format->color)));
2071 if (buffer_format->cs.font_size) {
2072 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2073 GINT_TO_POINTER (buffer_format->font_size));
2075 if (buffer_format->cs.justification) {
2076 switch (buffer_format->justification) {
2077 case GTK_JUSTIFY_LEFT:
2078 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2079 GINT_TO_POINTER(TRUE));
2081 case GTK_JUSTIFY_CENTER:
2082 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2083 GINT_TO_POINTER(TRUE));
2085 case GTK_JUSTIFY_RIGHT:
2086 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2087 GINT_TO_POINTER(TRUE));
2094 if (buffer_format->cs.font) {
2095 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2096 GINT_TO_POINTER (buffer_format->font));
2098 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2099 if (buffer_format->cs.bullet) {
2100 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2101 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2103 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2105 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2107 g_free (buffer_format);
2108 g_free (current_format);
2110 /* Check dimming rules */
2111 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2112 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2116 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2118 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2120 ModestWindowPrivate *parent_priv;
2121 ModestMsgEditWindowPrivate *priv;
2123 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2124 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2126 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2127 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2128 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2129 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2131 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2132 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2133 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2136 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2138 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2139 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2141 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2142 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2144 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2145 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2148 switch (buffer_format->justification)
2150 case GTK_JUSTIFY_LEFT:
2151 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2153 case GTK_JUSTIFY_CENTER:
2154 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2156 case GTK_JUSTIFY_RIGHT:
2157 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2164 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2166 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2167 G_CALLBACK (modest_msg_edit_window_color_button_change),
2169 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2170 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2171 G_CALLBACK (modest_msg_edit_window_color_button_change),
2174 if (priv->current_size_index != buffer_format->font_size) {
2178 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2179 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2183 priv->current_size_index = buffer_format->font_size;
2185 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2186 markup = g_strconcat ("<span font_family='Sans'>",
2187 size_text, "</span>", NULL);
2189 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2193 gtk_tree_path_free (path);
2196 if (priv->current_face_index != buffer_format->font) {
2200 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2201 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2205 priv->current_face_index = buffer_format->font;
2206 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2207 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2208 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2215 g_free (buffer_format);
2221 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2223 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2224 ModestMsgEditWindowPrivate *priv;
2225 GtkWidget *dialog = NULL;
2227 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2228 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2230 dialog = hildon_color_chooser_new ();
2231 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2232 g_free (buffer_format);
2234 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2236 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2237 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2240 gtk_widget_destroy (dialog);
2245 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2247 ModestMsgEditWindowPrivate *priv;
2248 GtkWidget *dialog = NULL;
2249 GdkColor *old_color = NULL;
2251 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2252 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2254 dialog = hildon_color_chooser_new ();
2255 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2257 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2259 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2260 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2262 gtk_widget_destroy (dialog);
2267 create_stream_for_uri (const gchar* uri)
2272 TnyStream *result = NULL;
2274 GnomeVFSHandle *handle = NULL;
2275 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2276 if (test == GNOME_VFS_OK) {
2277 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2278 /* Streams over OBEX (Bluetooth) are not seekable but
2279 * we expect them to be (we might need to read them
2280 * several times). So if this is a Bluetooth URI just
2281 * read the whole file into memory (this is not a fast
2282 * protocol so we can assume that these files are not
2283 * going to be very big) */
2284 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2285 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2286 TnyStream *memstream = tny_camel_mem_stream_new ();
2287 tny_stream_write_to_stream (vfssstream, memstream);
2288 g_object_unref (vfssstream);
2291 result = vfssstream;
2299 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2302 ModestMsgEditWindowPrivate *priv;
2303 GtkWidget *dialog = NULL;
2305 GSList *uris = NULL;
2306 GSList *uri_node = NULL;
2308 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2310 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2311 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2312 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2314 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2316 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2317 GTK_WINDOW (dialog), GTK_WINDOW (window));
2319 response = gtk_dialog_run (GTK_DIALOG (dialog));
2321 case GTK_RESPONSE_OK:
2323 gchar *current_folder;
2324 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2325 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2326 if (current_folder && current_folder != '\0') {
2328 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2329 current_folder, &err);
2331 g_debug ("Error storing latest used folder: %s", err->message);
2335 g_free (current_folder);
2341 gtk_widget_destroy (dialog);
2343 g_object_ref (window);
2344 /* The operation could take some time so allow the dialog to be closed */
2345 while (gtk_events_pending ())
2346 gtk_main_iteration ();
2348 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2350 GnomeVFSHandle *handle = NULL;
2351 GnomeVFSResult result;
2352 GtkTextIter position;
2353 GtkTextMark *insert_mark;
2355 uri = (const gchar *) uri_node->data;
2356 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2357 if (result == GNOME_VFS_OK) {
2359 GnomeVFSFileInfo *info;
2360 gchar *filename, *basename, *escaped_filename;
2361 TnyMimePart *mime_part;
2363 const gchar *mime_type = NULL;
2364 GnomeVFSURI *vfs_uri;
2365 guint64 stream_size;
2367 gnome_vfs_close (handle);
2368 vfs_uri = gnome_vfs_uri_new (uri);
2370 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2371 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2372 g_free (escaped_filename);
2373 gnome_vfs_uri_unref (vfs_uri);
2374 info = gnome_vfs_file_info_new ();
2376 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2377 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2379 mime_type = gnome_vfs_file_info_get_mime_type (info);
2381 mime_part = tny_platform_factory_new_mime_part
2382 (modest_runtime_get_platform_factory ());
2384 TnyStream *stream = create_stream_for_uri (uri);
2386 if (stream == NULL) {
2388 modest_platform_information_banner (NULL, NULL,
2389 _FM("sfil_ib_opening_not_allowed"));
2391 g_object_unref (mime_part);
2392 gnome_vfs_file_info_unref (info);
2396 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2398 content_id = g_strdup_printf ("%d", priv->next_cid);
2399 tny_mime_part_set_content_id (mime_part, content_id);
2400 g_free (content_id);
2403 basename = g_path_get_basename (filename);
2404 tny_mime_part_set_filename (mime_part, basename);
2407 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2409 if (pixbuf != NULL) {
2410 priv->images_size += stream_size;
2411 priv->images_count ++;
2412 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2413 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2414 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2415 tny_mime_part_get_content_id (mime_part), pixbuf);
2416 g_object_unref (pixbuf);
2418 tny_list_prepend (priv->images, (GObject *) mime_part);
2419 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2421 modest_platform_information_banner (NULL, NULL,
2422 _("mail_ib_file_operation_failed"));
2426 g_object_unref (mime_part);
2427 gnome_vfs_file_info_unref (info);
2431 g_object_unref (window);
2435 on_attach_file_response (GtkDialog *dialog,
2439 GSList *uris = NULL;
2441 GnomeVFSFileSize total_size, allowed_size;
2442 ModestMsgEditWindow *window;
2443 ModestMsgEditWindowPrivate *priv;
2448 case GTK_RESPONSE_OK:
2450 gchar *current_folder;
2452 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2453 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2454 if (current_folder && current_folder != '\0') {
2456 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2457 current_folder, &err);
2459 g_debug ("Error storing latest used folder: %s", err->message);
2463 g_free (current_folder);
2470 window = MODEST_MSG_EDIT_WINDOW (user_data);
2471 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2473 /* allowed size is the maximum size - what's already there */
2474 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2475 &att_num, &att_size);
2476 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2479 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2481 const gchar *uri = (const gchar *) uri_node->data;
2484 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2486 if (total_size > allowed_size) {
2487 g_debug ("%s: total size: %u",
2488 __FUNCTION__, (unsigned int)total_size);
2491 allowed_size -= total_size;
2493 g_slist_foreach (uris, (GFunc) g_free, NULL);
2494 g_slist_free (uris);
2496 gtk_widget_destroy (GTK_WIDGET (dialog));
2500 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2502 GtkWidget *dialog = NULL;
2503 ModestMsgEditWindowPrivate *priv;
2506 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2508 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2510 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2513 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2514 GTK_FILE_CHOOSER_ACTION_OPEN);
2515 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2516 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2517 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2518 if (conf_folder && conf_folder[0] != '\0') {
2519 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2522 /* Set the default folder to documents folder */
2523 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2526 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2527 ".documents", NULL);
2529 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2530 g_free (docs_folder);
2532 g_free (conf_folder);
2533 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2534 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2535 GTK_WINDOW (dialog), GTK_WINDOW (window));
2537 /* Connect to response & show */
2538 g_signal_connect (dialog, "response",
2539 G_CALLBACK (on_attach_file_response), window);
2540 gtk_widget_show (dialog);
2545 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2547 GnomeVFSFileSize allowed_size)
2550 GnomeVFSHandle *handle = NULL;
2551 ModestMsgEditWindowPrivate *priv;
2552 GnomeVFSResult result;
2553 GnomeVFSFileSize size = 0;
2554 g_return_val_if_fail (window, 0);
2555 g_return_val_if_fail (uri, 0);
2557 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2559 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2560 if (result == GNOME_VFS_OK) {
2561 TnyMimePart *mime_part;
2563 const gchar *mime_type = NULL;
2565 gchar *escaped_filename;
2568 GnomeVFSFileInfo *info;
2569 GnomeVFSURI *vfs_uri;
2571 gnome_vfs_close (handle);
2572 vfs_uri = gnome_vfs_uri_new (uri);
2575 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2576 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2577 g_free (escaped_filename);
2578 gnome_vfs_uri_unref (vfs_uri);
2580 info = gnome_vfs_file_info_new ();
2582 if (gnome_vfs_get_file_info (uri,
2584 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2586 mime_type = gnome_vfs_file_info_get_mime_type (info);
2587 mime_part = tny_platform_factory_new_mime_part
2588 (modest_runtime_get_platform_factory ());
2590 /* try to get the attachment's size; this may fail for weird
2591 * file systems, like obex, upnp... */
2592 if (allowed_size != 0 &&
2593 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2595 if (size > allowed_size) {
2596 modest_platform_information_banner (NULL, NULL,
2597 _("mail_ib_error_attachment_size"));
2602 g_debug ("%s: could not get attachment size", __FUNCTION__);
2604 stream = create_stream_for_uri (uri);
2606 if (stream == NULL) {
2608 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2610 g_object_unref (mime_part);
2612 gnome_vfs_file_info_unref (info);
2616 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2617 g_object_unref (stream);
2619 content_id = g_strdup_printf ("%d", priv->next_cid);
2620 tny_mime_part_set_content_id (mime_part, content_id);
2621 g_free (content_id);
2624 basename = g_path_get_basename (filename);
2625 tny_mime_part_set_filename (mime_part, basename);
2628 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2629 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2631 info->size == 0, info->size);
2632 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2633 gtk_widget_show_all (priv->attachments_caption);
2634 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2636 g_object_unref (mime_part);
2637 gnome_vfs_file_info_unref (info);
2644 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2647 ModestMsgEditWindowPrivate *priv;
2650 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2651 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2653 if (att_list == NULL) {
2654 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2655 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2656 g_object_unref (att_list);
2660 g_object_ref (att_list);
2663 if (tny_list_get_length (att_list) == 0) {
2664 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2666 gboolean dialog_response;
2667 gchar *message = NULL;
2668 gchar *filename = NULL;
2670 if (tny_list_get_length (att_list) == 1) {
2672 iter = tny_list_create_iterator (att_list);
2673 part = (TnyMimePart *) tny_iterator_get_current (iter);
2674 g_object_unref (iter);
2675 if (TNY_IS_MSG (part)) {
2676 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2678 filename = tny_header_dup_subject (header);
2679 g_object_unref (header);
2681 if (filename == NULL) {
2682 filename = g_strdup (_("mail_va_no_subject"));
2685 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2687 g_object_unref (part);
2689 filename = g_strdup ("");
2691 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2692 "emev_nc_delete_attachments",
2693 tny_list_get_length (att_list)), filename);
2696 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2700 if (dialog_response != GTK_RESPONSE_OK) {
2701 g_object_unref (att_list);
2705 for (iter = tny_list_create_iterator (att_list);
2706 !tny_iterator_is_done (iter);
2707 tny_iterator_next (iter)) {
2708 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2709 const gchar *att_id;
2710 tny_list_remove (priv->attachments, (GObject *) mime_part);
2712 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2714 if (tny_list_get_length (priv->attachments) == 0)
2715 gtk_widget_hide (priv->attachments_caption);
2716 att_id = tny_mime_part_get_content_id (mime_part);
2718 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2720 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2721 g_object_unref (mime_part);
2723 g_object_unref (iter);
2726 g_object_unref (att_list);
2728 /* if the last attachment has been removed, focus the Subject: field */
2729 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2730 gtk_widget_grab_focus (priv->subject_field);
2734 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2737 ModestMsgEditWindowPrivate *priv;
2740 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2742 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2744 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2746 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2750 font_size_clicked (GtkToolButton *button,
2751 ModestMsgEditWindow *window)
2753 ModestMsgEditWindowPrivate *priv;
2754 GtkWidget *selector, *dialog;
2756 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2758 selector = hildon_touch_selector_new ();
2759 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2760 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2762 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2763 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2764 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2766 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2770 WPTextBufferFormat format;
2772 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2774 memset (&format, 0, sizeof (format));
2775 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2777 format.cs.font_size = TRUE;
2778 format.cs.text_position = TRUE;
2779 format.cs.font = TRUE;
2780 format.font_size = new_index;
2781 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2783 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2784 GINT_TO_POINTER (new_index)))
2785 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2787 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2788 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2789 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2790 size_text, "</span>", NULL);
2792 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2796 gtk_widget_destroy (dialog);
2798 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2803 font_face_clicked (GtkToolButton *button,
2804 ModestMsgEditWindow *window)
2806 ModestMsgEditWindowPrivate *priv;
2807 GtkWidget *selector, *dialog;
2808 GtkCellRenderer *renderer;
2810 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2812 selector = hildon_touch_selector_new ();
2813 renderer = gtk_cell_renderer_text_new ();
2814 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2815 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2816 renderer, "family", 0, "text", 0, NULL);
2817 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2819 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2820 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2821 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2823 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2824 gint new_font_index;
2828 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2829 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2830 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2834 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2836 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2837 GINT_TO_POINTER(new_font_index)))
2838 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2840 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2841 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2843 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2847 gtk_tree_path_free (path);
2850 gtk_widget_destroy (dialog);
2852 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2857 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2860 ModestMsgEditWindowPrivate *priv = NULL;
2861 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2863 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2864 if (!priv->update_caption_visibility)
2867 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2869 gtk_widget_show (priv->cc_caption);
2871 gtk_widget_hide (priv->cc_caption);
2873 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2877 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2880 ModestMsgEditWindowPrivate *priv = NULL;
2881 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2883 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2884 if (!priv->update_caption_visibility)
2887 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2889 gtk_widget_show (priv->bcc_caption);
2891 gtk_widget_hide (priv->bcc_caption);
2893 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2897 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2898 ModestRecptEditor *editor)
2900 ModestMsgEditWindowPrivate *priv;
2902 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2903 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2905 /* we check for low-mem; in that case, show a warning, and don't allow
2906 * for the addressbook
2908 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2911 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2913 if (editor == NULL) {
2914 GtkWidget *view_focus, *parent;
2915 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2917 /* This code should be kept in sync with ModestRecptEditor. The
2918 textview inside the recpt editor is the one that really gets the
2919 focus. As it's inside a scrolled window, and this one inside the
2920 hbox recpt editor inherits from, we'll need to go up in the
2921 hierarchy to know if the text view is part of the recpt editor
2922 or if it's a different text entry */
2923 parent = gtk_widget_get_parent (view_focus);
2924 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2925 editor = MODEST_RECPT_EDITOR (parent);
2928 editor = MODEST_RECPT_EDITOR (priv->to_field);
2931 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2935 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2937 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2939 modest_msg_edit_window_open_addressbook (window, NULL);
2943 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2944 gboolean show_toolbar)
2946 ModestWindowPrivate *parent_priv;
2947 ModestMsgEditWindowPrivate *priv;
2949 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2950 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2951 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2953 /* We can not just use the code of
2954 modest_msg_edit_window_setup_toolbar because it has a
2955 mixture of both initialization and creation code. */
2957 gint current_format;
2958 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2959 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2960 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2961 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2963 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2966 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2971 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2972 TnyHeaderFlags priority_flags)
2974 ModestMsgEditWindowPrivate *priv;
2975 ModestWindowPrivate *parent_priv;
2977 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2979 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2980 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2982 if (priv->priority_flags != priority_flags) {
2983 GtkAction *priority_action = NULL;
2985 priv->priority_flags = priority_flags;
2987 switch (priority_flags) {
2988 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2989 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2990 MODEST_HEADER_ICON_HIGH,
2991 HILDON_ICON_SIZE_SMALL);
2992 gtk_widget_show (priv->priority_icon);
2993 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2994 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2996 case TNY_HEADER_FLAG_LOW_PRIORITY:
2997 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2998 MODEST_HEADER_ICON_LOW,
2999 HILDON_ICON_SIZE_SMALL);
3000 gtk_widget_show (priv->priority_icon);
3001 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3002 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3005 gtk_widget_hide (priv->priority_icon);
3006 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3007 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3010 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3011 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3013 gtk_widget_queue_resize (priv->subject_box);
3017 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3020 ModestMsgEditWindowPrivate *priv;
3021 ModestWindowPrivate *parent_priv;
3022 gint current_format;
3024 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3026 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3027 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3029 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3030 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3032 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3034 if (current_format != file_format) {
3035 switch (file_format) {
3036 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3037 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3038 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3039 if (parent_priv->toolbar)
3040 gtk_widget_show (parent_priv->toolbar);
3042 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3046 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3047 response = gtk_dialog_run (GTK_DIALOG (dialog));
3048 gtk_widget_destroy (dialog);
3049 if (response == GTK_RESPONSE_OK) {
3050 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3051 if (parent_priv->toolbar)
3052 gtk_widget_hide (parent_priv->toolbar);
3054 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3055 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3060 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3061 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3062 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3067 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3070 ModestMsgEditWindowPrivate *priv;
3071 WPTextBufferFormat oldfmt, fmt;
3072 gint old_position = 0;
3076 GdkColor *color = NULL;
3077 gboolean bold, bold_set, italic, italic_set;
3078 gboolean underline, underline_set;
3079 gboolean strikethrough, strikethrough_set;
3080 gboolean position_set;
3081 gboolean font_size_set, font_set, color_set;
3084 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3085 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3087 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3088 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3089 GTK_WINDOW(dialog), GTK_WINDOW (window));
3091 /* First we get the currently selected font information */
3092 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3094 switch (oldfmt.text_position) {
3095 case TEXT_POSITION_NORMAL:
3098 case TEXT_POSITION_SUPERSCRIPT:
3106 g_object_set (G_OBJECT (dialog),
3107 "bold", oldfmt.bold != FALSE,
3108 "bold-set", !oldfmt.cs.bold,
3109 "underline", oldfmt.underline != FALSE,
3110 "underline-set", !oldfmt.cs.underline,
3111 "italic", oldfmt.italic != FALSE,
3112 "italic-set", !oldfmt.cs.italic,
3113 "strikethrough", oldfmt.strikethrough != FALSE,
3114 "strikethrough-set", !oldfmt.cs.strikethrough,
3115 "color", &oldfmt.color,
3116 "color-set", !oldfmt.cs.color,
3117 "size", wp_font_size[oldfmt.font_size],
3118 "size-set", !oldfmt.cs.font_size,
3119 "position", old_position,
3120 "position-set", !oldfmt.cs.text_position,
3121 "family", wp_get_font_name (oldfmt.font),
3122 "family-set", !oldfmt.cs.font,
3125 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3126 GTK_WINDOW (dialog), GTK_WINDOW (window));
3127 gtk_widget_show_all (dialog);
3128 priv->font_dialog = dialog;
3129 response = gtk_dialog_run (GTK_DIALOG (dialog));
3130 priv->font_dialog = NULL;
3131 if (response == GTK_RESPONSE_OK) {
3133 g_object_get( dialog,
3135 "bold-set", &bold_set,
3136 "underline", &underline,
3137 "underline-set", &underline_set,
3139 "italic-set", &italic_set,
3140 "strikethrough", &strikethrough,
3141 "strikethrough-set", &strikethrough_set,
3143 "color-set", &color_set,
3145 "size-set", &font_size_set,
3146 "family", &font_name,
3147 "family-set", &font_set,
3148 "position", &position,
3149 "position-set", &position_set,
3154 if (response == GTK_RESPONSE_OK) {
3155 memset(&fmt, 0, sizeof(fmt));
3161 fmt.italic = italic;
3162 fmt.cs.italic = TRUE;
3164 if (underline_set) {
3165 fmt.underline = underline;
3166 fmt.cs.underline = TRUE;
3168 if (strikethrough_set) {
3169 fmt.strikethrough = strikethrough;
3170 fmt.cs.strikethrough = TRUE;
3175 ? TEXT_POSITION_NORMAL
3176 : ( ( position == 1 )
3177 ? TEXT_POSITION_SUPERSCRIPT
3178 : TEXT_POSITION_SUBSCRIPT );
3179 fmt.cs.text_position = TRUE;
3180 fmt.font_size = oldfmt.font_size;
3184 fmt.cs.color = TRUE;
3187 fmt.font = wp_get_font_index(font_name,
3192 if (font_size_set) {
3193 fmt.cs.font_size = TRUE;
3194 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3196 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3197 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3199 gtk_widget_destroy (dialog);
3201 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3205 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3207 ModestMsgEditWindowPrivate *priv;
3208 ModestWindowPrivate *parent_priv;
3209 gboolean was_rich_text, is_rich_text;
3211 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3212 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3213 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3215 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3217 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3219 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3221 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3223 gtk_widget_show (parent_priv->toolbar);
3225 gtk_widget_hide (parent_priv->toolbar);
3228 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3229 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3233 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3235 ModestMsgEditWindowPrivate *priv;
3237 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3238 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3240 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3242 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3243 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3248 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3250 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3252 priv->can_undo = can_undo;
3256 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3258 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3260 priv->can_redo = can_redo;
3264 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3266 ModestMsgEditWindowPrivate *priv;
3267 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3268 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3270 return priv->can_undo;
3274 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3276 ModestMsgEditWindowPrivate *priv;
3277 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3278 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3280 return priv->can_redo;
3285 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3288 GtkTextIter match_start, match_end;
3290 if (image_id == NULL)
3293 gtk_text_buffer_get_start_iter (buffer, &iter);
3295 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3296 GSList *tags = gtk_text_iter_get_tags (&match_start);
3298 for (node = tags; node != NULL; node = g_slist_next (node)) {
3299 GtkTextTag *tag = (GtkTextTag *) node->data;
3300 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3301 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3302 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3304 offset = gtk_text_iter_get_offset (&match_start);
3305 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3306 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3310 gtk_text_iter_forward_char (&iter);
3315 message_is_empty (ModestMsgEditWindow *window)
3317 ModestMsgEditWindowPrivate *priv = NULL;
3319 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3320 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3322 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3323 * so we can ignore markup.
3325 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3328 count = gtk_text_buffer_get_char_count (buf);
3334 msg_body_focus (GtkWidget *focus,
3335 GdkEventFocus *event,
3339 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3340 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3341 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3346 recpt_field_changed (GtkTextBuffer *buffer,
3347 ModestMsgEditWindow *editor)
3349 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3350 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3354 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3356 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3357 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3361 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3364 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3365 GtkTextBuffer *buffer;
3367 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3368 gtk_text_buffer_set_modified (buffer, modified);
3369 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3370 gtk_text_buffer_set_modified (buffer, modified);
3371 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3372 gtk_text_buffer_set_modified (buffer, modified);
3373 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3377 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3379 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3380 const char *account_name;
3381 GtkTextBuffer *buffer;
3383 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3384 if (gtk_text_buffer_get_modified (buffer))
3386 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3387 if (gtk_text_buffer_get_modified (buffer))
3389 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3390 if (gtk_text_buffer_get_modified (buffer))
3392 if (gtk_text_buffer_get_modified (priv->text_buffer))
3395 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3396 if (priv->original_mailbox) {
3397 if (!account_name || strcmp (account_name, priv->original_mailbox))
3399 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3410 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3412 ModestMsgEditWindowPrivate *priv = NULL;
3413 GSList *address_list = NULL;
3415 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3416 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3418 /* check if there's no recipient added */
3419 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3420 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3421 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3422 /* no recipient contents, then select contacts */
3423 modest_msg_edit_window_open_addressbook (window, NULL);
3428 g_object_ref (window);
3429 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3430 (add_to_addressbook) ? &address_list : NULL)) {
3431 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3432 g_object_unref (window);
3435 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3436 (add_to_addressbook) ? &address_list : NULL)) {
3437 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3438 g_object_unref (window);
3441 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3442 (add_to_addressbook) ? &address_list : NULL)) {
3443 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3444 g_object_unref (window);
3448 /* Add contacts to address book */
3449 if (add_to_addressbook && address_list)
3450 modest_address_book_add_address_list (address_list);
3452 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3453 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3454 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3455 g_object_unref (window);
3462 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3464 GSList *recipients = NULL;
3465 ModestMsgEditWindowPrivate *priv;
3466 gchar *joined, *after_remove, *to, *cc, *bcc;
3468 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3470 /* First of all check names */
3471 if (!modest_msg_edit_window_check_names (self, FALSE))
3474 if (!modest_msg_edit_window_has_pending_addresses (self))
3477 /* Don't add the from obviously */
3478 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3479 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3480 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3482 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3487 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3490 recipients = modest_text_utils_split_addresses_list (after_remove);
3491 g_free (after_remove);
3494 /* Offer the user to add recipients to the address book */
3495 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3496 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3501 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3502 ModestMsgEditWindow *window)
3504 modest_msg_edit_window_offer_attach_file (window);
3508 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3510 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3512 return priv->clipboard_text;
3516 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3518 ModestMsgEditWindow *window)
3520 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3521 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3524 /* It could happen that the window was already closed */
3525 if (!GTK_WIDGET_VISIBLE (window))
3528 g_object_ref (window);
3529 text = gtk_clipboard_wait_for_text (selection_clipboard);
3531 if (priv->clipboard_text != NULL) {
3532 g_free (priv->clipboard_text);
3534 priv->clipboard_text = text;
3536 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3538 g_object_unref (window);
3541 static gboolean clipboard_owner_change_idle (gpointer userdata)
3543 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3544 ModestMsgEditWindowPrivate *priv;
3546 gdk_threads_enter ();
3547 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3548 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3550 priv->clipboard_owner_idle = 0;
3551 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3552 gdk_threads_leave ();
3558 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3560 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3561 if (priv->clipboard_owner_idle == 0) {
3562 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3563 clipboard_owner_change_idle,
3564 g_object_ref (window),
3570 subject_field_move_cursor (GtkEntry *entry,
3571 GtkMovementStep step,
3576 /* It could happen that the window was already closed */
3577 if (!GTK_WIDGET_VISIBLE (window))
3580 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3584 update_window_title (ModestMsgEditWindow *window)
3586 ModestMsgEditWindowPrivate *priv = NULL;
3587 const gchar *subject;
3589 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3590 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3591 if (subject == NULL || subject[0] == '\0')
3592 subject = _("mail_va_new_email");
3594 gtk_window_set_title (GTK_WINDOW (window), subject);
3600 body_insert_text (GtkTextBuffer *buffer,
3601 GtkTextIter *location,
3604 ModestMsgEditWindow *window)
3606 GtkTextIter end_iter;
3613 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3615 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3617 offset = gtk_text_iter_get_offset (&end_iter);
3618 line = gtk_text_iter_get_line (&end_iter);
3622 while (text_offset < text + len) {
3623 if (*text_offset == '\n')
3625 if (text_lines + line >= MAX_BODY_LINES) {
3626 len = text_offset - text;
3632 utf8_len = g_utf8_strlen (text, len);
3634 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3635 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3636 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3641 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3643 /* Prevent endless recursion */
3644 result = g_strndup (text, utf8_end - text);
3645 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3646 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3647 (gpointer) result, (gpointer) (utf8_end - text),
3649 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3653 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3654 if (priv->max_chars_banner == NULL) {
3655 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3656 _CS("ckdg_ib_maximum_characters_reached"));
3657 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3663 subject_field_changed (GtkEditable *editable,
3664 ModestMsgEditWindow *window)
3666 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3667 update_window_title (window);
3668 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3669 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3670 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3673 subject_field_insert_text (GtkEditable *editable,
3675 gint new_text_length,
3677 ModestMsgEditWindow *window)
3679 GString *result = g_string_new ("");
3681 gint result_len = 0;
3682 const gchar *entry_text = NULL;
3685 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3686 old_length = g_utf8_strlen (entry_text, -1);
3688 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3689 gunichar c = g_utf8_get_char_validated (current, 8);
3690 /* Invalid unichar, stop */
3696 result = g_string_append_unichar (result, c);
3700 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3701 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3704 /* Prevent endless recursion */
3705 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3706 g_signal_emit_by_name (editable, "insert-text",
3707 (gpointer) result->str, (gpointer) result->len,
3708 (gpointer) position, (gpointer) window);
3709 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3713 if (result_len + old_length > 1000) {
3714 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3715 _CS("ckdg_ib_maximum_characters_reached"));
3717 g_string_free (result, TRUE);
3721 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3724 ModestMsgEditWindowPrivate *priv = NULL;
3726 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3727 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3729 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3732 gtk_widget_show_all (priv->find_toolbar);
3733 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3735 gtk_widget_hide_all (priv->find_toolbar);
3736 gtk_widget_grab_focus (priv->msg_body);
3741 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3743 GtkTextIter *match_start,
3744 GtkTextIter *match_end)
3746 GtkTextIter end_iter;
3747 gchar *str_casefold;
3750 gchar *range_casefold;
3753 gboolean result = FALSE;
3760 gtk_text_iter_forward_to_end (&end_iter);
3762 str_casefold = g_utf8_casefold (str, -1);
3763 str_chars_n = strlen (str);
3765 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3766 range_casefold = g_utf8_casefold (range_text, -1);
3767 range_chars_n = strlen (range_casefold);
3769 if (range_chars_n < str_chars_n) {
3770 g_free (str_casefold);
3771 g_free (range_text);
3772 g_free (range_casefold);
3776 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3777 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3778 if (!g_utf8_collate (range_subtext, str_casefold)) {
3779 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3781 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3782 match_start, match_end, NULL)) {
3783 g_debug ("Matched string with collate, but not matched in model");
3785 g_free (found_text);
3787 g_free (range_subtext);
3791 g_free (str_casefold);
3792 g_free (range_text);
3793 g_free (range_casefold);
3800 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3801 ModestMsgEditWindow *window)
3803 gchar *current_search = NULL;
3804 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3806 GtkTextIter selection_start, selection_end;
3807 GtkTextIter match_start, match_end;
3808 gboolean continue_search = FALSE;
3810 if (message_is_empty (window)) {
3811 g_free (priv->last_search);
3812 priv->last_search = NULL;
3813 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3817 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3818 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3819 g_free (current_search);
3820 g_free (priv->last_search);
3821 priv->last_search = NULL;
3822 /* Information banner about empty search */
3823 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3827 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3828 continue_search = TRUE;
3830 g_free (priv->last_search);
3831 priv->last_search = g_strdup (current_search);
3834 if (continue_search) {
3835 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3836 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3837 &match_start, &match_end);
3839 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3841 GtkTextIter buffer_start;
3842 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3843 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3844 &match_start, &match_end);
3846 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3849 /* Mark as selected the string found in search */
3851 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3852 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3853 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3855 g_free (priv->last_search);
3856 priv->last_search = NULL;
3858 g_free (current_search);
3862 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3864 ModestMsgEditWindowPrivate *priv;
3866 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3871 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3874 ModestMsgEditWindowPrivate *priv;
3876 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3881 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3882 ModestMsgEditWindow *window)
3884 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3888 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3891 ModestMsgEditWindowPrivate *priv;
3892 TnyHeader *header = NULL;
3894 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3895 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3897 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3899 if (priv->draft_msg != NULL) {
3900 g_object_unref (priv->draft_msg);
3903 if (draft != NULL) {
3904 g_object_ref (draft);
3905 header = tny_msg_get_header (draft);
3906 if (priv->msg_uid) {
3907 g_free (priv->msg_uid);
3908 priv->msg_uid = NULL;
3910 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3913 priv->draft_msg = draft;
3917 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3918 GtkTextIter *start, GtkTextIter *end,
3921 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3922 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3925 if (tag == NULL) return;
3926 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3927 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3928 replace_with_images (window, priv->images);
3933 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3936 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3938 g_return_if_fail (TNY_IS_MIME_PART (part));
3939 tny_list_prepend (priv->attachments, (GObject *) part);
3940 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3941 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3942 gtk_widget_show_all (priv->attachments_caption);
3943 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3947 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3949 ModestMsgEditWindowPrivate *priv;
3951 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3952 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3954 return priv->msg_uid;
3958 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3959 ModestMsgEditWindowWidgetType widget_type)
3961 ModestMsgEditWindowPrivate *priv;
3963 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3964 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3966 switch (widget_type) {
3967 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3968 return priv->msg_body;
3970 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3971 return priv->to_field;
3973 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3974 return priv->cc_field;
3976 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3977 return priv->bcc_field;
3979 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3980 return priv->subject_field;
3982 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3983 return priv->attachments_view;
3991 remove_tags (WPTextBuffer *buffer)
3993 GtkTextIter start, end;
3995 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3996 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3998 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4002 on_account_removed (TnyAccountStore *account_store,
4003 TnyAccount *account,
4006 /* Do nothing if it's a store account, because we use the
4007 transport to send the messages */
4008 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4009 const gchar *parent_acc = NULL;
4010 const gchar *our_acc = NULL;
4012 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4013 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4014 /* Close this window if I'm showing a message of the removed account */
4015 if (strcmp (parent_acc, our_acc) == 0)
4016 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4021 update_signature (ModestMsgEditWindow *self,
4022 const gchar *old_account,
4023 const gchar *new_account)
4025 ModestMsgEditWindowPrivate *priv;
4026 gboolean has_old_signature, has_new_signature;
4028 ModestAccountMgr *mgr;
4031 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4033 gtk_text_buffer_begin_user_action (priv->text_buffer);
4035 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4036 mgr = modest_runtime_get_account_mgr ();
4040 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4041 if (has_old_signature) {
4042 GtkTextIter match_start, match_end;
4044 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4045 seems that the search has some problems
4046 with the blank space at the end */
4047 if (gtk_text_iter_forward_search (&iter, "--",
4048 GTK_TEXT_SEARCH_TEXT_ONLY,
4049 &match_start, NULL, NULL)) {
4050 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4051 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4053 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4054 &match_start, &match_end, NULL)) {
4058 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4063 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4064 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4065 if (has_new_signature) {
4067 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4068 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4070 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4071 g_free (full_signature);
4074 gtk_text_buffer_end_user_action (priv->text_buffer);
4077 static void update_branding (ModestMsgEditWindow *self,
4078 const gchar *new_account)
4080 ModestMsgEditWindowPrivate *priv;
4081 ModestAccountMgr *mgr;
4082 const GdkPixbuf *new_icon = NULL;
4083 gchar *new_label = NULL;
4084 gboolean show = FALSE;
4086 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4088 mgr = modest_runtime_get_account_mgr ();
4090 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4092 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4093 gtk_widget_show (priv->brand_icon);
4096 gtk_widget_hide (priv->brand_icon);
4099 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4100 gtk_widget_show (priv->brand_label);
4104 gtk_widget_hide (priv->brand_label);
4108 gtk_widget_show (priv->brand_container);
4110 gtk_widget_hide (priv->brand_container);
4114 from_field_changed (HildonPickerButton *button,
4115 ModestMsgEditWindow *self)
4117 ModestMsgEditWindowPrivate *priv;
4118 gchar *old_account, *new_account;
4120 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4122 old_account = priv->last_from_account;
4123 new_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4126 g_warning ("%s, could not get the new account", __FUNCTION__);
4130 /* If the From is the same do nothing */
4131 if (old_account && new_account && !strcmp (old_account, new_account))
4134 priv->last_from_account = new_account;
4136 update_signature (self, old_account, new_account);
4137 update_branding (self, new_account);
4141 typedef struct _MessageSettingsHelper {
4142 ModestMsgEditWindow *window;
4143 GSList *priority_group;
4144 GSList *format_group;
4145 GtkToggleButton *current_priority;
4146 GtkToggleButton *current_format;
4147 } MessageSettingsHelper;
4150 on_priority_toggle (GtkToggleButton *button,
4151 MessageSettingsHelper *helper)
4154 ModestMsgEditWindowPrivate *priv;
4156 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4157 if (gtk_toggle_button_get_active (button)) {
4159 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4160 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4161 if ((node_button != button) &&
4162 gtk_toggle_button_get_active (node_button)) {
4163 gtk_toggle_button_set_active (node_button, FALSE);
4166 helper->current_priority = button;
4168 gboolean found = FALSE;
4169 /* If no one is active, activate it again */
4170 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4171 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4172 if (gtk_toggle_button_get_active (node_button)) {
4178 gtk_toggle_button_set_active (button, TRUE);
4184 on_format_toggle (GtkToggleButton *button,
4185 MessageSettingsHelper *helper)
4188 ModestMsgEditWindowPrivate *priv;
4190 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4191 if (gtk_toggle_button_get_active (button)) {
4193 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4194 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4195 if ((node_button != button) &&
4196 gtk_toggle_button_get_active (node_button)) {
4197 gtk_toggle_button_set_active (node_button, FALSE);
4200 helper->current_format = button;
4202 gboolean found = FALSE;
4203 /* If no one is active, activate it again */
4204 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4205 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4206 if (gtk_toggle_button_get_active (node_button)) {
4212 gtk_toggle_button_set_active (button, TRUE);
4219 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4224 GtkWidget *priority_hbox;
4225 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4226 GtkWidget *captioned;
4227 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4228 GtkWidget *format_hbox;
4229 GtkWidget *html_toggle, *text_toggle;
4230 ModestMsgEditWindowPrivate *priv;
4231 MessageSettingsHelper helper = {0,};
4233 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4234 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4235 helper.window = window;
4236 helper.priority_group = NULL;
4237 helper.format_group = NULL;
4239 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4240 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4242 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4243 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4244 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4245 vbox = gtk_vbox_new (FALSE, 0);
4246 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4247 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4248 gtk_container_add (GTK_CONTAINER (align), vbox);
4249 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4250 gtk_widget_show (align);
4251 gtk_widget_show (vbox);
4253 /* Priority toggles */
4254 priority_hbox = gtk_hbox_new (TRUE, 0);
4255 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4256 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4257 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4258 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4259 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4260 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4261 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4262 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4263 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4264 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4265 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4266 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4267 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4268 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4269 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4270 gtk_widget_show_all (priority_hbox);
4271 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4272 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4273 gtk_widget_show (captioned);
4274 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4276 /* format toggles */
4277 format_hbox = gtk_hbox_new (TRUE, 0);
4278 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4279 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4280 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4281 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4282 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4283 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4284 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4285 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4286 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4287 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4288 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4289 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4290 gtk_widget_show_all (format_hbox);
4291 gtk_widget_show (format_hbox);
4292 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4295 g_object_unref (title_sizegroup);
4296 g_object_unref (value_sizegroup);
4298 /* Set current values */
4299 switch (priv->priority_flags) {
4300 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4301 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4302 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4304 case TNY_HEADER_FLAG_LOW_PRIORITY:
4305 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4306 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4309 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4310 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4314 switch (modest_msg_edit_window_get_format (window)) {
4315 case MODEST_MSG_EDIT_FORMAT_TEXT:
4316 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4317 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4319 case MODEST_MSG_EDIT_FORMAT_HTML:
4321 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4322 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4326 /* Signal connects */
4327 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4328 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4329 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4330 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4331 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4333 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4334 GTK_WINDOW (dialog), GTK_WINDOW (window));
4336 /* Save settings if the user clicked on done */
4337 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4338 TnyHeaderFlags flags;
4339 ModestMsgEditFormat old_format, new_format;
4341 /* Set priority flags */
4342 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4343 if (priv->priority_flags != flags)
4344 modest_msg_edit_window_set_priority_flags (window, flags);
4346 /* Set edit format */
4347 old_format = modest_msg_edit_window_get_format (window);
4348 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4349 if (old_format != new_format) {
4350 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4351 modest_msg_edit_window_set_file_format (window, file_format);
4355 gtk_widget_destroy (dialog);
4356 g_slist_free (helper.priority_group);
4360 on_message_settings (GtkAction *action,
4361 ModestMsgEditWindow *window)
4363 modest_msg_edit_window_show_msg_settings_dialog (window);
4367 on_cc_button_toggled (HildonCheckButton *button,
4368 ModestMsgEditWindow *window)
4370 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4372 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4373 hildon_check_button_get_active (button));
4377 on_bcc_button_toggled (HildonCheckButton *button,
4378 ModestMsgEditWindow *window)
4380 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4382 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4383 hildon_check_button_get_active (button));
4387 setup_menu (ModestMsgEditWindow *self)
4389 ModestMsgEditWindowPrivate *priv = NULL;
4391 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4393 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4395 /* Settings menu buttons */
4396 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4397 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4399 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4400 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4401 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4402 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4403 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4404 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4406 priv->cc_button = hildon_check_button_new (0);
4407 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4408 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4410 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4412 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4413 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4414 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4415 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4417 priv->bcc_button = hildon_check_button_new (0);
4418 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4419 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4421 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4423 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4424 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4425 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4426 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4428 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4429 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4430 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4431 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4432 APP_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4434 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4435 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4436 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4437 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4438 APP_MENU_CALLBACK (on_message_settings),
4440 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4441 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4446 emit_open_addressbook (GtkButton *button,
4447 ModestRecptEditor *editor)
4449 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4453 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4454 const gchar *label, GtkWidget *control)
4456 GtkWidget *abook_button;
4459 GtkWidget *label_widget;
4461 box = gtk_hbox_new (FALSE, 0);
4463 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4464 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4466 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4467 label_widget = gtk_label_new (label);
4468 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4469 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4471 gtk_container_add (GTK_CONTAINER (align), abook_button);
4472 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4473 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4474 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4475 if (title_size_group)
4476 gtk_size_group_add_widget (title_size_group, label_widget);
4477 if (value_size_group)
4478 gtk_size_group_add_widget (value_size_group, control);
4480 g_signal_connect (G_OBJECT (abook_button), "clicked",
4481 G_CALLBACK (emit_open_addressbook), control);
4487 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4489 ModestMsgEditWindowPrivate *priv = NULL;
4491 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4493 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4494 priv->max_chars_banner = NULL;
4498 has_pending_addresses (ModestRecptEditor *recpt_editor)
4500 const gchar *recipients = NULL;
4501 GSList *start_indexes = NULL, *end_indexes = NULL;
4502 GSList *current_start, *current_end;
4503 GtkTextBuffer *buffer;
4504 gint offset_delta = 0;
4506 gboolean has_recipients_to_add = FALSE;
4508 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4509 last_length = g_utf8_strlen (recipients, -1);
4510 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4515 current_start = start_indexes;
4516 current_end = end_indexes;
4517 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4519 while (current_start && !has_recipients_to_add) {
4521 gchar *start_ptr, *end_ptr;
4522 gint start_pos, end_pos;
4524 start_pos = (*((gint*) current_start->data)) + offset_delta;
4525 end_pos = (*((gint*) current_end->data)) + offset_delta;
4527 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4528 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4530 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4532 if (modest_text_utils_validate_recipient (address, NULL)) {
4533 if (!modest_address_book_has_address (address)) {
4534 has_recipients_to_add = TRUE;
4537 current_start = g_slist_next (current_start);
4538 current_end = g_slist_next (current_end);
4540 return has_recipients_to_add;
4544 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4546 ModestMsgEditWindowPrivate *priv = NULL;
4548 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4550 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4552 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4553 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4554 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))