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 <modest-scrollable.h>
68 #include <modest-isearch-toolbar.h>
69 #include <hildon/hildon-touch-selector.h>
70 #include <hildon/hildon-picker-dialog.h>
71 #include "modest-msg-edit-window-ui-dimming.h"
73 #include "modest-hildon-includes.h"
74 #include "widgets/modest-msg-edit-window-ui.h"
75 #include <libgnomevfs/gnome-vfs-mime.h>
76 #include <modest-utils.h>
77 #include "modest-maemo-utils.h"
78 #include <modest-ui-constants.h>
81 #define DEFAULT_FONT_SIZE 3
82 #define DEFAULT_FONT 2
83 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
84 #define DEFAULT_MAIN_VBOX_SPACING 0
85 #define SUBJECT_MAX_LENGTH 1000
86 #define IMAGE_MAX_WIDTH 560
87 #define DEFAULT_FONT_SCALE 1.5
88 #define ATTACHMENT_BUTTON_WIDTH 118
89 #define MAX_FROM_VALUE 36
90 #define MAX_BODY_LENGTH 128*1024
91 #define MAX_BODY_LINES 2048
93 static gboolean is_wp_text_buffer_started = FALSE;
95 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
96 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
97 static void modest_msg_edit_window_finalize (GObject *obj);
99 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
100 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
101 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
103 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
104 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
105 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
106 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
107 GtkTextIter *start, GtkTextIter *end,
109 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
110 static void body_insert_text (GtkTextBuffer *buffer,
111 GtkTextIter *location,
114 ModestMsgEditWindow *window);
115 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
116 static void subject_field_insert_text (GtkEditable *editable,
118 gint new_text_length,
120 ModestMsgEditWindow *window);
121 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
123 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
125 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
126 ModestRecptEditor *editor);
127 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
128 ModestMsgEditWindow *window);
130 /* ModestWindow methods implementation */
131 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
132 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
133 gboolean show_toolbar);
134 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
136 ModestMsgEditWindow *window);
137 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
138 static void subject_field_move_cursor (GtkEntry *entry,
139 GtkMovementStep step,
143 static void update_window_title (ModestMsgEditWindow *window);
146 static void modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
147 ModestMsgEditWindow *window);
148 static void modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
149 ModestMsgEditWindow *window);
150 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
152 GtkTextIter *match_start,
153 GtkTextIter *match_end);
155 static void remove_tags (WPTextBuffer *buffer);
157 static void on_account_removed (TnyAccountStore *account_store,
161 static void init_window (ModestMsgEditWindow *obj);
163 gboolean scroll_drag_timeout (gpointer userdata);
164 static void correct_scroll (ModestMsgEditWindow *w);
165 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
166 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
167 ModestMsgEditWindow *userdata);
168 static void text_buffer_mark_set (GtkTextBuffer *buffer,
171 ModestMsgEditWindow *userdata);
172 static void on_message_settings (GtkAction *action,
173 ModestMsgEditWindow *window);
174 static void setup_menu (ModestMsgEditWindow *self);
176 static void from_field_changed (HildonPickerButton *button,
177 ModestMsgEditWindow *self);
178 static void font_size_clicked (GtkToolButton *button,
179 ModestMsgEditWindow *window);
180 static void font_face_clicked (GtkToolButton *button,
181 ModestMsgEditWindow *window);
182 static void update_signature (ModestMsgEditWindow *self,
183 const gchar *old_account,
184 const gchar *new_account);
185 static void update_branding (ModestMsgEditWindow *self,
186 const gchar *new_account);
187 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
188 const gchar *label, GtkWidget *control);
189 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
190 static void DEBUG_BUFFER (WPTextBuffer *buffer)
194 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
196 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
197 while (!gtk_text_iter_is_end (&iter)) {
198 GString *output = g_string_new ("");
199 GSList *toggled_tags;
202 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
203 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
204 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
205 GtkTextTag *tag = (GtkTextTag *) node->data;
207 g_object_get (G_OBJECT (tag), "name", &name, NULL);
208 output = g_string_append (output, name);
209 g_string_append (output, " ");
211 output = g_string_append (output, "] OPENED [ ");
212 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
213 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
214 GtkTextTag *tag = (GtkTextTag *) node->data;
216 g_object_get (G_OBJECT (tag), "name", &name, NULL);
217 output = g_string_append (output, name);
218 g_string_append (output, " ");
220 output = g_string_append (output, "]\n");
221 g_debug ("%s", output->str);
222 g_string_free (output, TRUE);
223 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
225 g_debug ("END BUFFER");
229 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
230 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
234 /* static gboolean */
235 /* on_key_pressed (GtkWidget *self, */
236 /* GdkEventKey *event, */
237 /* gpointer user_data); */
239 /* list my signals */
246 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
247 struct _ModestMsgEditWindowPrivate {
249 GtkWidget *header_box;
251 ModestPairList *from_field_protos;
252 GtkWidget *from_field;
253 gchar *last_from_account;
254 gchar *original_account_name;
259 gchar *original_mailbox;
263 GtkWidget *bcc_field;
264 GtkWidget *subject_field;
265 GtkWidget *attachments_view;
266 GtkWidget *priority_icon;
267 GtkWidget *subject_box;
268 GtkWidget *send_button;
270 GtkWidget *cc_caption;
271 GtkWidget *bcc_caption;
272 gboolean update_caption_visibility;
273 GtkWidget *attachments_caption;
275 GtkTextBuffer *text_buffer;
277 GtkWidget *font_size_toolitem;
278 GtkWidget *font_face_toolitem;
279 GtkWidget *font_color_button;
280 GtkWidget *font_color_toolitem;
281 GSList *font_items_group;
282 GtkTreeModel *faces_model;
283 gint current_face_index;
284 GtkWidget *font_tool_button_label;
285 GtkTreeModel *sizes_model;
286 gint current_size_index;
287 GtkWidget *size_tool_button_label;
289 GtkWidget *isearch_toolbar;
292 GtkWidget *font_dialog;
294 GtkWidget *scrollable;
295 guint correct_scroll_idle;
296 guint scroll_drag_timeout_id;
300 TnyList *attachments;
305 TnyHeaderFlags priority_flags;
307 gboolean can_undo, can_redo;
308 gulong clipboard_change_handler_id;
309 gulong default_clipboard_change_handler_id;
310 gulong account_removed_handler_id;
311 guint clipboard_owner_idle;
312 gchar *clipboard_text;
321 GtkWidget *cc_button;
322 GtkWidget *bcc_button;
324 GtkWidget *max_chars_banner;
326 GtkWidget *brand_icon;
327 GtkWidget *brand_label;
328 GtkWidget *brand_container;
331 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
332 MODEST_TYPE_MSG_EDIT_WINDOW, \
333 ModestMsgEditWindowPrivate))
335 static GtkWindowClass *parent_class = NULL;
337 /* uncomment the following if you have defined any signals */
338 /* static guint signals[LAST_SIGNAL] = {0}; */
341 modest_msg_edit_window_get_type (void)
343 static GType my_type = 0;
345 static const GTypeInfo my_info = {
346 sizeof(ModestMsgEditWindowClass),
347 NULL, /* base init */
348 NULL, /* base finalize */
349 (GClassInitFunc) modest_msg_edit_window_class_init,
350 NULL, /* class finalize */
351 NULL, /* class data */
352 sizeof(ModestMsgEditWindow),
354 (GInstanceInitFunc) modest_msg_edit_window_init,
357 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
358 "ModestMsgEditWindow",
366 save_state (ModestWindow *self)
368 modest_widget_memory_save (modest_runtime_get_conf(),
369 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
374 restore_settings (ModestMsgEditWindow *self)
376 ModestConf *conf = NULL;
378 conf = modest_runtime_get_conf ();
380 /* Dim at start clipboard actions */
381 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
386 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
388 GObjectClass *gobject_class;
389 ModestWindowClass *modest_window_class;
390 gobject_class = (GObjectClass*) klass;
391 modest_window_class = (ModestWindowClass*) klass;
393 parent_class = g_type_class_peek_parent (klass);
394 gobject_class->finalize = modest_msg_edit_window_finalize;
396 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
397 modest_window_class->save_state_func = save_state;
398 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
400 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
404 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
406 ModestMsgEditWindowPrivate *priv;
407 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
409 priv->msg_body = NULL;
410 priv->from_field = NULL;
411 priv->to_field = NULL;
412 priv->cc_field = NULL;
413 priv->bcc_field = NULL;
414 priv->subject_field = NULL;
415 priv->attachments = TNY_LIST (tny_simple_list_new ());
416 priv->images = TNY_LIST (tny_simple_list_new ());
417 priv->images_size = 0;
418 priv->images_count = 0;
421 priv->cc_caption = NULL;
422 priv->bcc_caption = NULL;
423 priv->update_caption_visibility = FALSE;
425 priv->priority_flags = 0;
427 priv->isearch_toolbar = NULL;
428 priv->last_search = NULL;
430 priv->draft_msg = NULL;
431 priv->outbox_msg = NULL;
432 priv->msg_uid = NULL;
434 priv->can_undo = FALSE;
435 priv->can_redo = FALSE;
436 priv->clipboard_change_handler_id = 0;
437 priv->default_clipboard_change_handler_id = 0;
438 priv->account_removed_handler_id = 0;
439 priv->clipboard_owner_idle = 0;
440 priv->clipboard_text = NULL;
443 priv->scroll_drag_timeout_id = 0;
444 priv->correct_scroll_idle = 0;
445 priv->last_upper = 0.0;
447 priv->font_dialog = NULL;
448 priv->app_menu = NULL;
450 priv->references = NULL;
451 priv->in_reply_to = NULL;
452 priv->max_chars_banner = NULL;
454 if (!is_wp_text_buffer_started) {
455 is_wp_text_buffer_started = TRUE;
456 wp_text_buffer_library_init ();
461 hildon_program_add_window (hildon_program_get_instance(),
466 multimailbox_get_default_mailbox (const gchar *account_name)
468 gchar *transport_account;
469 gchar *result = NULL;
471 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
473 TNY_ACCOUNT_TYPE_TRANSPORT);
474 if (transport_account) {
476 ModestProtocolRegistry *registry;
478 registry = modest_runtime_get_protocol_registry ();
480 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
481 MODEST_ACCOUNT_PROTO, TRUE);
483 ModestProtocol *protocol =
484 modest_protocol_registry_get_protocol_by_name (registry,
485 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
487 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
488 ModestPairList *pair_list;
490 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
493 ModestPair *pair = (ModestPair *) pair_list->data;
494 result = g_strdup ((const gchar *) pair->first);
495 modest_pair_list_free (pair_list);
506 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
508 static ModestPairList*
509 get_transports (void)
511 GSList *transports = NULL;
513 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
514 GSList *accounts = modest_account_mgr_account_names (account_mgr,
515 TRUE /* only enabled accounts. */);
517 GSList *cursor = accounts;
519 gchar *account_name = cursor->data;
522 gchar *transport_account;
523 gboolean multi_mailbox = FALSE;
524 ModestProtocol *protocol = NULL;
526 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
528 transport_account = modest_account_mgr_get_server_account_name
529 (modest_runtime_get_account_mgr (),
531 TNY_ACCOUNT_TYPE_TRANSPORT);
532 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
533 ModestPairList *pair_list;
534 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
537 transports = g_slist_concat (transports, pair_list);
538 multi_mailbox = TRUE;
543 if (!multi_mailbox) {
544 gchar *from_string = NULL;
546 from_string = modest_account_mgr_get_from_string (account_mgr,
548 if (from_string && account_name) {
549 gchar *name = account_name;
550 ModestPair *pair = modest_pair_new ((gpointer) name,
551 (gpointer) from_string , TRUE);
552 transports = g_slist_prepend (transports, pair);
557 cursor = cursor->next;
559 g_slist_free (accounts); /* only free the accounts, not the elements,
560 * because they are used in the pairlist */
564 static void window_focus (GtkWindow *window,
568 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
572 scroll_drag_timeout (gpointer userdata)
574 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
575 ModestMsgEditWindowPrivate *priv;
577 /* It could happen that the window was already closed */
578 if (!GTK_WIDGET_VISIBLE (win))
581 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
583 correct_scroll_without_drag_check (win, TRUE);
585 priv->scroll_drag_timeout_id = 0;
591 correct_scroll_without_drag_check_idle (gpointer userdata)
593 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
594 ModestMsgEditWindowPrivate *priv;
596 GdkRectangle rectangle;
597 gint offset_min, offset_max;
601 /* It could happen that the window was already closed */
602 if (!GTK_WIDGET_VISIBLE (w))
605 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
607 insert = gtk_text_buffer_get_insert (priv->text_buffer);
608 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
610 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
611 offset_min = priv->msg_body->allocation.y + rectangle.y;
612 offset_max = offset_min + rectangle.height;
614 vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
615 offset_min = MAX (offset_min - 48, 0);
616 offset_max = MIN (offset_max + 48, vadj->upper);
618 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
620 priv->correct_scroll_idle = 0;
625 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
627 ModestMsgEditWindowPrivate *priv;
629 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
631 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
634 if (priv->correct_scroll_idle > 0) {
638 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
639 (GSourceFunc) correct_scroll_without_drag_check_idle,
645 correct_scroll (ModestMsgEditWindow *w)
647 ModestMsgEditWindowPrivate *priv;
649 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
650 if (gtk_grab_get_current () == priv->msg_body) {
651 if (priv->scroll_drag_timeout_id == 0) {
652 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
654 (GSourceFunc) scroll_drag_timeout,
661 correct_scroll_without_drag_check (w, TRUE);
665 text_buffer_end_user_action (GtkTextBuffer *buffer,
666 ModestMsgEditWindow *userdata)
669 correct_scroll (userdata);
673 text_buffer_mark_set (GtkTextBuffer *buffer,
676 ModestMsgEditWindow *userdata)
678 gtk_text_buffer_begin_user_action (buffer);
679 gtk_text_buffer_end_user_action (buffer);
683 cut_clipboard_check (GtkTextView *text_view,
686 GtkTextBuffer *buffer;
688 buffer = gtk_text_view_get_buffer (text_view);
689 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
690 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
695 copy_clipboard_check (GtkTextView *text_view,
698 GtkTextBuffer *buffer;
700 buffer = gtk_text_view_get_buffer (text_view);
701 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
702 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
707 attachment_deleted (ModestAttachmentsView *attachments_view,
710 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
715 body_size_request (GtkWidget *body,
719 /* Make sure the body always get at least 70 pixels */
720 if (req->height < 70)
725 connect_signals (ModestMsgEditWindow *obj)
727 ModestMsgEditWindowPrivate *priv;
729 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
731 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
732 G_CALLBACK (text_buffer_refresh_attributes), obj);
733 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
734 G_CALLBACK (text_buffer_can_undo), obj);
735 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
736 G_CALLBACK (text_buffer_can_redo), obj);
737 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
738 G_CALLBACK (body_changed), obj);
739 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
740 G_CALLBACK (body_insert_text), obj);
741 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
742 G_CALLBACK (body_changed), obj);
743 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
744 G_CALLBACK (text_buffer_end_user_action), obj);
745 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
746 G_CALLBACK (text_buffer_mark_set), obj);
747 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
748 G_CALLBACK (text_buffer_apply_tag), obj);
749 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
750 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
751 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
752 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
753 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
754 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
756 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
757 G_CALLBACK (modest_ui_actions_on_send), obj);
759 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
760 G_CALLBACK (from_field_changed), obj);
762 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
763 G_CALLBACK (msg_body_focus), obj);
764 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
765 G_CALLBACK (msg_body_focus), obj);
766 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
767 G_CALLBACK (body_size_request), obj);
768 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
769 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
770 "changed", G_CALLBACK (recpt_field_changed), obj);
771 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
772 "changed", G_CALLBACK (recpt_field_changed), obj);
773 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
774 "changed", G_CALLBACK (recpt_field_changed), obj);
775 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
776 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
777 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
779 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
780 G_CALLBACK (modest_msg_edit_window_isearch_toolbar_search), obj);
781 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
782 G_CALLBACK (modest_msg_edit_window_isearch_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 = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
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 modest_entry_set_hint (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->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
1004 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
1006 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1008 priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
1010 g_object_set (G_OBJECT (priv->scrollable), "horizontal-policy", GTK_POLICY_NEVER, NULL);
1012 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1013 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1014 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1016 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1017 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1018 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1020 modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), window_align);
1021 gtk_widget_show_all (GTK_WIDGET(priv->scrollable));
1023 window_box = gtk_vbox_new (FALSE, 0);
1024 gtk_container_add (GTK_CONTAINER(obj), window_box);
1026 gtk_box_pack_start (GTK_BOX (window_box), priv->scrollable, TRUE, TRUE, 0);
1028 /* Set window icon */
1029 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1031 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1032 g_object_unref (window_icon);
1037 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1039 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1041 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1042 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1043 priv->clipboard_change_handler_id))
1044 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1045 priv->clipboard_change_handler_id);
1046 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1047 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1048 priv->default_clipboard_change_handler_id))
1049 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1050 priv->default_clipboard_change_handler_id);
1052 if (priv->account_removed_handler_id &&
1053 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1054 priv->account_removed_handler_id))
1055 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1056 priv->account_removed_handler_id);
1060 modest_msg_edit_window_finalize (GObject *obj)
1062 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1064 if (priv->max_chars_banner) {
1065 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1066 priv->max_chars_banner = FALSE;
1069 /* Sanity check: shouldn't be needed, the window mgr should
1070 call this function before */
1071 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1073 if (priv->font_dialog != NULL) {
1074 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1077 if (priv->clipboard_text != NULL) {
1078 g_free (priv->clipboard_text);
1079 priv->clipboard_text = NULL;
1082 if (priv->draft_msg != NULL) {
1083 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1084 if (TNY_IS_HEADER (header)) {
1085 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1086 modest_window_mgr_unregister_header (mgr, header);
1088 g_object_unref (priv->draft_msg);
1089 priv->draft_msg = NULL;
1091 if (priv->outbox_msg != NULL) {
1092 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1093 if (TNY_IS_HEADER (header)) {
1094 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1095 modest_window_mgr_unregister_header (mgr, header);
1097 g_object_unref (priv->outbox_msg);
1098 priv->outbox_msg = NULL;
1100 if (priv->correct_scroll_idle > 0) {
1101 g_source_remove (priv->correct_scroll_idle);
1102 priv->correct_scroll_idle = 0;
1104 if (priv->scroll_drag_timeout_id > 0) {
1105 g_source_remove (priv->scroll_drag_timeout_id);
1106 priv->scroll_drag_timeout_id = 0;
1108 if (priv->clipboard_owner_idle > 0) {
1109 g_source_remove (priv->clipboard_owner_idle);
1110 priv->clipboard_owner_idle = 0;
1112 if (priv->original_account_name)
1113 g_free (priv->original_account_name);
1114 if (priv->original_mailbox)
1115 g_free (priv->original_mailbox);
1116 g_free (priv->msg_uid);
1117 g_free (priv->last_search);
1118 g_free (priv->references);
1119 g_free (priv->in_reply_to);
1120 g_object_unref (priv->attachments);
1121 g_object_unref (priv->images);
1123 /* This had to stay alive for as long as the picker that used it: */
1124 modest_pair_list_free (priv->from_field_protos);
1126 G_OBJECT_CLASS(parent_class)->finalize (obj);
1130 pixbuf_size_prepared (GdkPixbufLoader *loader,
1133 ModestMsgEditWindow *self)
1135 gint new_height, new_width;
1138 new_height = height;
1142 if (width > IMAGE_MAX_WIDTH) {
1143 new_height = height * IMAGE_MAX_WIDTH / width;
1144 new_width = IMAGE_MAX_WIDTH;
1147 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1151 pixbuf_from_stream (TnyStream *stream,
1152 const gchar *mime_type,
1153 guint64 *stream_size,
1154 ModestMsgEditWindow *self)
1156 GdkPixbufLoader *loader;
1159 GError *error = NULL;
1163 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1165 if (loader == NULL) {
1170 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1172 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1174 tny_stream_reset (TNY_STREAM (stream));
1175 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1176 unsigned char read_buffer[128];
1178 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1180 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1183 /* Allow some UI responsiveness */
1184 while (gtk_events_pending ())
1185 gtk_main_iteration ();
1187 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1189 gdk_pixbuf_loader_close (loader, &error);
1192 g_error_free (error);
1193 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1195 g_object_ref (pixbuf);
1196 g_object_unref (loader);
1201 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1202 GdkPixbuf *new_pixbuf;
1204 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1205 gdk_pixbuf_get_width (pixbuf);
1206 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1207 g_object_unref (pixbuf);
1208 pixbuf = new_pixbuf;
1212 *stream_size = size;
1218 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1220 ModestMsgEditWindowPrivate *priv;
1223 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1225 g_object_ref (self);
1226 for (iter = tny_list_create_iterator (attachments);
1227 !tny_iterator_is_done (iter);
1228 tny_iterator_next (iter)) {
1229 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1230 const gchar *cid = tny_mime_part_get_content_id (part);
1231 const gchar *mime_type = tny_mime_part_get_content_type (part);
1232 if ((cid != NULL)&&(mime_type != NULL)) {
1233 guint64 stream_size;
1234 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1235 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1238 g_object_unref (stream);
1240 if (pixbuf != NULL) {
1241 priv->images_count ++;
1242 priv->images_size += stream_size;
1243 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1244 g_object_unref (pixbuf);
1247 g_object_unref (part);
1249 g_object_unref (iter);
1250 g_object_unref (self);
1254 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1256 TnyMimePart *parent = NULL;
1257 const gchar *content_type = NULL;
1258 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1260 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1262 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1263 parent = g_object_ref (msg);
1264 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1265 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1268 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1269 iter = tny_list_create_iterator (parts);
1270 while (!tny_iterator_is_done (iter)) {
1272 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1273 content_type = tny_mime_part_get_content_type (part);
1274 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1278 g_object_unref (part);
1280 tny_iterator_next (iter);
1282 g_object_unref (iter);
1283 g_object_unref (parts);
1286 if (parent != NULL) {
1287 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1290 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1291 iter = tny_list_create_iterator (parts);
1292 while (!tny_iterator_is_done (iter)) {
1294 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1295 content_type = tny_mime_part_get_content_type (part);
1296 if (content_type && g_str_has_prefix (content_type, "image/")) {
1297 tny_list_prepend (priv->images, (GObject *) part);
1299 g_object_unref (part);
1300 tny_iterator_next (iter);
1302 g_object_unref (iter);
1303 g_object_unref (parts);
1304 g_object_unref (parent);
1309 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1312 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1314 for (iter = tny_list_create_iterator (attachments) ;
1315 !tny_iterator_is_done (iter);
1316 tny_iterator_next (iter)) {
1317 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1318 const gchar *cid = tny_mime_part_get_content_id (part);
1320 char *invalid = NULL;
1321 gint int_cid = strtol (cid, &invalid, 10);
1322 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1323 priv->next_cid = int_cid + 1;
1326 g_object_unref (part);
1328 g_object_unref (iter);
1332 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1335 gchar *to, *cc, *bcc, *subject;
1337 ModestMsgEditWindowPrivate *priv;
1338 ModestWindowPrivate *parent_priv;
1340 TnyHeaderFlags priority_flags;
1341 TnyFolder *msg_folder;
1342 gboolean is_html = FALSE;
1343 gboolean field_view_set;
1345 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1346 g_return_if_fail (TNY_IS_MSG (msg));
1348 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1349 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1351 header = tny_msg_get_header (msg);
1352 to = tny_header_dup_to (header);
1353 cc = tny_header_dup_cc (header);
1354 bcc = tny_header_dup_bcc (header);
1355 subject = tny_header_dup_subject (header);
1357 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1358 priority_flags = tny_header_get_priority (header);
1361 gchar *quoted_names = modest_text_utils_quote_names (to);
1362 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1363 g_free (quoted_names);
1366 field_view_set = TRUE;
1368 gchar *quoted_names = modest_text_utils_quote_names (cc);
1369 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1370 g_free (quoted_names);
1371 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1372 gtk_widget_show (priv->cc_caption);
1373 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1374 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1375 gtk_widget_hide (priv->cc_caption);
1376 field_view_set = FALSE;
1378 modest_togglable_set_active (priv->cc_button, field_view_set);
1380 field_view_set = TRUE;
1382 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1383 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1384 g_free (quoted_names);
1385 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1386 gtk_widget_show (priv->bcc_caption);
1387 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1388 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1389 gtk_widget_hide (priv->bcc_caption);
1390 field_view_set = FALSE;
1392 modest_togglable_set_active (priv->bcc_button, field_view_set);
1396 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1397 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1400 update_window_title (self);
1402 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1403 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1405 if ((body == NULL)||(body[0] == '\0')) {
1407 body = modest_text_utils_convert_to_html ("");
1410 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1411 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1414 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1417 /* Add attachments to the view */
1418 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1419 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1420 if (tny_list_get_length (priv->attachments) == 0) {
1421 gtk_widget_hide (priv->attachments_caption);
1423 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1424 gtk_widget_show_all (priv->attachments_caption);
1426 get_related_images (self, msg);
1427 update_next_cid (self, priv->attachments);
1428 update_next_cid (self, priv->images);
1429 replace_with_images (self, priv->images);
1431 if (preserve_is_rich && !is_html) {
1432 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1433 /* Get the default format required from configuration */
1434 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1435 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1438 /* Set the default focus depending on having already a To: field or not */
1439 if ((!to)||(*to == '\0')) {
1440 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1442 gtk_widget_grab_focus (priv->msg_body);
1445 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1447 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1448 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1450 modest_msg_edit_window_set_modified (self, FALSE);
1452 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1453 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1454 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1455 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1457 if (priv->msg_uid) {
1458 g_free (priv->msg_uid);
1459 priv->msg_uid = NULL;
1462 /* we should set a reference to the incoming message if it is a draft */
1463 msg_folder = tny_msg_get_folder (msg);
1465 if (modest_tny_folder_is_local_folder (msg_folder)) {
1466 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1467 if (type == TNY_FOLDER_TYPE_INVALID)
1468 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1470 if (type == TNY_FOLDER_TYPE_DRAFTS)
1471 priv->draft_msg = g_object_ref(msg);
1472 if (type == TNY_FOLDER_TYPE_OUTBOX)
1473 priv->outbox_msg = g_object_ref(msg);
1474 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1476 g_object_unref (msg_folder);
1487 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1489 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1490 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1491 GtkWidget *placeholder;
1492 GtkWidget *tool_item;
1497 GtkWidget *sizes_menu;
1498 GtkWidget *fonts_menu;
1504 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1505 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1506 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1507 modest_window_add_toolbar (MODEST_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1509 /* Font color placeholder */
1510 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1511 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1514 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1515 priv->font_color_button = hildon_color_button_new ();
1516 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1517 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1518 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1519 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1520 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1521 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1522 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1523 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1525 G_CALLBACK (modest_msg_edit_window_color_button_change),
1528 /* Font size and face placeholder */
1529 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1530 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1532 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1533 priv->size_tool_button_label = gtk_label_new (NULL);
1534 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1535 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1536 size_text, "</span>", NULL);
1537 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1538 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1540 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1541 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1542 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1543 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1544 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1545 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1546 gtk_widget_set_sensitive (arrow, FALSE);
1547 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1548 sizes_menu = gtk_menu_new ();
1549 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1550 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1553 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1554 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1556 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1560 if (wp_font_size[size_index] == 12)
1561 priv->current_size_index = size_index;
1565 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1566 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1567 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1568 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1569 priv->font_size_toolitem = tool_item;
1572 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1573 priv->font_tool_button_label = gtk_label_new (NULL);
1574 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1575 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1576 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1578 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1579 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1580 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1581 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1582 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1583 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1584 gtk_widget_set_sensitive (arrow, FALSE);
1585 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1586 fonts_menu = gtk_menu_new ();
1587 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1588 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1591 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1593 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1594 0, wp_get_font_name (font_index),
1597 if (font_index == DEFAULT_FONT)
1598 priv->current_face_index = font_index;
1600 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1601 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1602 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1603 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1604 priv->font_face_toolitem = tool_item;
1606 /* Set expand and homogeneous for remaining items */
1607 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1608 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1609 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1610 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1611 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1612 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1614 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1615 will not show the tool items added to the placeholders) */
1616 gtk_widget_show_all (parent_priv->toolbar);
1618 /* Set the no show all *after* showing all items. We do not
1619 want the toolbar to be shown with a show all because it
1620 could go agains the gconf setting regarding showing or not
1621 the toolbar of the editor window */
1622 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1628 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1631 ModestWindowPrivate *parent_priv;
1632 ModestMsgEditWindowPrivate *priv;
1633 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1634 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1635 ModestWindowMgr *mgr = NULL;
1637 g_return_val_if_fail (msg, NULL);
1638 g_return_val_if_fail (account_name, NULL);
1640 mgr = modest_runtime_get_window_mgr ();
1642 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1644 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1645 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1647 /* Menubar. Update the state of some toggles */
1648 priv->from_field_protos = get_transports ();
1649 priv->original_mailbox = NULL;
1650 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1651 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1652 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1653 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1654 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) mailbox);
1655 priv->original_mailbox = g_strdup (mailbox);
1656 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1657 /* We set the first mailbox as the active mailbox */
1658 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1659 if (priv->original_mailbox != NULL)
1660 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1661 (gpointer) priv->original_mailbox);
1663 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1664 (gpointer) account_name);
1666 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1668 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1669 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1670 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1672 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1673 hildon_touch_selector_get_current_text
1674 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1675 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1676 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
1679 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1681 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1683 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1684 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1686 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1688 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1689 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1690 /* Add common dimming rules */
1691 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1692 modest_msg_edit_window_toolbar_dimming_entries,
1693 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1694 MODEST_WINDOW (obj));
1695 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1696 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1697 MODEST_WINDOW (obj));
1698 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1699 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1700 MODEST_WINDOW (obj));
1701 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1702 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1703 MODEST_WINDOW (obj));
1704 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1705 G_CALLBACK (modest_ui_dimming_rules_on_send),
1706 MODEST_WINDOW (obj));
1707 /* Insert dimming rules group for this window */
1708 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1709 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1711 /* Setup app menu */
1712 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1714 /* Checks the dimming rules */
1715 g_object_unref (toolbar_rules_group);
1716 g_object_unref (clipboard_rules_group);
1717 gtk_widget_hide (priv->priority_icon);
1718 gtk_widget_queue_resize (priv->subject_box);
1719 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1721 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1723 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1724 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1725 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1726 priv->update_caption_visibility = TRUE;
1728 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1730 /* Track account-removed signal, this window should be closed
1731 in the case we're creating a mail associated to the account
1733 priv->account_removed_handler_id =
1734 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1736 G_CALLBACK(on_account_removed),
1739 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1741 return (ModestWindow*) obj;
1745 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1747 GString **string_buffer = (GString **) user_data;
1749 *string_buffer = g_string_append (*string_buffer, buffer);
1755 * @result: A new string which should be freed with g_free().
1758 get_formatted_data (ModestMsgEditWindow *edit_window)
1760 ModestMsgEditWindowPrivate *priv;
1761 GString *string_buffer = g_string_new ("");
1763 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1765 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1767 modest_text_utils_hyperlinkify (string_buffer);
1769 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1771 return g_string_free (string_buffer, FALSE);
1776 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1779 const gchar *account_name;
1780 ModestMsgEditWindowPrivate *priv;
1781 TnyIterator *att_iter;
1782 const gchar *picker_active_id;
1784 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1786 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1788 picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1789 g_return_val_if_fail (picker_active_id, NULL);
1790 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1792 /* don't free these (except from) */
1793 data = g_slice_new0 (MsgData);
1794 data->from = g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1795 data->account_name = g_strdup (account_name);
1796 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1797 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1798 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1799 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1800 data->references = g_strdup (priv->references);
1801 data->in_reply_to = g_strdup (priv->in_reply_to);
1802 if (priv->draft_msg) {
1803 data->draft_msg = g_object_ref (priv->draft_msg);
1804 } else if (priv->outbox_msg) {
1805 data->draft_msg = g_object_ref (priv->outbox_msg);
1807 data->draft_msg = NULL;
1810 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1812 gtk_text_buffer_get_bounds (buf, &b, &e);
1813 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1815 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1816 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1818 data->html_body = NULL;
1820 /* deep-copy the data */
1821 att_iter = tny_list_create_iterator (priv->attachments);
1822 data->attachments = NULL;
1823 while (!tny_iterator_is_done (att_iter)) {
1824 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1825 if (!(TNY_IS_MIME_PART(part))) {
1826 g_warning ("strange data in attachment list");
1827 g_object_unref (part);
1828 tny_iterator_next (att_iter);
1831 data->attachments = g_list_append (data->attachments,
1833 tny_iterator_next (att_iter);
1835 g_object_unref (att_iter);
1837 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1838 att_iter = tny_list_create_iterator (priv->images);
1839 data->images = NULL;
1840 while (!tny_iterator_is_done (att_iter)) {
1841 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1843 if (!(TNY_IS_MIME_PART(part))) {
1844 g_warning ("strange data in attachment list");
1845 g_object_unref (part);
1846 tny_iterator_next (att_iter);
1849 cid = tny_mime_part_get_content_id (part);
1851 gchar *image_tag_id;
1852 GtkTextTag *image_tag;
1854 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1855 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1856 g_free (image_tag_id);
1858 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1860 ((gtk_text_iter_has_tag (&iter, image_tag))||
1861 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1862 data->images = g_list_append (data->images,
1863 g_object_ref (part));
1865 g_object_unref (part);
1866 tny_iterator_next (att_iter);
1868 g_object_unref (att_iter);
1870 data->priority_flags = priv->priority_flags;
1877 unref_gobject (GObject *obj, gpointer data)
1879 if (!G_IS_OBJECT(obj))
1881 g_object_unref (obj);
1885 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1888 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1896 g_free (data->from);
1897 g_free (data->subject);
1898 g_free (data->plain_body);
1899 g_free (data->html_body);
1900 g_free (data->account_name);
1901 g_free (data->references);
1902 g_free (data->in_reply_to);
1904 if (data->draft_msg != NULL) {
1905 g_object_unref (data->draft_msg);
1906 data->draft_msg = NULL;
1909 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1910 g_list_free (data->attachments);
1911 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1912 g_list_free (data->images);
1914 g_slice_free (MsgData, data);
1918 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1920 guint64 *parts_size)
1922 ModestMsgEditWindowPrivate *priv;
1924 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1926 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1928 /* TODO: add images */
1929 *parts_size += priv->images_size;
1930 *parts_count += priv->images_count;
1935 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1938 ModestMsgEditWindowPrivate *priv = NULL;
1939 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1941 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1943 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1945 return MODEST_MSG_EDIT_FORMAT_HTML;
1947 return MODEST_MSG_EDIT_FORMAT_TEXT;
1951 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1952 ModestMsgEditFormat format)
1954 ModestMsgEditWindowPrivate *priv;
1955 ModestWindowPrivate *parent_priv;
1957 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1958 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1959 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1962 case MODEST_MSG_EDIT_FORMAT_HTML:
1963 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1964 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
1966 case MODEST_MSG_EDIT_FORMAT_TEXT:
1967 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1968 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
1971 g_return_if_reached ();
1975 ModestMsgEditFormatState *
1976 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1978 ModestMsgEditFormatState *format_state = NULL;
1979 ModestMsgEditWindowPrivate *priv;
1980 WPTextBufferFormat *buffer_format;
1982 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1984 buffer_format = g_new0 (WPTextBufferFormat, 1);
1985 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1987 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1989 format_state = g_new0 (ModestMsgEditFormatState, 1);
1990 format_state->bold = buffer_format->bold&0x1;
1991 format_state->italics = buffer_format->italic&0x1;
1992 format_state->bullet = buffer_format->bullet&0x1;
1993 format_state->color = buffer_format->color;
1994 format_state->font_size = buffer_format->font_size;
1995 format_state->font_family = wp_get_font_name (buffer_format->font);
1996 format_state->justification = buffer_format->justification;
1997 g_free (buffer_format);
1999 return format_state;
2004 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2005 const ModestMsgEditFormatState *format_state)
2007 ModestMsgEditWindowPrivate *priv;
2008 WPTextBufferFormat *buffer_format;
2009 WPTextBufferFormat *current_format;
2011 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2012 g_return_if_fail (format_state != NULL);
2014 buffer_format = g_new0 (WPTextBufferFormat, 1);
2015 current_format = g_new0 (WPTextBufferFormat, 1);
2017 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2018 gtk_widget_grab_focus (priv->msg_body);
2019 buffer_format->bold = (format_state->bold != FALSE);
2020 buffer_format->italic = (format_state->italics != FALSE);
2021 buffer_format->color = format_state->color;
2022 buffer_format->font_size = format_state->font_size;
2023 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2024 buffer_format->justification = format_state->justification;
2025 buffer_format->bullet = format_state->bullet;
2027 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2029 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2030 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2031 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2032 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2033 buffer_format->cs.font = (buffer_format->font != current_format->font);
2034 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2035 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2037 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2038 if (buffer_format->cs.bold) {
2039 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2040 GINT_TO_POINTER (buffer_format->bold&0x1));
2042 if (buffer_format->cs.italic) {
2043 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2044 GINT_TO_POINTER (buffer_format->italic&0x1));
2046 if (buffer_format->cs.color) {
2047 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2048 GINT_TO_POINTER (&(buffer_format->color)));
2050 if (buffer_format->cs.font_size) {
2051 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2052 GINT_TO_POINTER (buffer_format->font_size));
2054 if (buffer_format->cs.justification) {
2055 switch (buffer_format->justification) {
2056 case GTK_JUSTIFY_LEFT:
2057 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2058 GINT_TO_POINTER(TRUE));
2060 case GTK_JUSTIFY_CENTER:
2061 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2062 GINT_TO_POINTER(TRUE));
2064 case GTK_JUSTIFY_RIGHT:
2065 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2066 GINT_TO_POINTER(TRUE));
2073 if (buffer_format->cs.font) {
2074 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2075 GINT_TO_POINTER (buffer_format->font));
2077 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2078 if (buffer_format->cs.bullet) {
2079 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2080 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2082 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2084 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2086 g_free (buffer_format);
2087 g_free (current_format);
2089 /* Check dimming rules */
2090 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2091 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2095 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2097 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2099 ModestWindowPrivate *parent_priv;
2100 ModestMsgEditWindowPrivate *priv;
2102 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2103 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2105 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2106 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2107 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2108 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2110 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2111 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2112 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2115 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2117 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2118 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2120 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2121 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2123 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2124 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2127 switch (buffer_format->justification)
2129 case GTK_JUSTIFY_LEFT:
2130 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2132 case GTK_JUSTIFY_CENTER:
2133 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2135 case GTK_JUSTIFY_RIGHT:
2136 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2143 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2145 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2146 G_CALLBACK (modest_msg_edit_window_color_button_change),
2148 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2149 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2150 G_CALLBACK (modest_msg_edit_window_color_button_change),
2153 if (priv->current_size_index != buffer_format->font_size) {
2157 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2158 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2162 priv->current_size_index = buffer_format->font_size;
2164 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2165 markup = g_strconcat ("<span font_family='Sans'>",
2166 size_text, "</span>", NULL);
2168 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2172 gtk_tree_path_free (path);
2175 if (priv->current_face_index != buffer_format->font) {
2179 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2180 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2184 priv->current_face_index = buffer_format->font;
2185 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2186 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2187 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2194 g_free (buffer_format);
2200 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2203 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2204 ModestMsgEditWindowPrivate *priv;
2205 GtkWidget *dialog = NULL;
2207 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2208 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2210 dialog = hildon_color_chooser_new ();
2211 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2212 g_free (buffer_format);
2214 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2216 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2217 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2220 gtk_widget_destroy (dialog);
2225 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2228 ModestMsgEditWindowPrivate *priv;
2229 GtkWidget *dialog = NULL;
2230 GdkColor *old_color = NULL;
2232 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2233 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2235 dialog = hildon_color_chooser_new ();
2236 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2238 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2240 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2241 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2243 gtk_widget_destroy (dialog);
2248 create_stream_for_uri (const gchar* uri)
2253 TnyStream *result = NULL;
2255 GnomeVFSHandle *handle = NULL;
2256 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2257 if (test == GNOME_VFS_OK) {
2258 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2259 /* Streams over OBEX (Bluetooth) are not seekable but
2260 * we expect them to be (we might need to read them
2261 * several times). So if this is a Bluetooth URI just
2262 * read the whole file into memory (this is not a fast
2263 * protocol so we can assume that these files are not
2264 * going to be very big) */
2265 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2266 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2267 TnyStream *memstream = tny_camel_mem_stream_new ();
2268 tny_stream_write_to_stream (vfssstream, memstream);
2269 g_object_unref (vfssstream);
2272 result = vfssstream;
2280 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2283 ModestMsgEditWindowPrivate *priv;
2284 GtkWidget *dialog = NULL;
2286 GSList *uris = NULL;
2287 GSList *uri_node = NULL;
2289 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2291 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2292 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2293 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2295 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2297 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2298 GTK_WINDOW (dialog), GTK_WINDOW (window));
2300 response = gtk_dialog_run (GTK_DIALOG (dialog));
2302 case GTK_RESPONSE_OK:
2304 gchar *current_folder;
2305 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2306 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2307 if (current_folder && current_folder != '\0') {
2309 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2310 current_folder, &err);
2312 g_debug ("Error storing latest used folder: %s", err->message);
2316 g_free (current_folder);
2322 gtk_widget_destroy (dialog);
2324 g_object_ref (window);
2325 /* The operation could take some time so allow the dialog to be closed */
2326 while (gtk_events_pending ())
2327 gtk_main_iteration ();
2329 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2331 GnomeVFSHandle *handle = NULL;
2332 GnomeVFSResult result;
2333 GtkTextIter position;
2334 GtkTextMark *insert_mark;
2336 uri = (const gchar *) uri_node->data;
2337 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2338 if (result == GNOME_VFS_OK) {
2340 GnomeVFSFileInfo *info;
2341 gchar *filename, *basename, *escaped_filename;
2342 TnyMimePart *mime_part;
2344 const gchar *mime_type = NULL;
2345 GnomeVFSURI *vfs_uri;
2346 guint64 stream_size;
2348 gnome_vfs_close (handle);
2349 vfs_uri = gnome_vfs_uri_new (uri);
2351 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2352 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2353 g_free (escaped_filename);
2354 gnome_vfs_uri_unref (vfs_uri);
2355 info = gnome_vfs_file_info_new ();
2357 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2358 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2360 mime_type = gnome_vfs_file_info_get_mime_type (info);
2362 mime_part = tny_platform_factory_new_mime_part
2363 (modest_runtime_get_platform_factory ());
2365 TnyStream *stream = create_stream_for_uri (uri);
2367 if (stream == NULL) {
2369 modest_platform_information_banner (NULL, NULL,
2370 _FM("sfil_ib_opening_not_allowed"));
2372 g_object_unref (mime_part);
2373 gnome_vfs_file_info_unref (info);
2377 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2379 content_id = g_strdup_printf ("%d", priv->next_cid);
2380 tny_mime_part_set_content_id (mime_part, content_id);
2381 g_free (content_id);
2384 basename = g_path_get_basename (filename);
2385 tny_mime_part_set_filename (mime_part, basename);
2388 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2390 if (pixbuf != NULL) {
2391 priv->images_size += stream_size;
2392 priv->images_count ++;
2393 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2394 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2395 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2396 tny_mime_part_get_content_id (mime_part), pixbuf);
2397 g_object_unref (pixbuf);
2399 tny_list_prepend (priv->images, (GObject *) mime_part);
2400 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2402 modest_platform_information_banner (NULL, NULL,
2403 _("mail_ib_file_operation_failed"));
2407 g_object_unref (mime_part);
2408 gnome_vfs_file_info_unref (info);
2412 g_object_unref (window);
2416 on_attach_file_response (GtkDialog *dialog,
2420 GSList *uris = NULL;
2422 GnomeVFSFileSize total_size, allowed_size;
2423 ModestMsgEditWindow *window;
2424 ModestMsgEditWindowPrivate *priv;
2429 case GTK_RESPONSE_OK:
2431 gchar *current_folder;
2433 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2434 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2435 if (current_folder && current_folder != '\0') {
2437 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2438 current_folder, &err);
2440 g_debug ("Error storing latest used folder: %s", err->message);
2444 g_free (current_folder);
2451 window = MODEST_MSG_EDIT_WINDOW (user_data);
2452 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2454 /* allowed size is the maximum size - what's already there */
2455 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2456 &att_num, &att_size);
2457 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2460 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2462 const gchar *uri = (const gchar *) uri_node->data;
2465 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2467 if (total_size > allowed_size) {
2468 g_debug ("%s: total size: %u",
2469 __FUNCTION__, (unsigned int)total_size);
2472 allowed_size -= total_size;
2474 g_slist_foreach (uris, (GFunc) g_free, NULL);
2475 g_slist_free (uris);
2477 gtk_widget_destroy (GTK_WIDGET (dialog));
2481 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2483 GtkWidget *dialog = NULL;
2484 ModestMsgEditWindowPrivate *priv;
2487 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2489 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2491 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2494 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2495 GTK_FILE_CHOOSER_ACTION_OPEN);
2496 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2497 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2498 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2499 if (conf_folder && conf_folder[0] != '\0') {
2500 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2503 /* Set the default folder to documents folder */
2504 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2507 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2508 ".documents", NULL);
2510 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2511 g_free (docs_folder);
2513 g_free (conf_folder);
2514 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2515 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2516 GTK_WINDOW (dialog), GTK_WINDOW (window));
2518 /* Connect to response & show */
2519 g_signal_connect (dialog, "response",
2520 G_CALLBACK (on_attach_file_response), window);
2521 gtk_widget_show (dialog);
2526 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2528 GnomeVFSFileSize allowed_size)
2531 GnomeVFSHandle *handle = NULL;
2532 ModestMsgEditWindowPrivate *priv;
2533 GnomeVFSResult result;
2534 GnomeVFSFileSize size = 0;
2535 g_return_val_if_fail (window, 0);
2536 g_return_val_if_fail (uri, 0);
2538 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2540 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2541 if (result == GNOME_VFS_OK) {
2542 TnyMimePart *mime_part;
2544 const gchar *mime_type = NULL;
2546 gchar *escaped_filename;
2549 GnomeVFSFileInfo *info;
2550 GnomeVFSURI *vfs_uri;
2552 gnome_vfs_close (handle);
2553 vfs_uri = gnome_vfs_uri_new (uri);
2556 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2557 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2558 g_free (escaped_filename);
2559 gnome_vfs_uri_unref (vfs_uri);
2561 info = gnome_vfs_file_info_new ();
2563 if (gnome_vfs_get_file_info (uri,
2565 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2567 mime_type = gnome_vfs_file_info_get_mime_type (info);
2568 mime_part = tny_platform_factory_new_mime_part
2569 (modest_runtime_get_platform_factory ());
2571 /* try to get the attachment's size; this may fail for weird
2572 * file systems, like obex, upnp... */
2573 if (allowed_size != 0 &&
2574 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2576 if (size > allowed_size) {
2577 modest_platform_information_banner (NULL, NULL,
2578 _("mail_ib_error_attachment_size"));
2583 g_debug ("%s: could not get attachment size", __FUNCTION__);
2585 stream = create_stream_for_uri (uri);
2587 if (stream == NULL) {
2589 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2591 g_object_unref (mime_part);
2593 gnome_vfs_file_info_unref (info);
2597 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2598 g_object_unref (stream);
2600 content_id = g_strdup_printf ("%d", priv->next_cid);
2601 tny_mime_part_set_content_id (mime_part, content_id);
2602 g_free (content_id);
2605 basename = g_path_get_basename (filename);
2606 tny_mime_part_set_filename (mime_part, basename);
2609 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2610 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2612 info->size == 0, info->size);
2613 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2614 gtk_widget_show_all (priv->attachments_caption);
2615 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2617 g_object_unref (mime_part);
2618 gnome_vfs_file_info_unref (info);
2625 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2628 ModestMsgEditWindowPrivate *priv;
2631 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2632 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2634 if (att_list == NULL) {
2635 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2636 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2637 g_object_unref (att_list);
2641 g_object_ref (att_list);
2644 if (tny_list_get_length (att_list) == 0) {
2645 modest_platform_system_banner (NULL, NULL, _("TODO: no attachments selected to remove"));
2647 gboolean dialog_response;
2648 gchar *message = NULL;
2649 gchar *filename = NULL;
2651 if (tny_list_get_length (att_list) == 1) {
2653 iter = tny_list_create_iterator (att_list);
2654 part = (TnyMimePart *) tny_iterator_get_current (iter);
2655 g_object_unref (iter);
2656 if (TNY_IS_MSG (part)) {
2657 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2659 filename = tny_header_dup_subject (header);
2660 g_object_unref (header);
2662 if (filename == NULL) {
2663 filename = g_strdup (_("mail_va_no_subject"));
2666 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2668 g_object_unref (part);
2670 filename = g_strdup ("");
2672 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2673 "emev_nc_delete_attachments",
2674 tny_list_get_length (att_list)), filename);
2677 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2681 if (dialog_response != GTK_RESPONSE_OK) {
2682 g_object_unref (att_list);
2686 for (iter = tny_list_create_iterator (att_list);
2687 !tny_iterator_is_done (iter);
2688 tny_iterator_next (iter)) {
2689 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2690 const gchar *att_id;
2691 tny_list_remove (priv->attachments, (GObject *) mime_part);
2693 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2695 if (tny_list_get_length (priv->attachments) == 0)
2696 gtk_widget_hide (priv->attachments_caption);
2697 att_id = tny_mime_part_get_content_id (mime_part);
2699 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2701 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2702 g_object_unref (mime_part);
2704 g_object_unref (iter);
2707 g_object_unref (att_list);
2709 /* if the last attachment has been removed, focus the Subject: field */
2710 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2711 gtk_widget_grab_focus (priv->subject_field);
2715 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2718 ModestMsgEditWindowPrivate *priv;
2721 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2723 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2725 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2727 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2731 font_size_clicked (GtkToolButton *button,
2732 ModestMsgEditWindow *window)
2734 ModestMsgEditWindowPrivate *priv;
2735 GtkWidget *selector, *dialog;
2737 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2739 selector = hildon_touch_selector_new ();
2740 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2741 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2743 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2744 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2745 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2747 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2751 WPTextBufferFormat format;
2753 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2755 memset (&format, 0, sizeof (format));
2756 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2758 format.cs.font_size = TRUE;
2759 format.cs.text_position = TRUE;
2760 format.cs.font = TRUE;
2761 format.font_size = new_index;
2762 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2764 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2765 GINT_TO_POINTER (new_index)))
2766 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2768 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2769 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2770 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2771 size_text, "</span>", NULL);
2773 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2777 gtk_widget_destroy (dialog);
2779 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2784 font_face_clicked (GtkToolButton *button,
2785 ModestMsgEditWindow *window)
2787 ModestMsgEditWindowPrivate *priv;
2788 GtkWidget *selector, *dialog;
2789 GtkCellRenderer *renderer;
2791 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2793 selector = hildon_touch_selector_new ();
2794 renderer = gtk_cell_renderer_text_new ();
2795 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2796 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2797 renderer, "family", 0, "text", 0, NULL);
2798 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2800 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2801 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2802 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2804 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2805 gint new_font_index;
2809 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2810 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2811 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2815 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2817 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2818 GINT_TO_POINTER(new_font_index)))
2819 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2821 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2822 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2824 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2828 gtk_tree_path_free (path);
2831 gtk_widget_destroy (dialog);
2833 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2838 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2841 ModestMsgEditWindowPrivate *priv = NULL;
2842 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2844 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2845 if (!priv->update_caption_visibility)
2848 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2850 gtk_widget_show (priv->cc_caption);
2852 gtk_widget_hide (priv->cc_caption);
2854 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2858 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2861 ModestMsgEditWindowPrivate *priv = NULL;
2862 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2864 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2865 if (!priv->update_caption_visibility)
2868 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2870 gtk_widget_show (priv->bcc_caption);
2872 gtk_widget_hide (priv->bcc_caption);
2874 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2878 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2879 ModestRecptEditor *editor)
2881 ModestMsgEditWindowPrivate *priv;
2883 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2884 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2886 /* we check for low-mem; in that case, show a warning, and don't allow
2887 * for the addressbook
2889 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2892 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2894 if (editor == NULL) {
2895 GtkWidget *view_focus, *parent;
2896 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2898 /* This code should be kept in sync with ModestRecptEditor. The
2899 textview inside the recpt editor is the one that really gets the
2900 focus. As it's inside a scrolled window, and this one inside the
2901 hbox recpt editor inherits from, we'll need to go up in the
2902 hierarchy to know if the text view is part of the recpt editor
2903 or if it's a different text entry */
2904 parent = gtk_widget_get_parent (view_focus);
2905 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2906 editor = MODEST_RECPT_EDITOR (parent);
2909 editor = MODEST_RECPT_EDITOR (priv->to_field);
2912 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2916 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2918 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2920 modest_msg_edit_window_open_addressbook (window, NULL);
2924 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2925 gboolean show_toolbar)
2927 ModestWindowPrivate *parent_priv;
2928 ModestMsgEditWindowPrivate *priv;
2930 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2931 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2932 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2934 /* We can not just use the code of
2935 modest_msg_edit_window_setup_toolbar because it has a
2936 mixture of both initialization and creation code. */
2938 gint current_format;
2939 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2940 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2941 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2942 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2944 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2947 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2952 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2953 TnyHeaderFlags priority_flags)
2955 ModestMsgEditWindowPrivate *priv;
2956 ModestWindowPrivate *parent_priv;
2958 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2960 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2961 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2963 if (priv->priority_flags != priority_flags) {
2964 GtkAction *priority_action = NULL;
2966 priv->priority_flags = priority_flags;
2968 switch (priority_flags) {
2969 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2970 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2971 MODEST_HEADER_ICON_HIGH,
2972 HILDON_ICON_SIZE_SMALL);
2973 gtk_widget_show (priv->priority_icon);
2974 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2975 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2977 case TNY_HEADER_FLAG_LOW_PRIORITY:
2978 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2979 MODEST_HEADER_ICON_LOW,
2980 HILDON_ICON_SIZE_SMALL);
2981 gtk_widget_show (priv->priority_icon);
2982 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2983 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2986 gtk_widget_hide (priv->priority_icon);
2987 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2988 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2991 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2992 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2994 gtk_widget_queue_resize (priv->subject_box);
2998 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3001 ModestMsgEditWindowPrivate *priv;
3002 ModestWindowPrivate *parent_priv;
3003 gint current_format;
3005 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3007 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3008 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3010 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3011 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3013 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3015 if (current_format != file_format) {
3016 switch (file_format) {
3017 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3018 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3019 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3020 if (parent_priv->toolbar)
3021 gtk_widget_show (parent_priv->toolbar);
3023 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3027 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3028 response = gtk_dialog_run (GTK_DIALOG (dialog));
3029 gtk_widget_destroy (dialog);
3030 if (response == GTK_RESPONSE_OK) {
3031 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3032 if (parent_priv->toolbar)
3033 gtk_widget_hide (parent_priv->toolbar);
3035 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3036 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3041 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3042 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3043 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3048 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3051 ModestMsgEditWindowPrivate *priv;
3052 WPTextBufferFormat oldfmt, fmt;
3053 gint old_position = 0;
3057 GdkColor *color = NULL;
3058 gboolean bold, bold_set, italic, italic_set;
3059 gboolean underline, underline_set;
3060 gboolean strikethrough, strikethrough_set;
3061 gboolean position_set;
3062 gboolean font_size_set, font_set, color_set;
3065 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3066 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3068 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3069 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3070 GTK_WINDOW(dialog), GTK_WINDOW (window));
3072 /* First we get the currently selected font information */
3073 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3075 switch (oldfmt.text_position) {
3076 case TEXT_POSITION_NORMAL:
3079 case TEXT_POSITION_SUPERSCRIPT:
3087 g_object_set (G_OBJECT (dialog),
3088 "bold", oldfmt.bold != FALSE,
3089 "bold-set", !oldfmt.cs.bold,
3090 "underline", oldfmt.underline != FALSE,
3091 "underline-set", !oldfmt.cs.underline,
3092 "italic", oldfmt.italic != FALSE,
3093 "italic-set", !oldfmt.cs.italic,
3094 "strikethrough", oldfmt.strikethrough != FALSE,
3095 "strikethrough-set", !oldfmt.cs.strikethrough,
3096 "color", &oldfmt.color,
3097 "color-set", !oldfmt.cs.color,
3098 "size", wp_font_size[oldfmt.font_size],
3099 "size-set", !oldfmt.cs.font_size,
3100 "position", old_position,
3101 "position-set", !oldfmt.cs.text_position,
3102 "family", wp_get_font_name (oldfmt.font),
3103 "family-set", !oldfmt.cs.font,
3106 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3107 GTK_WINDOW (dialog), GTK_WINDOW (window));
3108 gtk_widget_show_all (dialog);
3109 priv->font_dialog = dialog;
3110 response = gtk_dialog_run (GTK_DIALOG (dialog));
3111 priv->font_dialog = NULL;
3112 if (response == GTK_RESPONSE_OK) {
3114 g_object_get( dialog,
3116 "bold-set", &bold_set,
3117 "underline", &underline,
3118 "underline-set", &underline_set,
3120 "italic-set", &italic_set,
3121 "strikethrough", &strikethrough,
3122 "strikethrough-set", &strikethrough_set,
3124 "color-set", &color_set,
3126 "size-set", &font_size_set,
3127 "family", &font_name,
3128 "family-set", &font_set,
3129 "position", &position,
3130 "position-set", &position_set,
3135 if (response == GTK_RESPONSE_OK) {
3136 memset(&fmt, 0, sizeof(fmt));
3142 fmt.italic = italic;
3143 fmt.cs.italic = TRUE;
3145 if (underline_set) {
3146 fmt.underline = underline;
3147 fmt.cs.underline = TRUE;
3149 if (strikethrough_set) {
3150 fmt.strikethrough = strikethrough;
3151 fmt.cs.strikethrough = TRUE;
3156 ? TEXT_POSITION_NORMAL
3157 : ( ( position == 1 )
3158 ? TEXT_POSITION_SUPERSCRIPT
3159 : TEXT_POSITION_SUBSCRIPT );
3160 fmt.cs.text_position = TRUE;
3161 fmt.font_size = oldfmt.font_size;
3165 fmt.cs.color = TRUE;
3168 fmt.font = wp_get_font_index(font_name,
3173 if (font_size_set) {
3174 fmt.cs.font_size = TRUE;
3175 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3177 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3178 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3180 gtk_widget_destroy (dialog);
3182 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3186 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3188 ModestMsgEditWindowPrivate *priv;
3189 ModestWindowPrivate *parent_priv;
3190 gboolean was_rich_text, is_rich_text;
3192 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3193 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3194 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3196 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3198 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3200 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3202 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3204 gtk_widget_show (parent_priv->toolbar);
3206 gtk_widget_hide (parent_priv->toolbar);
3209 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3210 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3214 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3216 ModestMsgEditWindowPrivate *priv;
3218 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3219 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3221 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3223 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3224 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3229 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3231 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3233 priv->can_undo = can_undo;
3237 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3239 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3241 priv->can_redo = can_redo;
3245 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3247 ModestMsgEditWindowPrivate *priv;
3248 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3249 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3251 return priv->can_undo;
3255 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3257 ModestMsgEditWindowPrivate *priv;
3258 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3259 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3261 return priv->can_redo;
3266 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3269 GtkTextIter match_start, match_end;
3271 if (image_id == NULL)
3274 gtk_text_buffer_get_start_iter (buffer, &iter);
3276 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3277 GSList *tags = gtk_text_iter_get_tags (&match_start);
3279 for (node = tags; node != NULL; node = g_slist_next (node)) {
3280 GtkTextTag *tag = (GtkTextTag *) node->data;
3281 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3282 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3283 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3285 offset = gtk_text_iter_get_offset (&match_start);
3286 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3287 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3291 gtk_text_iter_forward_char (&iter);
3296 message_is_empty (ModestMsgEditWindow *window)
3298 ModestMsgEditWindowPrivate *priv = NULL;
3300 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3301 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3303 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3304 * so we can ignore markup.
3306 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3309 count = gtk_text_buffer_get_char_count (buf);
3315 msg_body_focus (GtkWidget *focus,
3316 GdkEventFocus *event,
3320 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3321 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3322 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3327 recpt_field_changed (GtkTextBuffer *buffer,
3328 ModestMsgEditWindow *editor)
3330 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3331 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3335 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3337 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3338 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3342 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3345 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3346 GtkTextBuffer *buffer;
3348 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3349 gtk_text_buffer_set_modified (buffer, modified);
3350 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3351 gtk_text_buffer_set_modified (buffer, modified);
3352 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3353 gtk_text_buffer_set_modified (buffer, modified);
3354 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3358 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3360 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3361 const char *account_name;
3362 GtkTextBuffer *buffer;
3364 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3365 if (gtk_text_buffer_get_modified (buffer))
3367 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3368 if (gtk_text_buffer_get_modified (buffer))
3370 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3371 if (gtk_text_buffer_get_modified (buffer))
3373 if (gtk_text_buffer_get_modified (priv->text_buffer))
3376 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3377 if (priv->original_mailbox) {
3378 if (!account_name || strcmp (account_name, priv->original_mailbox))
3380 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3391 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3393 ModestMsgEditWindowPrivate *priv = NULL;
3394 GSList *address_list = NULL;
3396 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3397 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3399 /* check if there's no recipient added */
3400 if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3401 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3402 (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3403 /* no recipient contents, then select contacts */
3404 modest_msg_edit_window_open_addressbook (window, NULL);
3409 g_object_ref (window);
3410 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3411 (add_to_addressbook) ? &address_list : NULL)) {
3412 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3413 g_object_unref (window);
3416 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3417 (add_to_addressbook) ? &address_list : NULL)) {
3418 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3419 g_object_unref (window);
3422 if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3423 (add_to_addressbook) ? &address_list : NULL)) {
3424 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3425 g_object_unref (window);
3429 /* Add contacts to address book */
3430 if (add_to_addressbook && address_list)
3431 modest_address_book_add_address_list (address_list);
3433 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3434 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3435 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3436 g_object_unref (window);
3443 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3445 GSList *recipients = NULL;
3446 ModestMsgEditWindowPrivate *priv;
3447 gchar *joined, *after_remove, *to, *cc, *bcc;
3449 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3451 /* First of all check names */
3452 if (!modest_msg_edit_window_check_names (self, FALSE))
3455 if (!modest_msg_edit_window_has_pending_addresses (self))
3458 /* Don't add the from obviously */
3459 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3460 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3461 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3463 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3468 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3471 recipients = modest_text_utils_split_addresses_list (after_remove);
3472 g_free (after_remove);
3475 /* Offer the user to add recipients to the address book */
3476 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3477 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3482 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3483 ModestMsgEditWindow *window)
3485 modest_msg_edit_window_offer_attach_file (window);
3489 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3491 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3493 return priv->clipboard_text;
3497 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3499 ModestMsgEditWindow *window)
3501 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3502 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3505 /* It could happen that the window was already closed */
3506 if (!GTK_WIDGET_VISIBLE (window))
3509 g_object_ref (window);
3510 text = gtk_clipboard_wait_for_text (selection_clipboard);
3512 if (priv->clipboard_text != NULL) {
3513 g_free (priv->clipboard_text);
3515 priv->clipboard_text = text;
3517 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3519 g_object_unref (window);
3522 static gboolean clipboard_owner_change_idle (gpointer userdata)
3524 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3525 ModestMsgEditWindowPrivate *priv;
3527 gdk_threads_enter ();
3528 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3529 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3531 priv->clipboard_owner_idle = 0;
3532 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3533 gdk_threads_leave ();
3539 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3541 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3542 if (priv->clipboard_owner_idle == 0) {
3543 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3544 clipboard_owner_change_idle,
3545 g_object_ref (window),
3551 subject_field_move_cursor (GtkEntry *entry,
3552 GtkMovementStep step,
3557 /* It could happen that the window was already closed */
3558 if (!GTK_WIDGET_VISIBLE (window))
3561 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3565 update_window_title (ModestMsgEditWindow *window)
3567 ModestMsgEditWindowPrivate *priv = NULL;
3568 const gchar *subject;
3570 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3571 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3572 if (subject == NULL || subject[0] == '\0')
3573 subject = _("mail_va_new_email");
3575 modest_window_set_title (MODEST_WINDOW (window), subject);
3581 body_insert_text (GtkTextBuffer *buffer,
3582 GtkTextIter *location,
3585 ModestMsgEditWindow *window)
3587 GtkTextIter end_iter;
3594 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3596 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3598 offset = gtk_text_iter_get_offset (&end_iter);
3599 line = gtk_text_iter_get_line (&end_iter);
3603 while (text_offset < text + len) {
3604 if (*text_offset == '\n')
3606 if (text_lines + line >= MAX_BODY_LINES) {
3607 len = text_offset - text;
3613 utf8_len = g_utf8_strlen (text, len);
3615 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3616 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3617 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3622 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3624 /* Prevent endless recursion */
3625 result = g_strndup (text, utf8_end - text);
3626 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3627 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3628 (gpointer) result, (gpointer) (utf8_end - text),
3630 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3634 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3635 if (priv->max_chars_banner == NULL) {
3636 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3637 _CS("ckdg_ib_maximum_characters_reached"));
3638 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3644 subject_field_changed (GtkEditable *editable,
3645 ModestMsgEditWindow *window)
3647 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3648 update_window_title (window);
3649 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3650 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3651 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3654 subject_field_insert_text (GtkEditable *editable,
3656 gint new_text_length,
3658 ModestMsgEditWindow *window)
3660 GString *result = g_string_new ("");
3662 gint result_len = 0;
3663 const gchar *entry_text = NULL;
3666 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3667 old_length = g_utf8_strlen (entry_text, -1);
3669 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3670 gunichar c = g_utf8_get_char_validated (current, 8);
3671 /* Invalid unichar, stop */
3677 result = g_string_append_unichar (result, c);
3681 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3682 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3685 /* Prevent endless recursion */
3686 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3687 g_signal_emit_by_name (editable, "insert-text",
3688 (gpointer) result->str, (gpointer) result->len,
3689 (gpointer) position, (gpointer) window);
3690 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3694 if (result_len + old_length > 1000) {
3695 modest_platform_system_banner (GTK_WIDGET (window), NULL,
3696 _CS("ckdg_ib_maximum_characters_reached"));
3698 g_string_free (result, TRUE);
3702 modest_msg_edit_window_toggle_isearch_toolbar (ModestMsgEditWindow *window,
3705 ModestMsgEditWindowPrivate *priv = NULL;
3707 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3708 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3710 gtk_widget_set_no_show_all (priv->isearch_toolbar, FALSE);
3713 gtk_widget_show_all (priv->isearch_toolbar);
3714 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
3716 gtk_widget_hide_all (priv->isearch_toolbar);
3717 gtk_widget_grab_focus (priv->msg_body);
3722 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3724 GtkTextIter *match_start,
3725 GtkTextIter *match_end)
3727 GtkTextIter end_iter;
3728 gchar *str_casefold;
3731 gchar *range_casefold;
3734 gboolean result = FALSE;
3741 gtk_text_iter_forward_to_end (&end_iter);
3743 str_casefold = g_utf8_casefold (str, -1);
3744 str_chars_n = strlen (str);
3746 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3747 range_casefold = g_utf8_casefold (range_text, -1);
3748 range_chars_n = strlen (range_casefold);
3750 if (range_chars_n < str_chars_n) {
3751 g_free (str_casefold);
3752 g_free (range_text);
3753 g_free (range_casefold);
3757 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3758 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3759 if (!g_utf8_collate (range_subtext, str_casefold)) {
3760 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3762 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3763 match_start, match_end, NULL)) {
3764 g_debug ("Matched string with collate, but not matched in model");
3766 g_free (found_text);
3768 g_free (range_subtext);
3772 g_free (str_casefold);
3773 g_free (range_text);
3774 g_free (range_casefold);
3781 modest_msg_edit_window_isearch_toolbar_search (GtkWidget *widget,
3782 ModestMsgEditWindow *window)
3784 const gchar *current_search = NULL;
3785 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3787 GtkTextIter selection_start, selection_end;
3788 GtkTextIter match_start, match_end;
3789 gboolean continue_search = FALSE;
3791 if (message_is_empty (window)) {
3792 g_free (priv->last_search);
3793 priv->last_search = NULL;
3794 modest_platform_system_banner (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3798 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
3799 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3800 g_free (priv->last_search);
3801 priv->last_search = NULL;
3802 /* Information banner about empty search */
3803 modest_platform_system_banner (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3807 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3808 continue_search = TRUE;
3810 g_free (priv->last_search);
3811 priv->last_search = g_strdup (current_search);
3814 if (continue_search) {
3815 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3816 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3817 &match_start, &match_end);
3819 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3821 GtkTextIter buffer_start;
3822 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3823 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3824 &match_start, &match_end);
3826 modest_platform_system_banner (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3829 /* Mark as selected the string found in search */
3831 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3832 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3833 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3835 g_free (priv->last_search);
3836 priv->last_search = NULL;
3841 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3843 ModestMsgEditWindowPrivate *priv;
3845 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3850 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3853 ModestMsgEditWindowPrivate *priv;
3855 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3860 modest_msg_edit_window_isearch_toolbar_close (GtkWidget *widget,
3861 ModestMsgEditWindow *window)
3863 modest_msg_edit_window_toggle_isearch_toolbar (window, FALSE);
3867 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3870 ModestMsgEditWindowPrivate *priv;
3871 TnyHeader *header = NULL;
3873 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3874 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3876 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3878 if (priv->draft_msg != NULL) {
3879 g_object_unref (priv->draft_msg);
3882 if (draft != NULL) {
3883 g_object_ref (draft);
3884 header = tny_msg_get_header (draft);
3885 if (priv->msg_uid) {
3886 g_free (priv->msg_uid);
3887 priv->msg_uid = NULL;
3889 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3892 priv->draft_msg = draft;
3896 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3897 GtkTextIter *start, GtkTextIter *end,
3900 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3901 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3904 if (tag == NULL) return;
3905 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3906 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3907 replace_with_images (window, priv->images);
3912 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3915 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3917 g_return_if_fail (TNY_IS_MIME_PART (part));
3918 tny_list_prepend (priv->attachments, (GObject *) part);
3919 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3920 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3921 gtk_widget_show_all (priv->attachments_caption);
3922 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3926 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3928 ModestMsgEditWindowPrivate *priv;
3930 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3931 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3933 return priv->msg_uid;
3937 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3938 ModestMsgEditWindowWidgetType widget_type)
3940 ModestMsgEditWindowPrivate *priv;
3942 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3943 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3945 switch (widget_type) {
3946 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3947 return priv->msg_body;
3949 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3950 return priv->to_field;
3952 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3953 return priv->cc_field;
3955 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3956 return priv->bcc_field;
3958 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3959 return priv->subject_field;
3961 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3962 return priv->attachments_view;
3970 remove_tags (WPTextBuffer *buffer)
3972 GtkTextIter start, end;
3974 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3975 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3977 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3981 on_account_removed (TnyAccountStore *account_store,
3982 TnyAccount *account,
3985 /* Do nothing if it's a store account, because we use the
3986 transport to send the messages */
3987 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3988 const gchar *parent_acc = NULL;
3989 const gchar *our_acc = NULL;
3991 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3992 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3993 /* Close this window if I'm showing a message of the removed account */
3994 if (strcmp (parent_acc, our_acc) == 0)
3995 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4000 update_signature (ModestMsgEditWindow *self,
4001 const gchar *old_account,
4002 const gchar *new_account)
4004 ModestMsgEditWindowPrivate *priv;
4005 gboolean has_old_signature, has_new_signature;
4007 ModestAccountMgr *mgr;
4010 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4012 gtk_text_buffer_begin_user_action (priv->text_buffer);
4014 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4015 mgr = modest_runtime_get_account_mgr ();
4019 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4020 if (has_old_signature) {
4021 GtkTextIter match_start, match_end;
4023 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4024 seems that the search has some problems
4025 with the blank space at the end */
4026 if (gtk_text_iter_forward_search (&iter, "--",
4027 GTK_TEXT_SEARCH_TEXT_ONLY,
4028 &match_start, NULL, NULL)) {
4029 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4030 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4032 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4033 &match_start, &match_end, NULL)) {
4037 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4042 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4043 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4044 if (has_new_signature) {
4046 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4047 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4049 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4050 g_free (full_signature);
4053 gtk_text_buffer_end_user_action (priv->text_buffer);
4056 static void update_branding (ModestMsgEditWindow *self,
4057 const gchar *new_account)
4059 ModestMsgEditWindowPrivate *priv;
4060 ModestAccountMgr *mgr;
4061 const GdkPixbuf *new_icon = NULL;
4062 gchar *new_label = NULL;
4063 gboolean show = FALSE;
4065 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4067 mgr = modest_runtime_get_account_mgr ();
4069 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4071 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4072 gtk_widget_show (priv->brand_icon);
4075 gtk_widget_hide (priv->brand_icon);
4078 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4079 gtk_widget_show (priv->brand_label);
4083 gtk_widget_hide (priv->brand_label);
4087 gtk_widget_show (priv->brand_container);
4089 gtk_widget_hide (priv->brand_container);
4093 from_field_changed (HildonPickerButton *button,
4094 ModestMsgEditWindow *self)
4096 ModestMsgEditWindowPrivate *priv;
4097 gchar *old_account, *new_account;
4099 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4101 old_account = priv->last_from_account;
4102 new_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4105 g_warning ("%s, could not get the new account", __FUNCTION__);
4109 /* If the From is the same do nothing */
4110 if (old_account && new_account && !strcmp (old_account, new_account))
4113 priv->last_from_account = new_account;
4115 update_signature (self, old_account, new_account);
4116 update_branding (self, new_account);
4120 typedef struct _MessageSettingsHelper {
4121 ModestMsgEditWindow *window;
4122 GSList *priority_group;
4123 GSList *format_group;
4124 GtkToggleButton *current_priority;
4125 GtkToggleButton *current_format;
4126 } MessageSettingsHelper;
4129 on_priority_toggle (GtkToggleButton *button,
4130 MessageSettingsHelper *helper)
4133 ModestMsgEditWindowPrivate *priv;
4135 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4136 if (gtk_toggle_button_get_active (button)) {
4138 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4139 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4140 if ((node_button != button) &&
4141 gtk_toggle_button_get_active (node_button)) {
4142 gtk_toggle_button_set_active (node_button, FALSE);
4145 helper->current_priority = button;
4147 gboolean found = FALSE;
4148 /* If no one is active, activate it again */
4149 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4150 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4151 if (gtk_toggle_button_get_active (node_button)) {
4157 gtk_toggle_button_set_active (button, TRUE);
4163 on_format_toggle (GtkToggleButton *button,
4164 MessageSettingsHelper *helper)
4167 ModestMsgEditWindowPrivate *priv;
4169 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4170 if (gtk_toggle_button_get_active (button)) {
4172 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4173 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4174 if ((node_button != button) &&
4175 gtk_toggle_button_get_active (node_button)) {
4176 gtk_toggle_button_set_active (node_button, FALSE);
4179 helper->current_format = button;
4181 gboolean found = FALSE;
4182 /* If no one is active, activate it again */
4183 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4184 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4185 if (gtk_toggle_button_get_active (node_button)) {
4191 gtk_toggle_button_set_active (button, TRUE);
4198 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4203 GtkWidget *priority_hbox;
4204 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4205 GtkWidget *captioned;
4206 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4207 GtkWidget *format_hbox;
4208 GtkWidget *html_toggle, *text_toggle;
4209 ModestMsgEditWindowPrivate *priv;
4210 MessageSettingsHelper helper = {0,};
4212 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4213 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4214 helper.window = window;
4215 helper.priority_group = NULL;
4216 helper.format_group = NULL;
4218 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4219 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4221 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4222 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4223 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4224 vbox = gtk_vbox_new (FALSE, 0);
4225 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4226 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4227 gtk_container_add (GTK_CONTAINER (align), vbox);
4228 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4229 gtk_widget_show (align);
4230 gtk_widget_show (vbox);
4232 /* Priority toggles */
4233 priority_hbox = gtk_hbox_new (TRUE, 0);
4234 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4235 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4236 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4237 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4238 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4239 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4240 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4241 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4242 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4243 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4244 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4245 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4246 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4247 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4248 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4249 gtk_widget_show_all (priority_hbox);
4250 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4251 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4252 gtk_widget_show (captioned);
4253 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4255 /* format toggles */
4256 format_hbox = gtk_hbox_new (TRUE, 0);
4257 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4258 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4259 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4260 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4261 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4262 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4263 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4264 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4265 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4266 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4267 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4268 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4269 gtk_widget_show_all (format_hbox);
4270 gtk_widget_show (format_hbox);
4271 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4274 g_object_unref (title_sizegroup);
4275 g_object_unref (value_sizegroup);
4277 /* Set current values */
4278 switch (priv->priority_flags) {
4279 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4280 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4281 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4283 case TNY_HEADER_FLAG_LOW_PRIORITY:
4284 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4285 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4288 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4289 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4293 switch (modest_msg_edit_window_get_format (window)) {
4294 case MODEST_MSG_EDIT_FORMAT_TEXT:
4295 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4296 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4298 case MODEST_MSG_EDIT_FORMAT_HTML:
4300 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4301 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4305 /* Signal connects */
4306 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4307 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4308 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4309 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4310 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4312 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4313 GTK_WINDOW (dialog), GTK_WINDOW (window));
4315 /* Save settings if the user clicked on done */
4316 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4317 TnyHeaderFlags flags;
4318 ModestMsgEditFormat old_format, new_format;
4320 /* Set priority flags */
4321 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4322 if (priv->priority_flags != flags)
4323 modest_msg_edit_window_set_priority_flags (window, flags);
4325 /* Set edit format */
4326 old_format = modest_msg_edit_window_get_format (window);
4327 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4328 if (old_format != new_format) {
4329 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4330 modest_msg_edit_window_set_file_format (window, file_format);
4334 gtk_widget_destroy (dialog);
4335 g_slist_free (helper.priority_group);
4339 on_message_settings (GtkAction *action,
4340 ModestMsgEditWindow *window)
4342 modest_msg_edit_window_show_msg_settings_dialog (window);
4346 on_cc_button_toggled (GtkWidget *button,
4347 ModestMsgEditWindow *window)
4349 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4351 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4352 modest_togglable_get_active (button));
4356 on_bcc_button_toggled (GtkWidget *button,
4357 ModestMsgEditWindow *window)
4359 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4361 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4362 modest_togglable_get_active (button));
4366 setup_menu (ModestMsgEditWindow *self)
4368 ModestMsgEditWindowPrivate *priv = NULL;
4370 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4372 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4374 /* Settings menu buttons */
4375 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4376 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_check_names),
4378 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4379 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4380 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4381 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4382 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_undo),
4383 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4385 priv->cc_button = hildon_check_button_new (0);
4386 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4387 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4389 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->cc_button, NULL);
4390 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4391 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4393 priv->bcc_button = modest_toolkit_factory_create_check_menu (modest_runtime_get_toolkit_factory (),
4394 _("mcen_me_editor_showbcc"));
4395 modest_togglable_set_active (priv->bcc_button,
4397 modest_window_add_item_to_menu (MODEST_WINDOW (self), priv->bcc_button,
4399 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4400 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4402 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4403 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4404 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4405 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4406 MODEST_WINDOW_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4408 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4409 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4410 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4411 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_message_settings"), NULL,
4412 MODEST_WINDOW_MENU_CALLBACK (on_message_settings),
4414 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4415 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4420 emit_open_addressbook (GtkButton *button,
4421 ModestRecptEditor *editor)
4423 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4427 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4428 const gchar *label, GtkWidget *control)
4430 GtkWidget *abook_button;
4433 GtkWidget *label_widget;
4435 box = gtk_hbox_new (FALSE, 0);
4437 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4438 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4440 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4441 label_widget = gtk_label_new (label);
4442 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4443 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4445 gtk_container_add (GTK_CONTAINER (align), abook_button);
4446 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4447 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4448 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4449 if (title_size_group)
4450 gtk_size_group_add_widget (title_size_group, label_widget);
4451 if (value_size_group)
4452 gtk_size_group_add_widget (value_size_group, control);
4454 g_signal_connect (G_OBJECT (abook_button), "clicked",
4455 G_CALLBACK (emit_open_addressbook), control);
4461 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4463 ModestMsgEditWindowPrivate *priv = NULL;
4465 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4467 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4468 priv->max_chars_banner = NULL;
4472 has_pending_addresses (ModestRecptEditor *recpt_editor)
4474 const gchar *recipients = NULL;
4475 GSList *start_indexes = NULL, *end_indexes = NULL;
4476 GSList *current_start, *current_end;
4477 GtkTextBuffer *buffer;
4478 gint offset_delta = 0;
4480 gboolean has_recipients_to_add = FALSE;
4482 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4483 last_length = g_utf8_strlen (recipients, -1);
4484 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4489 current_start = start_indexes;
4490 current_end = end_indexes;
4491 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4493 while (current_start && !has_recipients_to_add) {
4495 gchar *start_ptr, *end_ptr;
4496 gint start_pos, end_pos;
4498 start_pos = (*((gint*) current_start->data)) + offset_delta;
4499 end_pos = (*((gint*) current_end->data)) + offset_delta;
4501 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4502 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4504 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4506 if (modest_text_utils_validate_recipient (address, NULL)) {
4507 if (!modest_address_book_has_address (address)) {
4508 has_recipients_to_add = TRUE;
4511 current_start = g_slist_next (current_start);
4512 current_end = g_slist_next (current_end);
4514 return has_recipients_to_add;
4518 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4520 ModestMsgEditWindowPrivate *priv = NULL;
4522 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4524 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4526 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4527 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4528 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))