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 PipCalendarColor color;
1490 /* Show ColorPicker dialog */
1491 color = pip_color_picker_select_color(PipCalendarColorInvalid, PipColorPickerText);
1493 /* Check if some color is selected rather than dialog is dismissed */
1494 if (color != PipCalendarColorInvalid) {
1495 GdkColor *gdk_color = (GdkColor *) pip_calendar_color_get_gdkcolor (color);
1497 hildon_color_button_set_color ((HildonColorButton *) button, gdk_color);
1503 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1505 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1506 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1507 GtkWidget *placeholder;
1508 GtkWidget *tool_item;
1513 GtkWidget *sizes_menu;
1514 GtkWidget *fonts_menu;
1520 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1521 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1522 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1523 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1525 /* Font color placeholder */
1526 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1527 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1530 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1531 priv->font_color_button = hildon_color_button_new ();
1532 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1533 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1534 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1535 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1536 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1537 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1538 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1539 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1541 G_CALLBACK (modest_msg_edit_window_color_button_change),
1544 /* Yes I know this is a horrible hack, but it works for the
1545 moment while we don't create a ModestColorButton */
1546 #ifdef MODEST_USE_CALENDAR_WIDGETS
1547 GtkButtonClass *button_class = GTK_BUTTON_CLASS (HILDON_COLOR_BUTTON_GET_CLASS (priv->font_color_button));
1548 button_class->clicked = color_button_clicked;
1551 /* Font size and face placeholder */
1552 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1553 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1555 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1556 priv->size_tool_button_label = gtk_label_new (NULL);
1557 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1558 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1559 size_text, "</span>", NULL);
1560 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1561 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1563 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1564 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1565 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1566 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1567 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1568 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1569 gtk_widget_set_sensitive (arrow, FALSE);
1570 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1571 sizes_menu = gtk_menu_new ();
1572 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1573 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1576 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1577 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1579 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1583 if (wp_font_size[size_index] == 12)
1584 priv->current_size_index = size_index;
1588 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1589 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1590 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1591 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1592 priv->font_size_toolitem = tool_item;
1595 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1596 priv->font_tool_button_label = gtk_label_new (NULL);
1597 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1598 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1599 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1601 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1602 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1603 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1604 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1605 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1606 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1607 gtk_widget_set_sensitive (arrow, FALSE);
1608 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1609 fonts_menu = gtk_menu_new ();
1610 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1611 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1614 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1616 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1617 0, wp_get_font_name (font_index),
1620 if (font_index == DEFAULT_FONT)
1621 priv->current_face_index = font_index;
1623 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1624 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1625 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1626 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1627 priv->font_face_toolitem = tool_item;
1629 /* Set expand and homogeneous for remaining items */
1630 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1631 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1632 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1633 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1634 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1635 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1637 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1638 will not show the tool items added to the placeholders) */
1639 gtk_widget_show_all (parent_priv->toolbar);
1641 /* Set the no show all *after* showing all items. We do not
1642 want the toolbar to be shown with a show all because it
1643 could go agains the gconf setting regarding showing or not
1644 the toolbar of the editor window */
1645 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1651 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1654 ModestWindowPrivate *parent_priv;
1655 ModestMsgEditWindowPrivate *priv;
1656 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1657 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1658 ModestWindowMgr *mgr = NULL;
1660 g_return_val_if_fail (msg, NULL);
1661 g_return_val_if_fail (account_name, NULL);
1663 mgr = modest_runtime_get_window_mgr ();
1665 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1667 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1668 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1670 /* Menubar. Update the state of some toggles */
1671 priv->from_field_protos = get_transports ();
1672 priv->original_mailbox = NULL;
1673 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1674 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1675 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1676 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1677 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) mailbox);
1678 priv->original_mailbox = g_strdup (mailbox);
1679 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1680 /* We set the first mailbox as the active mailbox */
1681 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1682 if (priv->original_mailbox != NULL)
1683 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1684 (gpointer) priv->original_mailbox);
1686 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1687 (gpointer) account_name);
1689 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1691 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1692 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1693 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1695 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1696 hildon_touch_selector_get_current_text
1697 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1698 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1699 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1702 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1704 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1706 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1707 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1709 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1711 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1712 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1713 /* Add common dimming rules */
1714 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1715 modest_msg_edit_window_toolbar_dimming_entries,
1716 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1717 MODEST_WINDOW (obj));
1718 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1719 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1720 MODEST_WINDOW (obj));
1721 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1722 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1723 MODEST_WINDOW (obj));
1724 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1725 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1726 MODEST_WINDOW (obj));
1727 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1728 G_CALLBACK (modest_ui_dimming_rules_on_send),
1729 MODEST_WINDOW (obj));
1730 /* Insert dimming rules group for this window */
1731 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1732 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1734 /* Setup app menu */
1735 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1737 /* Checks the dimming rules */
1738 g_object_unref (toolbar_rules_group);
1739 g_object_unref (clipboard_rules_group);
1740 gtk_widget_hide (priv->priority_icon);
1741 gtk_widget_queue_resize (priv->subject_box);
1742 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1744 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1746 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1747 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1748 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1749 priv->update_caption_visibility = TRUE;
1751 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1753 /* Track account-removed signal, this window should be closed
1754 in the case we're creating a mail associated to the account
1756 priv->account_removed_handler_id =
1757 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1759 G_CALLBACK(on_account_removed),
1762 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1764 return (ModestWindow*) obj;
1768 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1770 GString **string_buffer = (GString **) user_data;
1772 *string_buffer = g_string_append (*string_buffer, buffer);
1778 * @result: A new string which should be freed with g_free().
1781 get_formatted_data (ModestMsgEditWindow *edit_window)
1783 ModestMsgEditWindowPrivate *priv;
1784 GString *string_buffer = g_string_new ("");
1786 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1788 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1790 modest_text_utils_hyperlinkify (string_buffer);
1792 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1794 return g_string_free (string_buffer, FALSE);
1799 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1802 const gchar *account_name;
1803 ModestMsgEditWindowPrivate *priv;
1804 TnyIterator *att_iter;
1805 const gchar *picker_active_id;
1807 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1809 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1811 picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1812 g_return_val_if_fail (picker_active_id, NULL);
1813 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1815 /* don't free these (except from) */
1816 data = g_slice_new0 (MsgData);
1817 data->from = g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1818 data->account_name = g_strdup (account_name);
1819 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1820 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1821 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1822 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1823 data->references = g_strdup (priv->references);
1824 data->in_reply_to = g_strdup (priv->in_reply_to);
1825 if (priv->draft_msg) {
1826 data->draft_msg = g_object_ref (priv->draft_msg);
1827 } else if (priv->outbox_msg) {
1828 data->draft_msg = g_object_ref (priv->outbox_msg);
1830 data->draft_msg = NULL;
1833 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1835 gtk_text_buffer_get_bounds (buf, &b, &e);
1836 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1838 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1839 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1841 data->html_body = NULL;
1843 /* deep-copy the data */
1844 att_iter = tny_list_create_iterator (priv->attachments);
1845 data->attachments = NULL;
1846 while (!tny_iterator_is_done (att_iter)) {
1847 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1848 if (!(TNY_IS_MIME_PART(part))) {
1849 g_warning ("strange data in attachment list");
1850 g_object_unref (part);
1851 tny_iterator_next (att_iter);
1854 data->attachments = g_list_append (data->attachments,
1856 tny_iterator_next (att_iter);
1858 g_object_unref (att_iter);
1860 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1861 att_iter = tny_list_create_iterator (priv->images);
1862 data->images = NULL;
1863 while (!tny_iterator_is_done (att_iter)) {
1864 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1866 if (!(TNY_IS_MIME_PART(part))) {
1867 g_warning ("strange data in attachment list");
1868 g_object_unref (part);
1869 tny_iterator_next (att_iter);
1872 cid = tny_mime_part_get_content_id (part);
1874 gchar *image_tag_id;
1875 GtkTextTag *image_tag;
1877 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1878 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1879 g_free (image_tag_id);
1881 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1883 ((gtk_text_iter_has_tag (&iter, image_tag))||
1884 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1885 data->images = g_list_append (data->images,
1886 g_object_ref (part));
1888 g_object_unref (part);
1889 tny_iterator_next (att_iter);
1891 g_object_unref (att_iter);
1893 data->priority_flags = priv->priority_flags;
1900 unref_gobject (GObject *obj, gpointer data)
1902 if (!G_IS_OBJECT(obj))
1904 g_object_unref (obj);
1908 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1911 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1919 g_free (data->from);
1920 g_free (data->subject);
1921 g_free (data->plain_body);
1922 g_free (data->html_body);
1923 g_free (data->account_name);
1924 g_free (data->references);
1925 g_free (data->in_reply_to);
1927 if (data->draft_msg != NULL) {
1928 g_object_unref (data->draft_msg);
1929 data->draft_msg = NULL;
1932 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1933 g_list_free (data->attachments);
1934 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1935 g_list_free (data->images);
1937 g_slice_free (MsgData, data);
1941 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1943 guint64 *parts_size)
1945 ModestMsgEditWindowPrivate *priv;
1947 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1949 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1951 /* TODO: add images */
1952 *parts_size += priv->images_size;
1953 *parts_count += priv->images_count;
1958 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1961 ModestMsgEditWindowPrivate *priv = NULL;
1962 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1964 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1966 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1968 return MODEST_MSG_EDIT_FORMAT_HTML;
1970 return MODEST_MSG_EDIT_FORMAT_TEXT;
1974 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1975 ModestMsgEditFormat format)
1977 ModestMsgEditWindowPrivate *priv;
1978 ModestWindowPrivate *parent_priv;
1980 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1981 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1982 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1985 case MODEST_MSG_EDIT_FORMAT_HTML:
1986 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1987 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
1989 case MODEST_MSG_EDIT_FORMAT_TEXT:
1990 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1991 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
1994 g_return_if_reached ();
1998 ModestMsgEditFormatState *
1999 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2001 ModestMsgEditFormatState *format_state = NULL;
2002 ModestMsgEditWindowPrivate *priv;
2003 WPTextBufferFormat *buffer_format;
2005 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2007 buffer_format = g_new0 (WPTextBufferFormat, 1);
2008 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2010 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2012 format_state = g_new0 (ModestMsgEditFormatState, 1);
2013 format_state->bold = buffer_format->bold&0x1;
2014 format_state->italics = buffer_format->italic&0x1;
2015 format_state->bullet = buffer_format->bullet&0x1;
2016 format_state->color = buffer_format->color;
2017 format_state->font_size = buffer_format->font_size;
2018 format_state->font_family = wp_get_font_name (buffer_format->font);
2019 format_state->justification = buffer_format->justification;
2020 g_free (buffer_format);
2022 return format_state;
2027 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2028 const ModestMsgEditFormatState *format_state)
2030 ModestMsgEditWindowPrivate *priv;
2031 WPTextBufferFormat *buffer_format;
2032 WPTextBufferFormat *current_format;
2034 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2035 g_return_if_fail (format_state != NULL);
2037 buffer_format = g_new0 (WPTextBufferFormat, 1);
2038 current_format = g_new0 (WPTextBufferFormat, 1);
2040 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2041 gtk_widget_grab_focus (priv->msg_body);
2042 buffer_format->bold = (format_state->bold != FALSE);
2043 buffer_format->italic = (format_state->italics != FALSE);
2044 buffer_format->color = format_state->color;
2045 buffer_format->font_size = format_state->font_size;
2046 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2047 buffer_format->justification = format_state->justification;
2048 buffer_format->bullet = format_state->bullet;
2050 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2052 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2053 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2054 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2055 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2056 buffer_format->cs.font = (buffer_format->font != current_format->font);
2057 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2058 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2060 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2061 if (buffer_format->cs.bold) {
2062 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2063 GINT_TO_POINTER (buffer_format->bold&0x1));
2065 if (buffer_format->cs.italic) {
2066 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2067 GINT_TO_POINTER (buffer_format->italic&0x1));
2069 if (buffer_format->cs.color) {
2070 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2071 GINT_TO_POINTER (&(buffer_format->color)));
2073 if (buffer_format->cs.font_size) {
2074 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2075 GINT_TO_POINTER (buffer_format->font_size));
2077 if (buffer_format->cs.justification) {
2078 switch (buffer_format->justification) {
2079 case GTK_JUSTIFY_LEFT:
2080 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2081 GINT_TO_POINTER(TRUE));
2083 case GTK_JUSTIFY_CENTER:
2084 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2085 GINT_TO_POINTER(TRUE));
2087 case GTK_JUSTIFY_RIGHT:
2088 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2089 GINT_TO_POINTER(TRUE));
2096 if (buffer_format->cs.font) {
2097 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2098 GINT_TO_POINTER (buffer_format->font));
2100 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2101 if (buffer_format->cs.bullet) {
2102 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2103 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2105 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2107 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2109 g_free (buffer_format);
2110 g_free (current_format);
2112 /* Check dimming rules */
2113 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2114 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2118 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2120 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2122 ModestWindowPrivate *parent_priv;
2123 ModestMsgEditWindowPrivate *priv;
2125 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2126 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2128 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2129 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2130 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2131 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2133 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2134 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2135 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2138 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2140 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2141 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2143 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2144 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2146 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2147 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2150 switch (buffer_format->justification)
2152 case GTK_JUSTIFY_LEFT:
2153 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2155 case GTK_JUSTIFY_CENTER:
2156 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2158 case GTK_JUSTIFY_RIGHT:
2159 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2166 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2168 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2169 G_CALLBACK (modest_msg_edit_window_color_button_change),
2171 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2172 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2173 G_CALLBACK (modest_msg_edit_window_color_button_change),
2176 if (priv->current_size_index != buffer_format->font_size) {
2180 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2181 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2185 priv->current_size_index = buffer_format->font_size;
2187 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2188 markup = g_strconcat ("<span font_family='Sans'>",
2189 size_text, "</span>", NULL);
2191 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2195 gtk_tree_path_free (path);
2198 if (priv->current_face_index != buffer_format->font) {
2202 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2203 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2207 priv->current_face_index = buffer_format->font;
2208 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2209 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2210 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2217 g_free (buffer_format);
2223 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2225 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2226 ModestMsgEditWindowPrivate *priv;
2227 GtkWidget *dialog = NULL;
2229 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2230 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2232 dialog = hildon_color_chooser_new ();
2233 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2234 g_free (buffer_format);
2236 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2238 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2239 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2242 gtk_widget_destroy (dialog);
2247 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2249 ModestMsgEditWindowPrivate *priv;
2250 GtkWidget *dialog = NULL;
2251 GdkColor *old_color = NULL;
2253 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2254 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2256 dialog = hildon_color_chooser_new ();
2257 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2259 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2261 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2262 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2264 gtk_widget_destroy (dialog);
2269 create_stream_for_uri (const gchar* uri)
2274 TnyStream *result = NULL;
2276 GnomeVFSHandle *handle = NULL;
2277 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2278 if (test == GNOME_VFS_OK) {
2279 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2280 /* Streams over OBEX (Bluetooth) are not seekable but
2281 * we expect them to be (we might need to read them
2282 * several times). So if this is a Bluetooth URI just
2283 * read the whole file into memory (this is not a fast
2284 * protocol so we can assume that these files are not
2285 * going to be very big) */
2286 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2287 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2288 TnyStream *memstream = tny_camel_mem_stream_new ();
2289 tny_stream_write_to_stream (vfssstream, memstream);
2290 g_object_unref (vfssstream);
2293 result = vfssstream;
2301 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2304 ModestMsgEditWindowPrivate *priv;
2305 GtkWidget *dialog = NULL;
2307 GSList *uris = NULL;
2308 GSList *uri_node = NULL;
2310 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2312 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2313 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2314 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2316 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2318 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2319 GTK_WINDOW (dialog), GTK_WINDOW (window));
2321 response = gtk_dialog_run (GTK_DIALOG (dialog));
2323 case GTK_RESPONSE_OK:
2325 gchar *current_folder;
2326 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2327 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2328 if (current_folder && current_folder != '\0') {
2330 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2331 current_folder, &err);
2333 g_debug ("Error storing latest used folder: %s", err->message);
2337 g_free (current_folder);
2343 gtk_widget_destroy (dialog);
2345 g_object_ref (window);
2346 /* The operation could take some time so allow the dialog to be closed */
2347 while (gtk_events_pending ())
2348 gtk_main_iteration ();
2350 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2352 GnomeVFSHandle *handle = NULL;
2353 GnomeVFSResult result;
2354 GtkTextIter position;
2355 GtkTextMark *insert_mark;
2357 uri = (const gchar *) uri_node->data;
2358 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2359 if (result == GNOME_VFS_OK) {
2361 GnomeVFSFileInfo *info;
2362 gchar *filename, *basename, *escaped_filename;
2363 TnyMimePart *mime_part;
2365 const gchar *mime_type = NULL;
2366 GnomeVFSURI *vfs_uri;
2367 guint64 stream_size;
2369 gnome_vfs_close (handle);
2370 vfs_uri = gnome_vfs_uri_new (uri);
2372 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2373 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2374 g_free (escaped_filename);
2375 gnome_vfs_uri_unref (vfs_uri);
2376 info = gnome_vfs_file_info_new ();
2378 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2379 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2381 mime_type = gnome_vfs_file_info_get_mime_type (info);
2383 mime_part = tny_platform_factory_new_mime_part
2384 (modest_runtime_get_platform_factory ());
2386 TnyStream *stream = create_stream_for_uri (uri);
2388 if (stream == NULL) {
2390 modest_platform_information_banner (NULL, NULL,
2391 _FM("sfil_ib_opening_not_allowed"));
2393 g_object_unref (mime_part);
2394 gnome_vfs_file_info_unref (info);
2398 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2400 content_id = g_strdup_printf ("%d", priv->next_cid);
2401 tny_mime_part_set_content_id (mime_part, content_id);
2402 g_free (content_id);
2405 basename = g_path_get_basename (filename);
2406 tny_mime_part_set_filename (mime_part, basename);
2409 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2411 if (pixbuf != NULL) {
2412 priv->images_size += stream_size;
2413 priv->images_count ++;
2414 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2415 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2416 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2417 tny_mime_part_get_content_id (mime_part), pixbuf);
2418 g_object_unref (pixbuf);
2420 tny_list_prepend (priv->images, (GObject *) mime_part);
2421 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2423 modest_platform_information_banner (NULL, NULL,
2424 _("mail_ib_file_operation_failed"));
2428 g_object_unref (mime_part);
2429 gnome_vfs_file_info_unref (info);
2433 g_object_unref (window);
2437 on_attach_file_response (GtkDialog *dialog,
2441 GSList *uris = NULL;
2443 GnomeVFSFileSize total_size, allowed_size;
2444 ModestMsgEditWindow *window;
2445 ModestMsgEditWindowPrivate *priv;
2450 case GTK_RESPONSE_OK:
2452 gchar *current_folder;
2454 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2455 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2456 if (current_folder && current_folder != '\0') {
2458 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2459 current_folder, &err);
2461 g_debug ("Error storing latest used folder: %s", err->message);
2465 g_free (current_folder);
2472 window = MODEST_MSG_EDIT_WINDOW (user_data);
2473 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2475 /* allowed size is the maximum size - what's already there */
2476 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2477 &att_num, &att_size);
2478 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2481 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2483 const gchar *uri = (const gchar *) uri_node->data;
2486 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2488 if (total_size > allowed_size) {
2489 g_debug ("%s: total size: %u",
2490 __FUNCTION__, (unsigned int)total_size);
2493 allowed_size -= total_size;
2495 g_slist_foreach (uris, (GFunc) g_free, NULL);
2496 g_slist_free (uris);
2498 gtk_widget_destroy (GTK_WIDGET (dialog));
2502 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2504 GtkWidget *dialog = NULL;
2505 ModestMsgEditWindowPrivate *priv;
2508 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2510 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2512 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2515 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2516 GTK_FILE_CHOOSER_ACTION_OPEN);
2517 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2518 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2519 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2520 if (conf_folder && conf_folder[0] != '\0') {
2521 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2524 /* Set the default folder to documents folder */
2525 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2528 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2529 ".documents", NULL);
2531 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2532 g_free (docs_folder);
2534 g_free (conf_folder);
2535 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2536 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2537 GTK_WINDOW (dialog), GTK_WINDOW (window));
2539 /* Connect to response & show */
2540 g_signal_connect (dialog, "response",
2541 G_CALLBACK (on_attach_file_response), window);
2542 gtk_widget_show (dialog);
2547 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2549 GnomeVFSFileSize allowed_size)
2552 GnomeVFSHandle *handle = NULL;
2553 ModestMsgEditWindowPrivate *priv;
2554 GnomeVFSResult result;
2555 GnomeVFSFileSize size = 0;
2556 g_return_val_if_fail (window, 0);
2557 g_return_val_if_fail (uri, 0);
2559 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2561 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2562 if (result == GNOME_VFS_OK) {
2563 TnyMimePart *mime_part;
2565 const gchar *mime_type = NULL;
2567 gchar *escaped_filename;
2570 GnomeVFSFileInfo *info;
2571 GnomeVFSURI *vfs_uri;
2573 gnome_vfs_close (handle);
2574 vfs_uri = gnome_vfs_uri_new (uri);
2577 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2578 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2579 g_free (escaped_filename);
2580 gnome_vfs_uri_unref (vfs_uri);
2582 info = gnome_vfs_file_info_new ();
2584 if (gnome_vfs_get_file_info (uri,
2586 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2588 mime_type = gnome_vfs_file_info_get_mime_type (info);
2589 mime_part = tny_platform_factory_new_mime_part
2590 (modest_runtime_get_platform_factory ());
2592 /* try to get the attachment's size; this may fail for weird
2593 * file systems, like obex, upnp... */
2594 if (allowed_size != 0 &&
2595 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2597 if (size > allowed_size) {
2598 modest_platform_information_banner (NULL, NULL,
2599 _("mail_ib_error_attachment_size"));
2604 g_debug ("%s: could not get attachment size", __FUNCTION__);
2606 stream = create_stream_for_uri (uri);
2608 if (stream == NULL) {
2610 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2612 g_object_unref (mime_part);
2614 gnome_vfs_file_info_unref (info);
2618 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2619 g_object_unref (stream);
2621 content_id = g_strdup_printf ("%d", priv->next_cid);
2622 tny_mime_part_set_content_id (mime_part, content_id);
2623 g_free (content_id);
2626 basename = g_path_get_basename (filename);
2627 tny_mime_part_set_filename (mime_part, basename);
2630 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2631 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2633 info->size == 0, info->size);
2634 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2635 gtk_widget_show_all (priv->attachments_caption);
2636 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2638 g_object_unref (mime_part);
2639 gnome_vfs_file_info_unref (info);
2646 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2649 ModestMsgEditWindowPrivate *priv;
2652 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2653 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2655 if (att_list == NULL) {
2656 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2657 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2658 g_object_unref (att_list);
2662 g_object_ref (att_list);
2665 if (tny_list_get_length (att_list) == 0) {
2666 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2668 gboolean dialog_response;
2669 gchar *message = NULL;
2670 gchar *filename = NULL;
2672 if (tny_list_get_length (att_list) == 1) {
2674 iter = tny_list_create_iterator (att_list);
2675 part = (TnyMimePart *) tny_iterator_get_current (iter);
2676 g_object_unref (iter);
2677 if (TNY_IS_MSG (part)) {
2678 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2680 filename = tny_header_dup_subject (header);
2681 g_object_unref (header);
2683 if (filename == NULL) {
2684 filename = g_strdup (_("mail_va_no_subject"));
2687 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2689 g_object_unref (part);
2691 filename = g_strdup ("");
2693 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2694 "emev_nc_delete_attachments",
2695 tny_list_get_length (att_list)), filename);
2698 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2702 if (dialog_response != GTK_RESPONSE_OK) {
2703 g_object_unref (att_list);
2707 for (iter = tny_list_create_iterator (att_list);
2708 !tny_iterator_is_done (iter);
2709 tny_iterator_next (iter)) {
2710 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2711 const gchar *att_id;
2712 tny_list_remove (priv->attachments, (GObject *) mime_part);
2714 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2716 if (tny_list_get_length (priv->attachments) == 0)
2717 gtk_widget_hide (priv->attachments_caption);
2718 att_id = tny_mime_part_get_content_id (mime_part);
2720 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2722 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2723 g_object_unref (mime_part);
2725 g_object_unref (iter);
2728 g_object_unref (att_list);
2730 /* if the last attachment has been removed, focus the Subject: field */
2731 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2732 gtk_widget_grab_focus (priv->subject_field);
2736 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2739 ModestMsgEditWindowPrivate *priv;
2742 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2744 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2746 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2748 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2752 font_size_clicked (GtkToolButton *button,
2753 ModestMsgEditWindow *window)
2755 ModestMsgEditWindowPrivate *priv;
2756 GtkWidget *selector, *dialog;
2758 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2760 selector = hildon_touch_selector_new ();
2761 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2762 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2764 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2765 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2766 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2768 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2772 WPTextBufferFormat format;
2774 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2776 memset (&format, 0, sizeof (format));
2777 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2779 format.cs.font_size = TRUE;
2780 format.cs.text_position = TRUE;
2781 format.cs.font = TRUE;
2782 format.font_size = new_index;
2783 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2785 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2786 GINT_TO_POINTER (new_index)))
2787 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2789 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2790 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2791 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2792 size_text, "</span>", NULL);
2794 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2798 gtk_widget_destroy (dialog);
2800 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2805 font_face_clicked (GtkToolButton *button,
2806 ModestMsgEditWindow *window)
2808 ModestMsgEditWindowPrivate *priv;
2809 GtkWidget *selector, *dialog;
2810 GtkCellRenderer *renderer;
2812 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2814 selector = hildon_touch_selector_new ();
2815 renderer = gtk_cell_renderer_text_new ();
2816 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2817 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2818 renderer, "family", 0, "text", 0, NULL);
2819 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2821 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2822 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2823 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2825 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2826 gint new_font_index;
2830 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2831 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2832 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2836 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2838 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2839 GINT_TO_POINTER(new_font_index)))
2840 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2842 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2843 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2845 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2849 gtk_tree_path_free (path);
2852 gtk_widget_destroy (dialog);
2854 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2859 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2862 ModestMsgEditWindowPrivate *priv = NULL;
2863 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2865 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2866 if (!priv->update_caption_visibility)
2869 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2871 gtk_widget_show (priv->cc_caption);
2873 gtk_widget_hide (priv->cc_caption);
2875 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2879 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2882 ModestMsgEditWindowPrivate *priv = NULL;
2883 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2885 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2886 if (!priv->update_caption_visibility)
2889 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2891 gtk_widget_show (priv->bcc_caption);
2893 gtk_widget_hide (priv->bcc_caption);
2895 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2899 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2900 ModestRecptEditor *editor)
2902 ModestMsgEditWindowPrivate *priv;
2904 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2905 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2907 /* we check for low-mem; in that case, show a warning, and don't allow
2908 * for the addressbook
2910 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2913 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2915 if (editor == NULL) {
2916 GtkWidget *view_focus, *parent;
2917 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2919 /* This code should be kept in sync with ModestRecptEditor. The
2920 textview inside the recpt editor is the one that really gets the
2921 focus. As it's inside a scrolled window, and this one inside the
2922 hbox recpt editor inherits from, we'll need to go up in the
2923 hierarchy to know if the text view is part of the recpt editor
2924 or if it's a different text entry */
2925 parent = gtk_widget_get_parent (view_focus);
2926 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2927 editor = MODEST_RECPT_EDITOR (parent);
2930 editor = MODEST_RECPT_EDITOR (priv->to_field);
2933 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2937 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2939 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2941 modest_msg_edit_window_open_addressbook (window, NULL);
2945 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2946 gboolean show_toolbar)
2948 ModestWindowPrivate *parent_priv;
2949 ModestMsgEditWindowPrivate *priv;
2951 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2952 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2953 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2955 /* We can not just use the code of
2956 modest_msg_edit_window_setup_toolbar because it has a
2957 mixture of both initialization and creation code. */
2959 gint current_format;
2960 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2961 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2962 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2963 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2965 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2968 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2973 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2974 TnyHeaderFlags priority_flags)
2976 ModestMsgEditWindowPrivate *priv;
2977 ModestWindowPrivate *parent_priv;
2979 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2981 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2982 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2984 if (priv->priority_flags != priority_flags) {
2985 GtkAction *priority_action = NULL;
2987 priv->priority_flags = priority_flags;
2989 switch (priority_flags) {
2990 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2991 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2992 MODEST_HEADER_ICON_HIGH,
2993 HILDON_ICON_SIZE_SMALL);
2994 gtk_widget_show (priv->priority_icon);
2995 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2996 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2998 case TNY_HEADER_FLAG_LOW_PRIORITY:
2999 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3000 MODEST_HEADER_ICON_LOW,
3001 HILDON_ICON_SIZE_SMALL);
3002 gtk_widget_show (priv->priority_icon);
3003 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3004 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3007 gtk_widget_hide (priv->priority_icon);
3008 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3009 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3012 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3013 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3015 gtk_widget_queue_resize (priv->subject_box);
3019 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3022 ModestMsgEditWindowPrivate *priv;
3023 ModestWindowPrivate *parent_priv;
3024 gint current_format;
3026 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3028 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3029 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3031 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3032 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3034 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3036 if (current_format != file_format) {
3037 switch (file_format) {
3038 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3039 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3040 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3041 if (parent_priv->toolbar)
3042 gtk_widget_show (parent_priv->toolbar);
3044 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3048 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3049 response = gtk_dialog_run (GTK_DIALOG (dialog));
3050 gtk_widget_destroy (dialog);
3051 if (response == GTK_RESPONSE_OK) {
3052 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3053 if (parent_priv->toolbar)
3054 gtk_widget_hide (parent_priv->toolbar);
3056 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3057 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3062 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3063 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3064 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3069 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3072 ModestMsgEditWindowPrivate *priv;
3073 WPTextBufferFormat oldfmt, fmt;
3074 gint old_position = 0;
3078 GdkColor *color = NULL;
3079 gboolean bold, bold_set, italic, italic_set;
3080 gboolean underline, underline_set;
3081 gboolean strikethrough, strikethrough_set;
3082 gboolean position_set;
3083 gboolean font_size_set, font_set, color_set;
3086 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3087 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3089 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3090 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3091 GTK_WINDOW(dialog), GTK_WINDOW (window));
3093 /* First we get the currently selected font information */
3094 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3096 switch (oldfmt.text_position) {
3097 case TEXT_POSITION_NORMAL:
3100 case TEXT_POSITION_SUPERSCRIPT:
3108 g_object_set (G_OBJECT (dialog),
3109 "bold", oldfmt.bold != FALSE,
3110 "bold-set", !oldfmt.cs.bold,
3111 "underline", oldfmt.underline != FALSE,
3112 "underline-set", !oldfmt.cs.underline,
3113 "italic", oldfmt.italic != FALSE,
3114 "italic-set", !oldfmt.cs.italic,
3115 "strikethrough", oldfmt.strikethrough != FALSE,
3116 "strikethrough-set", !oldfmt.cs.strikethrough,
3117 "color", &oldfmt.color,
3118 "color-set", !oldfmt.cs.color,
3119 "size", wp_font_size[oldfmt.font_size],
3120 "size-set", !oldfmt.cs.font_size,
3121 "position", old_position,
3122 "position-set", !oldfmt.cs.text_position,
3123 "family", wp_get_font_name (oldfmt.font),
3124 "family-set", !oldfmt.cs.font,
3127 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3128 GTK_WINDOW (dialog), GTK_WINDOW (window));
3129 gtk_widget_show_all (dialog);
3130 priv->font_dialog = dialog;
3131 response = gtk_dialog_run (GTK_DIALOG (dialog));
3132 priv->font_dialog = NULL;
3133 if (response == GTK_RESPONSE_OK) {
3135 g_object_get( dialog,
3137 "bold-set", &bold_set,
3138 "underline", &underline,
3139 "underline-set", &underline_set,
3141 "italic-set", &italic_set,
3142 "strikethrough", &strikethrough,
3143 "strikethrough-set", &strikethrough_set,
3145 "color-set", &color_set,
3147 "size-set", &font_size_set,
3148 "family", &font_name,
3149 "family-set", &font_set,
3150 "position", &position,
3151 "position-set", &position_set,
3156 if (response == GTK_RESPONSE_OK) {
3157 memset(&fmt, 0, sizeof(fmt));
3163 fmt.italic = italic;
3164 fmt.cs.italic = TRUE;
3166 if (underline_set) {
3167 fmt.underline = underline;
3168 fmt.cs.underline = TRUE;
3170 if (strikethrough_set) {
3171 fmt.strikethrough = strikethrough;
3172 fmt.cs.strikethrough = TRUE;
3177 ? TEXT_POSITION_NORMAL
3178 : ( ( position == 1 )
3179 ? TEXT_POSITION_SUPERSCRIPT
3180 : TEXT_POSITION_SUBSCRIPT );
3181 fmt.cs.text_position = TRUE;
3182 fmt.font_size = oldfmt.font_size;
3186 fmt.cs.color = TRUE;
3189 fmt.font = wp_get_font_index(font_name,
3194 if (font_size_set) {
3195 fmt.cs.font_size = TRUE;
3196 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3198 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3199 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3201 gtk_widget_destroy (dialog);
3203 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3207 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3209 ModestMsgEditWindowPrivate *priv;
3210 ModestWindowPrivate *parent_priv;
3211 gboolean was_rich_text, is_rich_text;
3213 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3214 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3215 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3217 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3219 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3221 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3223 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3225 gtk_widget_show (parent_priv->toolbar);
3227 gtk_widget_hide (parent_priv->toolbar);
3230 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3231 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3235 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3237 ModestMsgEditWindowPrivate *priv;
3239 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3240 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3242 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3244 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3245 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3250 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3252 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3254 priv->can_undo = can_undo;
3258 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3260 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3262 priv->can_redo = can_redo;
3266 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3268 ModestMsgEditWindowPrivate *priv;
3269 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3270 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3272 return priv->can_undo;
3276 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3278 ModestMsgEditWindowPrivate *priv;
3279 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3280 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3282 return priv->can_redo;
3287 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3290 GtkTextIter match_start, match_end;
3292 if (image_id == NULL)
3295 gtk_text_buffer_get_start_iter (buffer, &iter);
3297 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3298 GSList *tags = gtk_text_iter_get_tags (&match_start);
3300 for (node = tags; node != NULL; node = g_slist_next (node)) {
3301 GtkTextTag *tag = (GtkTextTag *) node->data;
3302 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3303 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3304 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3306 offset = gtk_text_iter_get_offset (&match_start);
3307 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3308 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3312 gtk_text_iter_forward_char (&iter);
3317 message_is_empty (ModestMsgEditWindow *window)
3319 ModestMsgEditWindowPrivate *priv = NULL;
3321 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3322 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3324 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3325 * so we can ignore markup.
3327 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3330 count = gtk_text_buffer_get_char_count (buf);
3336 msg_body_focus (GtkWidget *focus,
3337 GdkEventFocus *event,
3341 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3342 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3343 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3348 recpt_field_changed (GtkTextBuffer *buffer,
3349 ModestMsgEditWindow *editor)
3351 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3352 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3356 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3358 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3359 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3363 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3366 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3367 GtkTextBuffer *buffer;
3369 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3370 gtk_text_buffer_set_modified (buffer, modified);
3371 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3372 gtk_text_buffer_set_modified (buffer, modified);
3373 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3374 gtk_text_buffer_set_modified (buffer, modified);
3375 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3379 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3381 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3382 const char *account_name;
3383 GtkTextBuffer *buffer;
3385 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3386 if (gtk_text_buffer_get_modified (buffer))
3388 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3389 if (gtk_text_buffer_get_modified (buffer))
3391 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3392 if (gtk_text_buffer_get_modified (buffer))
3394 if (gtk_text_buffer_get_modified (priv->text_buffer))
3397 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3398 if (priv->original_mailbox) {
3399 if (!account_name || strcmp (account_name, priv->original_mailbox))
3401 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3412 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3414 ModestMsgEditWindowPrivate *priv = NULL;
3415 GSList *address_list = NULL;
3417 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3418 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3420 /* check if there's no recipient added */
3421 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3422 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3423 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3424 /* no recipient contents, then select contacts */
3425 modest_msg_edit_window_open_addressbook (window, NULL);
3430 g_object_ref (window);
3431 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3432 (add_to_addressbook) ? &address_list : NULL)) {
3433 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3434 g_object_unref (window);
3437 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3438 (add_to_addressbook) ? &address_list : NULL)) {
3439 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3440 g_object_unref (window);
3443 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3444 (add_to_addressbook) ? &address_list : NULL)) {
3445 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3446 g_object_unref (window);
3450 /* Add contacts to address book */
3451 if (add_to_addressbook && address_list)
3452 modest_address_book_add_address_list (address_list);
3454 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3455 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3456 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3457 g_object_unref (window);
3464 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3466 GSList *recipients = NULL;
3467 ModestMsgEditWindowPrivate *priv;
3468 gchar *joined, *after_remove, *to, *cc, *bcc;
3470 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3472 /* First of all check names */
3473 if (!modest_msg_edit_window_check_names (self, FALSE))
3476 if (!modest_msg_edit_window_has_pending_addresses (self))
3479 /* Don't add the from obviously */
3480 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3481 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3482 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3484 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3489 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3492 recipients = modest_text_utils_split_addresses_list (after_remove);
3493 g_free (after_remove);
3496 /* Offer the user to add recipients to the address book */
3497 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3498 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3503 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3504 ModestMsgEditWindow *window)
3506 modest_msg_edit_window_offer_attach_file (window);
3510 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3512 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3514 return priv->clipboard_text;
3518 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3520 ModestMsgEditWindow *window)
3522 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3523 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3526 /* It could happen that the window was already closed */
3527 if (!GTK_WIDGET_VISIBLE (window))
3530 g_object_ref (window);
3531 text = gtk_clipboard_wait_for_text (selection_clipboard);
3533 if (priv->clipboard_text != NULL) {
3534 g_free (priv->clipboard_text);
3536 priv->clipboard_text = text;
3538 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3540 g_object_unref (window);
3543 static gboolean clipboard_owner_change_idle (gpointer userdata)
3545 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3546 ModestMsgEditWindowPrivate *priv;
3548 gdk_threads_enter ();
3549 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3550 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3552 priv->clipboard_owner_idle = 0;
3553 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3554 gdk_threads_leave ();
3560 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3562 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3563 if (priv->clipboard_owner_idle == 0) {
3564 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3565 clipboard_owner_change_idle,
3566 g_object_ref (window),
3572 subject_field_move_cursor (GtkEntry *entry,
3573 GtkMovementStep step,
3578 /* It could happen that the window was already closed */
3579 if (!GTK_WIDGET_VISIBLE (window))
3582 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3586 update_window_title (ModestMsgEditWindow *window)
3588 ModestMsgEditWindowPrivate *priv = NULL;
3589 const gchar *subject;
3591 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3592 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3593 if (subject == NULL || subject[0] == '\0')
3594 subject = _("mail_va_new_email");
3596 gtk_window_set_title (GTK_WINDOW (window), subject);
3602 body_insert_text (GtkTextBuffer *buffer,
3603 GtkTextIter *location,
3606 ModestMsgEditWindow *window)
3608 GtkTextIter end_iter;
3615 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3617 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3619 offset = gtk_text_iter_get_offset (&end_iter);
3620 line = gtk_text_iter_get_line (&end_iter);
3624 while (text_offset < text + len) {
3625 if (*text_offset == '\n')
3627 if (text_lines + line >= MAX_BODY_LINES) {
3628 len = text_offset - text;
3634 utf8_len = g_utf8_strlen (text, len);
3636 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3637 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3638 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3643 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3645 /* Prevent endless recursion */
3646 result = g_strndup (text, utf8_end - text);
3647 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3648 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3649 (gpointer) result, (gpointer) (utf8_end - text),
3651 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3655 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3656 if (priv->max_chars_banner == NULL) {
3657 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3658 _CS("ckdg_ib_maximum_characters_reached"));
3659 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3665 subject_field_changed (GtkEditable *editable,
3666 ModestMsgEditWindow *window)
3668 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3669 update_window_title (window);
3670 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3671 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3672 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3675 subject_field_insert_text (GtkEditable *editable,
3677 gint new_text_length,
3679 ModestMsgEditWindow *window)
3681 GString *result = g_string_new ("");
3683 gint result_len = 0;
3684 const gchar *entry_text = NULL;
3687 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3688 old_length = g_utf8_strlen (entry_text, -1);
3690 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3691 gunichar c = g_utf8_get_char_validated (current, 8);
3692 /* Invalid unichar, stop */
3698 result = g_string_append_unichar (result, c);
3702 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3703 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3706 /* Prevent endless recursion */
3707 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3708 g_signal_emit_by_name (editable, "insert-text",
3709 (gpointer) result->str, (gpointer) result->len,
3710 (gpointer) position, (gpointer) window);
3711 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3715 if (result_len + old_length > 1000) {
3716 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3717 _CS("ckdg_ib_maximum_characters_reached"));
3719 g_string_free (result, TRUE);
3723 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3726 ModestMsgEditWindowPrivate *priv = NULL;
3728 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3729 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3731 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3734 gtk_widget_show_all (priv->find_toolbar);
3735 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3737 gtk_widget_hide_all (priv->find_toolbar);
3738 gtk_widget_grab_focus (priv->msg_body);
3743 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3745 GtkTextIter *match_start,
3746 GtkTextIter *match_end)
3748 GtkTextIter end_iter;
3749 gchar *str_casefold;
3752 gchar *range_casefold;
3755 gboolean result = FALSE;
3762 gtk_text_iter_forward_to_end (&end_iter);
3764 str_casefold = g_utf8_casefold (str, -1);
3765 str_chars_n = strlen (str);
3767 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3768 range_casefold = g_utf8_casefold (range_text, -1);
3769 range_chars_n = strlen (range_casefold);
3771 if (range_chars_n < str_chars_n) {
3772 g_free (str_casefold);
3773 g_free (range_text);
3774 g_free (range_casefold);
3778 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3779 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3780 if (!g_utf8_collate (range_subtext, str_casefold)) {
3781 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3783 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3784 match_start, match_end, NULL)) {
3785 g_debug ("Matched string with collate, but not matched in model");
3787 g_free (found_text);
3789 g_free (range_subtext);
3793 g_free (str_casefold);
3794 g_free (range_text);
3795 g_free (range_casefold);
3802 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3803 ModestMsgEditWindow *window)
3805 gchar *current_search = NULL;
3806 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3808 GtkTextIter selection_start, selection_end;
3809 GtkTextIter match_start, match_end;
3810 gboolean continue_search = FALSE;
3812 if (message_is_empty (window)) {
3813 g_free (priv->last_search);
3814 priv->last_search = NULL;
3815 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3819 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3820 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3821 g_free (current_search);
3822 g_free (priv->last_search);
3823 priv->last_search = NULL;
3824 /* Information banner about empty search */
3825 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3829 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3830 continue_search = TRUE;
3832 g_free (priv->last_search);
3833 priv->last_search = g_strdup (current_search);
3836 if (continue_search) {
3837 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3838 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3839 &match_start, &match_end);
3841 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3843 GtkTextIter buffer_start;
3844 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3845 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3846 &match_start, &match_end);
3848 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3851 /* Mark as selected the string found in search */
3853 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3854 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3855 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3857 g_free (priv->last_search);
3858 priv->last_search = NULL;
3860 g_free (current_search);
3864 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3866 ModestMsgEditWindowPrivate *priv;
3868 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3873 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3876 ModestMsgEditWindowPrivate *priv;
3878 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3883 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3884 ModestMsgEditWindow *window)
3886 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3890 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3893 ModestMsgEditWindowPrivate *priv;
3894 TnyHeader *header = NULL;
3896 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3897 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3899 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3901 if (priv->draft_msg != NULL) {
3902 g_object_unref (priv->draft_msg);
3905 if (draft != NULL) {
3906 g_object_ref (draft);
3907 header = tny_msg_get_header (draft);
3908 if (priv->msg_uid) {
3909 g_free (priv->msg_uid);
3910 priv->msg_uid = NULL;
3912 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3915 priv->draft_msg = draft;
3919 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3920 GtkTextIter *start, GtkTextIter *end,
3923 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3924 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3927 if (tag == NULL) return;
3928 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3929 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3930 replace_with_images (window, priv->images);
3935 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3938 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3940 g_return_if_fail (TNY_IS_MIME_PART (part));
3941 tny_list_prepend (priv->attachments, (GObject *) part);
3942 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3943 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3944 gtk_widget_show_all (priv->attachments_caption);
3945 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3949 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3951 ModestMsgEditWindowPrivate *priv;
3953 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3954 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3956 return priv->msg_uid;
3960 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3961 ModestMsgEditWindowWidgetType widget_type)
3963 ModestMsgEditWindowPrivate *priv;
3965 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3966 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3968 switch (widget_type) {
3969 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3970 return priv->msg_body;
3972 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3973 return priv->to_field;
3975 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3976 return priv->cc_field;
3978 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3979 return priv->bcc_field;
3981 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3982 return priv->subject_field;
3984 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3985 return priv->attachments_view;
3993 remove_tags (WPTextBuffer *buffer)
3995 GtkTextIter start, end;
3997 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3998 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4000 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4004 on_account_removed (TnyAccountStore *account_store,
4005 TnyAccount *account,
4008 /* Do nothing if it's a store account, because we use the
4009 transport to send the messages */
4010 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4011 const gchar *parent_acc = NULL;
4012 const gchar *our_acc = NULL;
4014 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4015 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4016 /* Close this window if I'm showing a message of the removed account */
4017 if (strcmp (parent_acc, our_acc) == 0)
4018 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4023 update_signature (ModestMsgEditWindow *self,
4024 const gchar *old_account,
4025 const gchar *new_account)
4027 ModestMsgEditWindowPrivate *priv;
4028 gboolean has_old_signature, has_new_signature;
4030 ModestAccountMgr *mgr;
4033 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4035 gtk_text_buffer_begin_user_action (priv->text_buffer);
4037 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4038 mgr = modest_runtime_get_account_mgr ();
4042 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4043 if (has_old_signature) {
4044 GtkTextIter match_start, match_end;
4046 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4047 seems that the search has some problems
4048 with the blank space at the end */
4049 if (gtk_text_iter_forward_search (&iter, "--",
4050 GTK_TEXT_SEARCH_TEXT_ONLY,
4051 &match_start, NULL, NULL)) {
4052 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4053 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4055 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4056 &match_start, &match_end, NULL)) {
4060 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4065 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4066 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4067 if (has_new_signature) {
4069 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4070 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4072 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4073 g_free (full_signature);
4076 gtk_text_buffer_end_user_action (priv->text_buffer);
4079 static void update_branding (ModestMsgEditWindow *self,
4080 const gchar *new_account)
4082 ModestMsgEditWindowPrivate *priv;
4083 ModestAccountMgr *mgr;
4084 const GdkPixbuf *new_icon = NULL;
4085 gchar *new_label = NULL;
4086 gboolean show = FALSE;
4088 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4090 mgr = modest_runtime_get_account_mgr ();
4092 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4094 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4095 gtk_widget_show (priv->brand_icon);
4098 gtk_widget_hide (priv->brand_icon);
4101 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4102 gtk_widget_show (priv->brand_label);
4106 gtk_widget_hide (priv->brand_label);
4110 gtk_widget_show (priv->brand_container);
4112 gtk_widget_hide (priv->brand_container);
4116 from_field_changed (HildonPickerButton *button,
4117 ModestMsgEditWindow *self)
4119 ModestMsgEditWindowPrivate *priv;
4120 gchar *old_account, *new_account;
4122 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4124 old_account = priv->last_from_account;
4125 new_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4128 g_warning ("%s, could not get the new account", __FUNCTION__);
4132 /* If the From is the same do nothing */
4133 if (old_account && new_account && !strcmp (old_account, new_account))
4136 priv->last_from_account = new_account;
4138 update_signature (self, old_account, new_account);
4139 update_branding (self, new_account);
4143 typedef struct _MessageSettingsHelper {
4144 ModestMsgEditWindow *window;
4145 GSList *priority_group;
4146 GSList *format_group;
4147 GtkToggleButton *current_priority;
4148 GtkToggleButton *current_format;
4149 } MessageSettingsHelper;
4152 on_priority_toggle (GtkToggleButton *button,
4153 MessageSettingsHelper *helper)
4156 ModestMsgEditWindowPrivate *priv;
4158 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4159 if (gtk_toggle_button_get_active (button)) {
4161 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4162 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4163 if ((node_button != button) &&
4164 gtk_toggle_button_get_active (node_button)) {
4165 gtk_toggle_button_set_active (node_button, FALSE);
4168 helper->current_priority = button;
4170 gboolean found = FALSE;
4171 /* If no one is active, activate it again */
4172 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4173 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4174 if (gtk_toggle_button_get_active (node_button)) {
4180 gtk_toggle_button_set_active (button, TRUE);
4186 on_format_toggle (GtkToggleButton *button,
4187 MessageSettingsHelper *helper)
4190 ModestMsgEditWindowPrivate *priv;
4192 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4193 if (gtk_toggle_button_get_active (button)) {
4195 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4196 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4197 if ((node_button != button) &&
4198 gtk_toggle_button_get_active (node_button)) {
4199 gtk_toggle_button_set_active (node_button, FALSE);
4202 helper->current_format = button;
4204 gboolean found = FALSE;
4205 /* If no one is active, activate it again */
4206 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4207 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4208 if (gtk_toggle_button_get_active (node_button)) {
4214 gtk_toggle_button_set_active (button, TRUE);
4221 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4226 GtkWidget *priority_hbox;
4227 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4228 GtkWidget *captioned;
4229 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4230 GtkWidget *format_hbox;
4231 GtkWidget *html_toggle, *text_toggle;
4232 ModestMsgEditWindowPrivate *priv;
4233 MessageSettingsHelper helper = {0,};
4235 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4236 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4237 helper.window = window;
4238 helper.priority_group = NULL;
4239 helper.format_group = NULL;
4241 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4242 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4244 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4245 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4246 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4247 vbox = gtk_vbox_new (FALSE, 0);
4248 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4249 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4250 gtk_container_add (GTK_CONTAINER (align), vbox);
4251 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4252 gtk_widget_show (align);
4253 gtk_widget_show (vbox);
4255 /* Priority toggles */
4256 priority_hbox = gtk_hbox_new (TRUE, 0);
4257 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4258 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4259 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4260 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4261 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4262 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4263 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4264 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4265 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4266 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4267 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4268 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4269 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4270 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4271 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4272 gtk_widget_show_all (priority_hbox);
4273 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4274 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4275 gtk_widget_show (captioned);
4276 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4278 /* format toggles */
4279 format_hbox = gtk_hbox_new (TRUE, 0);
4280 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4281 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4282 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4283 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4284 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4285 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4286 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4287 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4288 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4289 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4290 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4291 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4292 gtk_widget_show_all (format_hbox);
4293 gtk_widget_show (format_hbox);
4294 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4297 g_object_unref (title_sizegroup);
4298 g_object_unref (value_sizegroup);
4300 /* Set current values */
4301 switch (priv->priority_flags) {
4302 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4303 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4304 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4306 case TNY_HEADER_FLAG_LOW_PRIORITY:
4307 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4308 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4311 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4312 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4316 switch (modest_msg_edit_window_get_format (window)) {
4317 case MODEST_MSG_EDIT_FORMAT_TEXT:
4318 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4319 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4321 case MODEST_MSG_EDIT_FORMAT_HTML:
4323 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4324 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4328 /* Signal connects */
4329 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4330 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4331 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4332 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4333 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4335 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4336 GTK_WINDOW (dialog), GTK_WINDOW (window));
4338 /* Save settings if the user clicked on done */
4339 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4340 TnyHeaderFlags flags;
4341 ModestMsgEditFormat old_format, new_format;
4343 /* Set priority flags */
4344 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4345 if (priv->priority_flags != flags)
4346 modest_msg_edit_window_set_priority_flags (window, flags);
4348 /* Set edit format */
4349 old_format = modest_msg_edit_window_get_format (window);
4350 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4351 if (old_format != new_format) {
4352 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4353 modest_msg_edit_window_set_file_format (window, file_format);
4357 gtk_widget_destroy (dialog);
4358 g_slist_free (helper.priority_group);
4362 on_message_settings (GtkAction *action,
4363 ModestMsgEditWindow *window)
4365 modest_msg_edit_window_show_msg_settings_dialog (window);
4369 on_cc_button_toggled (HildonCheckButton *button,
4370 ModestMsgEditWindow *window)
4372 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4374 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4375 hildon_check_button_get_active (button));
4379 on_bcc_button_toggled (HildonCheckButton *button,
4380 ModestMsgEditWindow *window)
4382 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4384 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4385 hildon_check_button_get_active (button));
4389 setup_menu (ModestMsgEditWindow *self)
4391 ModestMsgEditWindowPrivate *priv = NULL;
4393 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4395 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4397 /* Settings menu buttons */
4398 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4399 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4401 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4402 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4403 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4404 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4405 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4406 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4408 priv->cc_button = hildon_check_button_new (0);
4409 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4410 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4412 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4414 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4415 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4416 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4417 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4419 priv->bcc_button = hildon_check_button_new (0);
4420 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4421 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4423 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4425 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4426 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4427 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4428 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4430 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4431 APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4432 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4433 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4434 APP_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4436 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4437 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4438 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4439 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4440 APP_MENU_CALLBACK (on_message_settings),
4442 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4443 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4448 emit_open_addressbook (GtkButton *button,
4449 ModestRecptEditor *editor)
4451 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4455 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4456 const gchar *label, GtkWidget *control)
4458 GtkWidget *abook_button;
4461 GtkWidget *label_widget;
4463 box = gtk_hbox_new (FALSE, 0);
4465 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4466 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4468 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4469 label_widget = gtk_label_new (label);
4470 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4471 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4473 gtk_container_add (GTK_CONTAINER (align), abook_button);
4474 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4475 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4476 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4477 if (title_size_group)
4478 gtk_size_group_add_widget (title_size_group, label_widget);
4479 if (value_size_group)
4480 gtk_size_group_add_widget (value_size_group, control);
4482 g_signal_connect (G_OBJECT (abook_button), "clicked",
4483 G_CALLBACK (emit_open_addressbook), control);
4489 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4491 ModestMsgEditWindowPrivate *priv = NULL;
4493 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4495 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4496 priv->max_chars_banner = NULL;
4500 has_pending_addresses (ModestRecptEditor *recpt_editor)
4502 const gchar *recipients = NULL;
4503 GSList *start_indexes = NULL, *end_indexes = NULL;
4504 GSList *current_start, *current_end;
4505 GtkTextBuffer *buffer;
4506 gint offset_delta = 0;
4508 gboolean has_recipients_to_add = FALSE;
4510 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4511 last_length = g_utf8_strlen (recipients, -1);
4512 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4517 current_start = start_indexes;
4518 current_end = end_indexes;
4519 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4521 while (current_start && !has_recipients_to_add) {
4523 gchar *start_ptr, *end_ptr;
4524 gint start_pos, end_pos;
4526 start_pos = (*((gint*) current_start->data)) + offset_delta;
4527 end_pos = (*((gint*) current_end->data)) + offset_delta;
4529 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4530 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4532 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4534 if (modest_text_utils_validate_recipient (address, NULL)) {
4535 if (!modest_address_book_has_address (address)) {
4536 has_recipients_to_add = TRUE;
4539 current_start = g_slist_next (current_start);
4540 current_end = g_slist_next (current_end);
4542 return has_recipients_to_add;
4546 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4548 ModestMsgEditWindowPrivate *priv = NULL;
4550 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4552 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4554 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4555 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4556 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))