1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <glib/gstdio.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38 #include <tny-camel-mem-stream.h>
39 #include <modest-account-protocol.h>
43 #include <modest-account-mgr.h>
44 #include <modest-account-mgr-helpers.h>
46 #include <widgets/modest-msg-edit-window.h>
47 #include <modest-selector-picker.h>
48 #include <widgets/modest-recpt-editor.h>
49 #include <widgets/modest-attachments-view.h>
51 #include <modest-runtime.h>
53 #include "modest-platform.h"
54 #include "modest-icon-names.h"
55 #include "modest-widget-memory.h"
56 #include "modest-window-priv.h"
57 #include "modest-mail-operation.h"
58 #include "modest-tny-platform-factory.h"
59 #include "modest-tny-msg.h"
60 #include "modest-tny-folder.h"
61 #include "modest-tny-account.h"
62 #include "modest-address-book.h"
63 #include "modest-text-utils.h"
64 #include <tny-simple-list.h>
65 #include <modest-wp-text-view.h>
66 #include <wptextbuffer.h>
67 #include <hildon/hildon-pannable-area.h>
68 #include <hildon/hildon-touch-selector.h>
69 #include <hildon/hildon-picker-dialog.h>
70 #include "modest-msg-edit-window-ui-dimming.h"
72 #include "modest-hildon-includes.h"
73 #include "widgets/modest-msg-edit-window-ui.h"
74 #include <libgnomevfs/gnome-vfs-mime.h>
75 #include <modest-utils.h>
76 #include "modest-maemo-utils.h"
77 #include <modest-ui-constants.h>
78 #include "modest-color-button.h"
80 #ifdef MODEST_USE_CALENDAR_WIDGETS
81 #include <calendar-ui-widgets.h>
84 #define DEFAULT_FONT_SIZE 3
85 #define DEFAULT_FONT 2
86 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
87 #define DEFAULT_MAIN_VBOX_SPACING 0
88 #define SUBJECT_MAX_LENGTH 1000
89 #define IMAGE_MAX_WIDTH 560
90 #define DEFAULT_FONT_SCALE 1.5
91 #define ATTACHMENT_BUTTON_WIDTH 118
92 #define MAX_FROM_VALUE 36
93 #define MAX_BODY_LENGTH 128*1024
94 #define MAX_BODY_LINES 2048
96 static gboolean is_wp_text_buffer_started = FALSE;
98 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass);
99 static void modest_msg_edit_window_init (ModestMsgEditWindow *obj);
100 static void modest_msg_edit_window_finalize (GObject *obj);
102 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
103 static void body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
104 static void recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
106 static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
107 static void text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
108 static void text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
109 static void text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
110 GtkTextIter *start, GtkTextIter *end,
112 static void text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
113 static void body_insert_text (GtkTextBuffer *buffer,
114 GtkTextIter *location,
117 ModestMsgEditWindow *window);
118 static void subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
119 static void subject_field_insert_text (GtkEditable *editable,
121 gint new_text_length,
123 ModestMsgEditWindow *window);
124 static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
126 static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
128 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
129 ModestRecptEditor *editor);
130 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
131 ModestMsgEditWindow *window);
133 /* ModestWindow methods implementation */
134 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
135 static void modest_msg_edit_window_show_toolbar (ModestWindow *window,
136 gboolean show_toolbar);
137 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
139 ModestMsgEditWindow *window);
140 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
141 static void subject_field_move_cursor (GtkEntry *entry,
142 GtkMovementStep step,
146 static void update_window_title (ModestMsgEditWindow *window);
149 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
150 ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
152 ModestMsgEditWindow *window);
153 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
155 GtkTextIter *match_start,
156 GtkTextIter *match_end);
158 static void remove_tags (WPTextBuffer *buffer);
160 static void on_account_removed (TnyAccountStore *account_store,
164 static void init_window (ModestMsgEditWindow *obj);
166 gboolean scroll_drag_timeout (gpointer userdata);
167 static void correct_scroll (ModestMsgEditWindow *w);
168 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
169 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
170 ModestMsgEditWindow *userdata);
171 static void text_buffer_mark_set (GtkTextBuffer *buffer,
174 ModestMsgEditWindow *userdata);
175 static void on_show_toolbar_button_toggled (HildonCheckButton *button,
176 ModestMsgEditWindow *window);
177 static void on_message_settings (GtkAction *action,
178 ModestMsgEditWindow *window);
179 static void setup_menu (ModestMsgEditWindow *self);
181 static void from_field_changed (HildonPickerButton *button,
182 ModestMsgEditWindow *self);
183 static void font_size_clicked (GtkToolButton *button,
184 ModestMsgEditWindow *window);
185 static void font_face_clicked (GtkToolButton *button,
186 ModestMsgEditWindow *window);
187 static void update_signature (ModestMsgEditWindow *self,
188 const gchar *old_account,
189 const gchar *new_account);
190 static void update_branding (ModestMsgEditWindow *self,
191 const gchar *new_account);
192 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
193 const gchar *label, GtkWidget *control);
194 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
195 static void DEBUG_BUFFER (WPTextBuffer *buffer)
199 g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
201 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
202 while (!gtk_text_iter_is_end (&iter)) {
203 GString *output = g_string_new ("");
204 GSList *toggled_tags;
207 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
208 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
209 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
210 GtkTextTag *tag = (GtkTextTag *) node->data;
212 g_object_get (G_OBJECT (tag), "name", &name, NULL);
213 output = g_string_append (output, name);
214 g_string_append (output, " ");
216 output = g_string_append (output, "] OPENED [ ");
217 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
218 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
219 GtkTextTag *tag = (GtkTextTag *) node->data;
221 g_object_get (G_OBJECT (tag), "name", &name, NULL);
222 output = g_string_append (output, name);
223 g_string_append (output, " ");
225 output = g_string_append (output, "]\n");
226 g_debug ("%s", output->str);
227 g_string_free (output, TRUE);
228 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
230 g_debug ("END BUFFER");
234 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
235 { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
239 /* static gboolean */
240 /* on_key_pressed (GtkWidget *self, */
241 /* GdkEventKey *event, */
242 /* gpointer user_data); */
244 /* list my signals */
251 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
252 struct _ModestMsgEditWindowPrivate {
254 GtkWidget *header_box;
256 ModestPairList *from_field_protos;
257 GtkWidget *from_field;
258 gchar *last_from_account;
259 gchar *original_account_name;
264 gchar *original_mailbox;
268 GtkWidget *bcc_field;
269 GtkWidget *subject_field;
270 GtkWidget *attachments_view;
271 GtkWidget *priority_icon;
272 GtkWidget *subject_box;
273 GtkWidget *send_button;
275 GtkWidget *cc_caption;
276 GtkWidget *bcc_caption;
277 gboolean update_caption_visibility;
278 GtkWidget *attachments_caption;
280 GtkTextBuffer *text_buffer;
282 GtkWidget *font_size_toolitem;
283 GtkWidget *font_face_toolitem;
284 GtkWidget *font_color_button;
285 GtkWidget *font_color_toolitem;
286 GSList *font_items_group;
287 GtkTreeModel *faces_model;
288 gint current_face_index;
289 GtkWidget *font_tool_button_label;
290 GtkTreeModel *sizes_model;
291 gint current_size_index;
292 GtkWidget *size_tool_button_label;
294 GtkWidget *find_toolbar;
297 GtkWidget *font_dialog;
300 guint correct_scroll_idle;
301 guint scroll_drag_timeout_id;
305 TnyList *attachments;
310 TnyHeaderFlags priority_flags;
312 gboolean can_undo, can_redo;
313 gulong clipboard_change_handler_id;
314 gulong default_clipboard_change_handler_id;
315 gulong account_removed_handler_id;
316 guint clipboard_owner_idle;
317 gchar *clipboard_text;
326 GtkWidget *cc_button;
327 GtkWidget *bcc_button;
328 GtkWidget *show_toolbar_button;
330 GtkWidget *max_chars_banner;
332 GtkWidget *brand_icon;
333 GtkWidget *brand_label;
334 GtkWidget *brand_container;
337 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
338 MODEST_TYPE_MSG_EDIT_WINDOW, \
339 ModestMsgEditWindowPrivate))
341 static GtkWindowClass *parent_class = NULL;
343 /* uncomment the following if you have defined any signals */
344 /* static guint signals[LAST_SIGNAL] = {0}; */
347 modest_msg_edit_window_get_type (void)
349 static GType my_type = 0;
351 static const GTypeInfo my_info = {
352 sizeof(ModestMsgEditWindowClass),
353 NULL, /* base init */
354 NULL, /* base finalize */
355 (GClassInitFunc) modest_msg_edit_window_class_init,
356 NULL, /* class finalize */
357 NULL, /* class data */
358 sizeof(ModestMsgEditWindow),
360 (GInstanceInitFunc) modest_msg_edit_window_init,
363 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
364 "ModestMsgEditWindow",
372 save_state (ModestWindow *self)
374 modest_widget_memory_save (modest_runtime_get_conf(),
375 G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
380 restore_settings (ModestMsgEditWindow *self)
382 ModestConf *conf = NULL;
384 conf = modest_runtime_get_conf ();
386 /* Dim at start clipboard actions */
387 modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
392 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
394 GObjectClass *gobject_class;
395 ModestWindowClass *modest_window_class;
396 gobject_class = (GObjectClass*) klass;
397 modest_window_class = (ModestWindowClass*) klass;
399 parent_class = g_type_class_peek_parent (klass);
400 gobject_class->finalize = modest_msg_edit_window_finalize;
402 modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
403 modest_window_class->save_state_func = save_state;
404 modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
406 g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
410 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
412 ModestMsgEditWindowPrivate *priv;
413 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
415 priv->msg_body = NULL;
416 priv->from_field = NULL;
417 priv->to_field = NULL;
418 priv->cc_field = NULL;
419 priv->bcc_field = NULL;
420 priv->subject_field = NULL;
421 priv->attachments = TNY_LIST (tny_simple_list_new ());
422 priv->images = TNY_LIST (tny_simple_list_new ());
423 priv->images_size = 0;
424 priv->images_count = 0;
427 priv->cc_caption = NULL;
428 priv->bcc_caption = NULL;
429 priv->update_caption_visibility = FALSE;
431 priv->priority_flags = 0;
433 priv->find_toolbar = NULL;
434 priv->last_search = NULL;
436 priv->draft_msg = NULL;
437 priv->outbox_msg = NULL;
438 priv->msg_uid = NULL;
440 priv->can_undo = FALSE;
441 priv->can_redo = FALSE;
442 priv->clipboard_change_handler_id = 0;
443 priv->default_clipboard_change_handler_id = 0;
444 priv->account_removed_handler_id = 0;
445 priv->clipboard_owner_idle = 0;
446 priv->clipboard_text = NULL;
449 priv->scroll_drag_timeout_id = 0;
450 priv->correct_scroll_idle = 0;
451 priv->last_upper = 0.0;
453 priv->font_dialog = NULL;
454 priv->app_menu = NULL;
456 priv->references = NULL;
457 priv->in_reply_to = NULL;
458 priv->max_chars_banner = NULL;
460 if (!is_wp_text_buffer_started) {
461 is_wp_text_buffer_started = TRUE;
462 wp_text_buffer_library_init ();
467 hildon_program_add_window (hildon_program_get_instance(),
472 multimailbox_get_default_mailbox (const gchar *account_name)
474 gchar *transport_account;
475 gchar *result = NULL;
477 transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
479 TNY_ACCOUNT_TYPE_TRANSPORT);
480 if (transport_account) {
482 ModestProtocolRegistry *registry;
484 registry = modest_runtime_get_protocol_registry ();
486 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account,
487 MODEST_ACCOUNT_PROTO, TRUE);
489 ModestProtocol *protocol =
490 modest_protocol_registry_get_protocol_by_name (registry,
491 MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
493 if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
494 ModestPairList *pair_list;
496 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
499 ModestPair *pair = (ModestPair *) pair_list->data;
500 result = g_strdup ((const gchar *) pair->first);
501 modest_pair_list_free (pair_list);
512 * @result: A ModestPairList, which must be freed with modest_pair_list_free().
514 static ModestPairList*
515 get_transports (void)
517 GSList *transports = NULL;
519 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
520 GSList *accounts = modest_account_mgr_account_names (account_mgr,
521 TRUE /* only enabled accounts. */);
523 GSList *cursor = accounts;
525 gchar *account_name = cursor->data;
528 gchar *transport_account;
529 gboolean multi_mailbox = FALSE;
530 ModestProtocol *protocol = NULL;
532 if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
534 transport_account = modest_account_mgr_get_server_account_name
535 (modest_runtime_get_account_mgr (),
537 TNY_ACCOUNT_TYPE_TRANSPORT);
538 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
539 ModestPairList *pair_list;
540 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
543 transports = g_slist_concat (transports, pair_list);
544 multi_mailbox = TRUE;
549 if (!multi_mailbox) {
550 gchar *from_string = NULL;
552 from_string = modest_account_mgr_get_from_string (account_mgr,
554 if (from_string && account_name) {
555 gchar *name = account_name;
556 ModestPair *pair = modest_pair_new ((gpointer) name,
557 (gpointer) from_string , TRUE);
558 transports = g_slist_prepend (transports, pair);
563 cursor = cursor->next;
565 g_slist_free (accounts); /* only free the accounts, not the elements,
566 * because they are used in the pairlist */
570 static void window_focus (GtkWindow *window,
574 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
578 scroll_drag_timeout (gpointer userdata)
580 ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
581 ModestMsgEditWindowPrivate *priv;
583 /* It could happen that the window was already closed */
584 if (!GTK_WIDGET_VISIBLE (win))
587 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
589 correct_scroll_without_drag_check (win, TRUE);
591 priv->scroll_drag_timeout_id = 0;
597 correct_scroll_without_drag_check_idle (gpointer userdata)
599 ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
600 ModestMsgEditWindowPrivate *priv;
602 GdkRectangle rectangle;
603 gint offset_min, offset_max;
607 /* It could happen that the window was already closed */
608 if (!GTK_WIDGET_VISIBLE (w))
611 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
613 insert = gtk_text_buffer_get_insert (priv->text_buffer);
614 gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
616 gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
617 offset_min = priv->msg_body->allocation.y + rectangle.y;
618 offset_max = offset_min + rectangle.height;
620 vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
621 offset_min = MAX (offset_min - 48, 0);
622 offset_max = MIN (offset_max + 48, vadj->upper);
624 gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
626 priv->correct_scroll_idle = 0;
631 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
633 ModestMsgEditWindowPrivate *priv;
635 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
637 if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
640 if (priv->correct_scroll_idle > 0) {
644 priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
645 (GSourceFunc) correct_scroll_without_drag_check_idle,
651 correct_scroll (ModestMsgEditWindow *w)
653 ModestMsgEditWindowPrivate *priv;
655 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
656 if (gtk_grab_get_current () == priv->msg_body) {
657 if (priv->scroll_drag_timeout_id == 0) {
658 priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
660 (GSourceFunc) scroll_drag_timeout,
667 correct_scroll_without_drag_check (w, TRUE);
671 text_buffer_end_user_action (GtkTextBuffer *buffer,
672 ModestMsgEditWindow *userdata)
675 correct_scroll (userdata);
679 text_buffer_mark_set (GtkTextBuffer *buffer,
682 ModestMsgEditWindow *userdata)
684 gtk_text_buffer_begin_user_action (buffer);
685 gtk_text_buffer_end_user_action (buffer);
689 cut_clipboard_check (GtkTextView *text_view,
692 GtkTextBuffer *buffer;
694 buffer = gtk_text_view_get_buffer (text_view);
695 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
696 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
701 copy_clipboard_check (GtkTextView *text_view,
704 GtkTextBuffer *buffer;
706 buffer = gtk_text_view_get_buffer (text_view);
707 if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
708 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
713 attachment_deleted (ModestAttachmentsView *attachments_view,
716 modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
721 body_size_request (GtkWidget *body,
725 /* Make sure the body always get at least 70 pixels */
726 if (req->height < 70)
731 connect_signals (ModestMsgEditWindow *obj)
733 ModestMsgEditWindowPrivate *priv;
735 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
737 g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
738 G_CALLBACK (text_buffer_refresh_attributes), obj);
739 g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
740 G_CALLBACK (text_buffer_can_undo), obj);
741 g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
742 G_CALLBACK (text_buffer_can_redo), obj);
743 g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
744 G_CALLBACK (body_changed), obj);
745 g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text",
746 G_CALLBACK (body_insert_text), obj);
747 g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
748 G_CALLBACK (body_changed), obj);
749 g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
750 G_CALLBACK (text_buffer_end_user_action), obj);
751 g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
752 G_CALLBACK (text_buffer_mark_set), obj);
753 g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
754 G_CALLBACK (text_buffer_apply_tag), obj);
755 g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook",
756 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
757 g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook",
758 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
759 g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook",
760 G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
762 g_signal_connect (G_OBJECT (priv->send_button), "clicked",
763 G_CALLBACK (modest_ui_actions_on_send), obj);
765 g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
766 G_CALLBACK (from_field_changed), obj);
768 g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
769 G_CALLBACK (msg_body_focus), obj);
770 g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
771 G_CALLBACK (msg_body_focus), obj);
772 g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
773 G_CALLBACK (body_size_request), obj);
774 g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
775 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
776 "changed", G_CALLBACK (recpt_field_changed), obj);
777 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
778 "changed", G_CALLBACK (recpt_field_changed), obj);
779 g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
780 "changed", G_CALLBACK (recpt_field_changed), obj);
781 g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
782 g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
783 g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
785 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
786 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
788 priv->clipboard_change_handler_id =
789 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
790 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
791 priv->default_clipboard_change_handler_id =
792 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
793 G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
795 g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
796 g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
797 g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
801 init_wp_text_view_style ()
803 static gboolean initialized = FALSE;
806 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
812 init_window (ModestMsgEditWindow *obj)
814 GtkWidget *to_caption, *subject_caption;
815 GtkWidget *main_vbox;
816 ModestMsgEditWindowPrivate *priv;
817 GtkActionGroup *action_group;
818 ModestWindowPrivate *parent_priv;
819 GdkPixbuf *window_icon = NULL;
820 GError *error = NULL;
822 GtkSizeGroup *title_size_group;
823 GtkSizeGroup *value_size_group;
824 GtkWidget *window_box;
825 GtkWidget *window_align;
826 #if (GTK_MINOR_VERSION >= 10)
827 GdkAtom deserialize_type;
829 GtkWidget *from_send_hbox;
830 GtkWidget *send_icon;
831 GtkWidget *attachments_label;
832 GtkWidget *branding_box;
834 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
835 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
837 parent_priv->ui_manager = gtk_ui_manager_new();
838 action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
839 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
841 /* Add common actions */
842 gtk_action_group_add_actions (action_group,
843 modest_msg_edit_action_entries,
844 G_N_ELEMENTS (modest_msg_edit_action_entries),
846 gtk_action_group_add_actions (action_group,
847 hildon2_msg_edit_action_entries,
848 G_N_ELEMENTS (hildon2_msg_edit_action_entries),
850 gtk_action_group_add_toggle_actions (action_group,
851 modest_msg_edit_toggle_action_entries,
852 G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
854 gtk_action_group_add_radio_actions (action_group,
855 modest_msg_edit_alignment_radio_action_entries,
856 G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
858 G_CALLBACK (modest_ui_actions_on_change_justify),
860 gtk_action_group_add_radio_actions (action_group,
861 modest_msg_edit_priority_action_entries,
862 G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
864 G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
866 gtk_action_group_add_radio_actions (action_group,
867 modest_msg_edit_file_format_action_entries,
868 G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
869 modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
870 G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
872 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
873 g_object_unref (action_group);
875 /* Load the UI definition */
876 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
879 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
880 g_clear_error (&error);
883 /* Add accelerators */
884 gtk_window_add_accel_group (GTK_WINDOW (obj),
885 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
887 parent_priv->menubar = NULL;
889 title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
890 value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
892 /* Note: This ModestPairList* must exist for as long as the picker
893 * that uses it, because the ModestSelectorPicker uses the ID opaquely,
894 * so it can't know how to manage its memory. */
895 priv->from_field = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
896 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
898 modest_selector_picker_set_value_max_chars (MODEST_SELECTOR_PICKER (priv->from_field), MAX_FROM_VALUE);
899 modest_maemo_utils_set_hbutton_layout (title_size_group, NULL,
900 _("mail_va_from"), priv->from_field);
901 hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
902 hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
903 hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
905 priv->to_field = modest_recpt_editor_new ();
906 priv->cc_field = modest_recpt_editor_new ();
907 priv->bcc_field = modest_recpt_editor_new ();
908 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
909 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
910 modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
911 priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
912 priv->priority_icon = gtk_image_new ();
913 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
914 priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
915 gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
916 g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
917 hildon_entry_set_placeholder ((HildonEntry *) priv->subject_field, _("mail_va_no_subject"));
918 hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field),
919 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
920 gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
921 priv->attachments_view = modest_attachments_view_new (NULL);
922 modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
923 MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
925 priv->header_box = gtk_vbox_new (FALSE, 0);
927 to_caption = _create_addressbook_box
928 (title_size_group, value_size_group,
929 _("mail_va_to"), priv->to_field);
930 priv->cc_caption = _create_addressbook_box
931 (title_size_group, value_size_group,
932 _("mail_va_cc"), priv->cc_field);
933 priv->bcc_caption = _create_addressbook_box
934 (title_size_group, value_size_group,
935 _("mail_va_hotfix1"), priv->bcc_field);
936 subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
937 _("mail_va_subject"), FALSE, priv->subject_box);
938 priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (NULL, NULL,
939 _("mail_va_attachment"),
941 priv->attachments_view,
942 HILDON_SIZE_AUTO_WIDTH |
943 HILDON_SIZE_AUTO_HEIGHT);
944 attachments_label = modest_maemo_utils_captioned_get_label_widget (priv->attachments_caption);
945 hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
948 priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
949 send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
950 gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
951 gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
953 g_object_unref (title_size_group);
954 g_object_unref (value_size_group);
956 priv->brand_icon = gtk_image_new ();
957 gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
958 priv->brand_label = gtk_label_new (NULL);
959 hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
960 gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
961 gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
962 gtk_widget_set_no_show_all (priv->brand_label, TRUE);
964 from_send_hbox = gtk_hbox_new (FALSE, 0);
965 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->from_field, TRUE, TRUE, 0);
966 gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
968 branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
969 gtk_widget_show (branding_box);
970 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
971 gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
973 priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
974 gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
975 gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
976 gtk_widget_set_no_show_all (priv->brand_container, TRUE);
979 gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
980 gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
981 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
982 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
983 gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
984 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
985 gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
986 gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
988 init_wp_text_view_style ();
990 priv->msg_body = modest_wp_text_view_new ();
993 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
994 priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
995 g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
996 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
997 #if (GTK_MINOR_VERSION >= 10)
998 gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
999 deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer),
1001 gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer),
1002 deserialize_type, TRUE);
1004 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1006 priv->find_toolbar = hildon_find_toolbar_new (NULL);
1007 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
1009 /* g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1011 priv->pannable = hildon_pannable_area_new ();
1013 g_object_set (G_OBJECT (priv->pannable), "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
1015 main_vbox = gtk_vbox_new (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1016 window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1017 gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1019 gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1020 gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1021 gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1023 hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
1024 gtk_widget_show_all (GTK_WIDGET(priv->pannable));
1026 window_box = gtk_vbox_new (FALSE, 0);
1027 gtk_container_add (GTK_CONTAINER(obj), window_box);
1029 gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
1031 /* Set window icon */
1032 window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1034 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1035 g_object_unref (window_icon);
1040 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1042 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1044 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1045 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1046 priv->clipboard_change_handler_id))
1047 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
1048 priv->clipboard_change_handler_id);
1049 if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1050 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1051 priv->default_clipboard_change_handler_id))
1052 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
1053 priv->default_clipboard_change_handler_id);
1055 if (priv->account_removed_handler_id &&
1056 g_signal_handler_is_connected (modest_runtime_get_account_store (),
1057 priv->account_removed_handler_id))
1058 g_signal_handler_disconnect(modest_runtime_get_account_store (),
1059 priv->account_removed_handler_id);
1063 modest_msg_edit_window_finalize (GObject *obj)
1065 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1067 if (priv->max_chars_banner) {
1068 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1069 priv->max_chars_banner = FALSE;
1072 /* Sanity check: shouldn't be needed, the window mgr should
1073 call this function before */
1074 modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1076 if (priv->font_dialog != NULL) {
1077 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1080 if (priv->clipboard_text != NULL) {
1081 g_free (priv->clipboard_text);
1082 priv->clipboard_text = NULL;
1085 if (priv->draft_msg != NULL) {
1086 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1087 if (TNY_IS_HEADER (header)) {
1088 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1089 modest_window_mgr_unregister_header (mgr, header);
1091 g_object_unref (priv->draft_msg);
1092 priv->draft_msg = NULL;
1094 if (priv->outbox_msg != NULL) {
1095 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1096 if (TNY_IS_HEADER (header)) {
1097 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1098 modest_window_mgr_unregister_header (mgr, header);
1100 g_object_unref (priv->outbox_msg);
1101 priv->outbox_msg = NULL;
1103 if (priv->correct_scroll_idle > 0) {
1104 g_source_remove (priv->correct_scroll_idle);
1105 priv->correct_scroll_idle = 0;
1107 if (priv->scroll_drag_timeout_id > 0) {
1108 g_source_remove (priv->scroll_drag_timeout_id);
1109 priv->scroll_drag_timeout_id = 0;
1111 if (priv->clipboard_owner_idle > 0) {
1112 g_source_remove (priv->clipboard_owner_idle);
1113 priv->clipboard_owner_idle = 0;
1115 if (priv->original_account_name)
1116 g_free (priv->original_account_name);
1117 if (priv->original_mailbox)
1118 g_free (priv->original_mailbox);
1119 g_free (priv->msg_uid);
1120 g_free (priv->last_search);
1121 g_free (priv->references);
1122 g_free (priv->in_reply_to);
1123 g_object_unref (priv->attachments);
1124 g_object_unref (priv->images);
1126 /* This had to stay alive for as long as the picker that used it: */
1127 modest_pair_list_free (priv->from_field_protos);
1129 G_OBJECT_CLASS(parent_class)->finalize (obj);
1133 pixbuf_size_prepared (GdkPixbufLoader *loader,
1136 ModestMsgEditWindow *self)
1138 gint new_height, new_width;
1141 new_height = height;
1145 if (width > IMAGE_MAX_WIDTH) {
1146 new_height = height * IMAGE_MAX_WIDTH / width;
1147 new_width = IMAGE_MAX_WIDTH;
1150 gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1154 pixbuf_from_stream (TnyStream *stream,
1155 const gchar *mime_type,
1156 guint64 *stream_size,
1157 ModestMsgEditWindow *self)
1159 GdkPixbufLoader *loader;
1162 GError *error = NULL;
1166 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1168 if (loader == NULL) {
1173 g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1175 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1177 tny_stream_reset (TNY_STREAM (stream));
1178 while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1179 unsigned char read_buffer[128];
1181 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1183 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1186 /* Allow some UI responsiveness */
1187 while (gtk_events_pending ())
1188 gtk_main_iteration ();
1190 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1192 gdk_pixbuf_loader_close (loader, &error);
1195 g_error_free (error);
1196 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1198 g_object_ref (pixbuf);
1199 g_object_unref (loader);
1204 if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1205 GdkPixbuf *new_pixbuf;
1207 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1208 gdk_pixbuf_get_width (pixbuf);
1209 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1210 g_object_unref (pixbuf);
1211 pixbuf = new_pixbuf;
1215 *stream_size = size;
1221 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1223 ModestMsgEditWindowPrivate *priv;
1226 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1228 g_object_ref (self);
1229 for (iter = tny_list_create_iterator (attachments);
1230 !tny_iterator_is_done (iter);
1231 tny_iterator_next (iter)) {
1232 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1233 const gchar *cid = tny_mime_part_get_content_id (part);
1234 const gchar *mime_type = tny_mime_part_get_content_type (part);
1235 if ((cid != NULL)&&(mime_type != NULL)) {
1236 guint64 stream_size;
1237 TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1238 GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1241 g_object_unref (stream);
1243 if (pixbuf != NULL) {
1244 priv->images_count ++;
1245 priv->images_size += stream_size;
1246 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1247 g_object_unref (pixbuf);
1250 g_object_unref (part);
1252 g_object_unref (iter);
1253 g_object_unref (self);
1257 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1259 TnyMimePart *parent = NULL;
1260 const gchar *content_type = NULL;
1261 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1263 content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1265 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1266 parent = g_object_ref (msg);
1267 } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1268 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1271 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1272 iter = tny_list_create_iterator (parts);
1273 while (!tny_iterator_is_done (iter)) {
1275 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1276 content_type = tny_mime_part_get_content_type (part);
1277 if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1281 g_object_unref (part);
1283 tny_iterator_next (iter);
1285 g_object_unref (iter);
1286 g_object_unref (parts);
1289 if (parent != NULL) {
1290 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1293 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1294 iter = tny_list_create_iterator (parts);
1295 while (!tny_iterator_is_done (iter)) {
1297 part = TNY_MIME_PART (tny_iterator_get_current (iter));
1298 content_type = tny_mime_part_get_content_type (part);
1299 if (content_type && g_str_has_prefix (content_type, "image/")) {
1300 tny_list_prepend (priv->images, (GObject *) part);
1302 g_object_unref (part);
1303 tny_iterator_next (iter);
1305 g_object_unref (iter);
1306 g_object_unref (parts);
1307 g_object_unref (parent);
1312 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1315 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1317 for (iter = tny_list_create_iterator (attachments) ;
1318 !tny_iterator_is_done (iter);
1319 tny_iterator_next (iter)) {
1320 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1321 const gchar *cid = tny_mime_part_get_content_id (part);
1323 char *invalid = NULL;
1324 gint int_cid = strtol (cid, &invalid, 10);
1325 if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1326 priv->next_cid = int_cid + 1;
1329 g_object_unref (part);
1331 g_object_unref (iter);
1335 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1338 gchar *to, *cc, *bcc, *subject;
1340 ModestMsgEditWindowPrivate *priv;
1341 ModestWindowPrivate *parent_priv;
1343 TnyHeaderFlags priority_flags;
1344 TnyFolder *msg_folder;
1345 gboolean is_html = FALSE;
1346 gboolean field_view_set;
1348 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1349 g_return_if_fail (TNY_IS_MSG (msg));
1351 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1352 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1354 header = tny_msg_get_header (msg);
1355 to = tny_header_dup_to (header);
1356 cc = tny_header_dup_cc (header);
1357 bcc = tny_header_dup_bcc (header);
1358 subject = tny_header_dup_subject (header);
1360 modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1361 priority_flags = tny_header_get_priority (header);
1364 gchar *quoted_names = modest_text_utils_quote_names (to);
1365 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1366 g_free (quoted_names);
1369 field_view_set = TRUE;
1371 gchar *quoted_names = modest_text_utils_quote_names (cc);
1372 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field), quoted_names);
1373 g_free (quoted_names);
1374 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1375 gtk_widget_show (priv->cc_caption);
1376 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1377 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1378 gtk_widget_hide (priv->cc_caption);
1379 field_view_set = FALSE;
1381 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1383 field_view_set = TRUE;
1385 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1386 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1387 g_free (quoted_names);
1388 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1389 gtk_widget_show (priv->bcc_caption);
1390 } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1391 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1392 gtk_widget_hide (priv->bcc_caption);
1393 field_view_set = FALSE;
1395 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1399 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1400 modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1403 update_window_title (self);
1405 wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1406 body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1408 if ((body == NULL)||(body[0] == '\0')) {
1410 body = modest_text_utils_convert_to_html ("");
1413 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1414 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1417 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1420 /* Add attachments to the view */
1421 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1422 priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1423 if (tny_list_get_length (priv->attachments) == 0) {
1424 gtk_widget_hide (priv->attachments_caption);
1426 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1427 gtk_widget_show_all (priv->attachments_caption);
1429 get_related_images (self, msg);
1430 update_next_cid (self, priv->attachments);
1431 update_next_cid (self, priv->images);
1432 replace_with_images (self, priv->images);
1434 if (preserve_is_rich && !is_html) {
1435 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1436 /* Get the default format required from configuration */
1437 } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1438 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1441 /* Set the default focus depending on having already a To: field or not */
1442 if ((!to)||(*to == '\0')) {
1443 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1445 gtk_widget_grab_focus (priv->msg_body);
1448 DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1450 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1451 gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1453 modest_msg_edit_window_set_modified (self, FALSE);
1455 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1456 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1457 text_buffer_can_undo (priv->text_buffer, FALSE, self);
1458 text_buffer_can_redo (priv->text_buffer, FALSE, self);
1460 if (priv->msg_uid) {
1461 g_free (priv->msg_uid);
1462 priv->msg_uid = NULL;
1465 /* we should set a reference to the incoming message if it is a draft */
1466 msg_folder = tny_msg_get_folder (msg);
1468 if (modest_tny_folder_is_local_folder (msg_folder)) {
1469 TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1470 if (type == TNY_FOLDER_TYPE_INVALID)
1471 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1473 if (type == TNY_FOLDER_TYPE_DRAFTS)
1474 priv->draft_msg = g_object_ref(msg);
1475 if (type == TNY_FOLDER_TYPE_OUTBOX)
1476 priv->outbox_msg = g_object_ref(msg);
1477 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1479 g_object_unref (msg_folder);
1489 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1491 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1492 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1493 GtkWidget *placeholder;
1494 GtkWidget *tool_item;
1499 GtkWidget *sizes_menu;
1500 GtkWidget *fonts_menu;
1506 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1507 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1508 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1509 hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1511 /* Font color placeholder */
1512 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1513 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1516 priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1517 priv->font_color_button = modest_color_button_new ();
1518 gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1519 GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1520 GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1521 gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1522 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1523 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1524 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1525 g_signal_connect_swapped (G_OBJECT (priv->font_color_button),
1527 G_CALLBACK (modest_msg_edit_window_color_button_change),
1530 /* Font size and face placeholder */
1531 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1532 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1534 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1535 priv->size_tool_button_label = gtk_label_new (NULL);
1536 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1537 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1538 size_text, "</span>", NULL);
1539 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1540 gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1542 hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1543 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1544 gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1545 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1546 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1547 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1548 gtk_widget_set_sensitive (arrow, FALSE);
1549 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1550 sizes_menu = gtk_menu_new ();
1551 priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1552 for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1555 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1556 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1558 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter,
1562 if (wp_font_size[size_index] == 12)
1563 priv->current_size_index = size_index;
1567 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1568 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1569 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1570 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1571 priv->font_size_toolitem = tool_item;
1574 tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1575 priv->font_tool_button_label = gtk_label_new (NULL);
1576 markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1577 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1578 gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1580 hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1581 hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1582 gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1583 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1584 gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1585 gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1586 gtk_widget_set_sensitive (arrow, FALSE);
1587 gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1588 fonts_menu = gtk_menu_new ();
1589 priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1590 for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1593 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1595 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter,
1596 0, wp_get_font_name (font_index),
1599 if (font_index == DEFAULT_FONT)
1600 priv->current_face_index = font_index;
1602 g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1603 gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1604 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1605 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1606 priv->font_face_toolitem = tool_item;
1608 /* Set expand and homogeneous for remaining items */
1609 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1610 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1611 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1612 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1613 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1614 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1615 tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsInsertImage");
1616 gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1617 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1619 /* Explicitelly show all the toolbar (a normal gtk_widget_show
1620 will not show the tool items added to the placeholders) */
1621 gtk_widget_show_all (parent_priv->toolbar);
1623 /* Set the no show all *after* showing all items. We do not
1624 want the toolbar to be shown with a show all because it
1625 could go against the gconf setting regarding showing or not
1626 the toolbar of the editor window */
1627 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1633 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1636 ModestWindowPrivate *parent_priv;
1637 ModestMsgEditWindowPrivate *priv;
1638 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1639 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1640 ModestWindowMgr *mgr = NULL;
1642 g_return_val_if_fail (msg, NULL);
1643 g_return_val_if_fail (account_name, NULL);
1645 mgr = modest_runtime_get_window_mgr ();
1647 obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1649 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1650 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1652 /* Menubar. Update the state of some toggles */
1653 priv->from_field_protos = get_transports ();
1654 priv->original_mailbox = NULL;
1655 modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1656 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1657 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1658 if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1659 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) mailbox);
1660 priv->original_mailbox = g_strdup (mailbox);
1661 } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1662 /* We set the first mailbox as the active mailbox */
1663 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1664 if (priv->original_mailbox != NULL)
1665 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1666 (gpointer) priv->original_mailbox);
1668 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1669 (gpointer) account_name);
1671 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1673 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1674 update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1675 hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1677 hildon_button_set_value (HILDON_BUTTON (priv->from_field),
1678 hildon_touch_selector_get_current_text
1679 (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1680 modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1681 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1684 connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1686 restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1688 modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1689 modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1691 priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1693 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1694 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1695 /* Add common dimming rules */
1696 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1697 modest_msg_edit_window_toolbar_dimming_entries,
1698 G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1699 MODEST_WINDOW (obj));
1700 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1701 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1702 MODEST_WINDOW (obj));
1703 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1704 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1705 MODEST_WINDOW (obj));
1706 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1707 G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1708 MODEST_WINDOW (obj));
1709 modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1710 G_CALLBACK (modest_ui_dimming_rules_on_send),
1711 MODEST_WINDOW (obj));
1712 /* Insert dimming rules group for this window */
1713 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1714 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1716 /* Setup app menu */
1717 setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1719 /* Checks the dimming rules */
1720 g_object_unref (toolbar_rules_group);
1721 g_object_unref (clipboard_rules_group);
1722 gtk_widget_hide (priv->priority_icon);
1723 gtk_widget_queue_resize (priv->subject_box);
1724 set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1726 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1728 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1729 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1730 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1731 priv->update_caption_visibility = TRUE;
1733 modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1735 /* Track account-removed signal, this window should be closed
1736 in the case we're creating a mail associated to the account
1738 priv->account_removed_handler_id =
1739 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1741 G_CALLBACK(on_account_removed),
1744 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1746 return (ModestWindow*) obj;
1750 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1752 GString **string_buffer = (GString **) user_data;
1754 *string_buffer = g_string_append (*string_buffer, buffer);
1760 * @result: A new string which should be freed with g_free().
1763 get_formatted_data (ModestMsgEditWindow *edit_window)
1765 ModestMsgEditWindowPrivate *priv;
1766 GString *string_buffer = g_string_new ("");
1768 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1770 wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1772 modest_text_utils_hyperlinkify (string_buffer);
1774 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1776 return g_string_free (string_buffer, FALSE);
1781 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1784 const gchar *account_name;
1785 ModestMsgEditWindowPrivate *priv;
1786 TnyIterator *att_iter;
1787 const gchar *picker_active_id;
1789 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1791 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1793 picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1794 g_return_val_if_fail (picker_active_id, NULL);
1795 account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1797 /* don't free these (except from) */
1798 data = g_slice_new0 (MsgData);
1799 data->from = g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1800 data->account_name = g_strdup (account_name);
1801 data->to = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1802 data->cc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1803 data->bcc = g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1804 data->subject = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1805 data->references = g_strdup (priv->references);
1806 data->in_reply_to = g_strdup (priv->in_reply_to);
1807 if (priv->draft_msg) {
1808 data->draft_msg = g_object_ref (priv->draft_msg);
1809 } else if (priv->outbox_msg) {
1810 data->draft_msg = g_object_ref (priv->outbox_msg);
1812 data->draft_msg = NULL;
1815 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1817 gtk_text_buffer_get_bounds (buf, &b, &e);
1818 data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1820 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1821 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1823 data->html_body = NULL;
1825 /* deep-copy the data */
1826 att_iter = tny_list_create_iterator (priv->attachments);
1827 data->attachments = NULL;
1828 while (!tny_iterator_is_done (att_iter)) {
1829 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1830 if (!(TNY_IS_MIME_PART(part))) {
1831 g_warning ("strange data in attachment list");
1832 g_object_unref (part);
1833 tny_iterator_next (att_iter);
1836 data->attachments = g_list_append (data->attachments,
1838 tny_iterator_next (att_iter);
1840 g_object_unref (att_iter);
1842 GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1843 att_iter = tny_list_create_iterator (priv->images);
1844 data->images = NULL;
1845 while (!tny_iterator_is_done (att_iter)) {
1846 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1848 if (!(TNY_IS_MIME_PART(part))) {
1849 g_warning ("strange data in attachment list");
1850 g_object_unref (part);
1851 tny_iterator_next (att_iter);
1854 cid = tny_mime_part_get_content_id (part);
1856 gchar *image_tag_id;
1857 GtkTextTag *image_tag;
1859 image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1860 image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1861 g_free (image_tag_id);
1863 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1865 ((gtk_text_iter_has_tag (&iter, image_tag))||
1866 (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1867 data->images = g_list_append (data->images,
1868 g_object_ref (part));
1870 g_object_unref (part);
1871 tny_iterator_next (att_iter);
1873 g_object_unref (att_iter);
1875 data->priority_flags = priv->priority_flags;
1882 unref_gobject (GObject *obj, gpointer data)
1884 if (!G_IS_OBJECT(obj))
1886 g_object_unref (obj);
1890 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1893 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1901 g_free (data->from);
1902 g_free (data->subject);
1903 g_free (data->plain_body);
1904 g_free (data->html_body);
1905 g_free (data->account_name);
1906 g_free (data->references);
1907 g_free (data->in_reply_to);
1909 if (data->draft_msg != NULL) {
1910 g_object_unref (data->draft_msg);
1911 data->draft_msg = NULL;
1914 g_list_foreach (data->attachments, (GFunc)unref_gobject, NULL);
1915 g_list_free (data->attachments);
1916 g_list_foreach (data->images, (GFunc)unref_gobject, NULL);
1917 g_list_free (data->images);
1919 g_slice_free (MsgData, data);
1923 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1925 guint64 *parts_size)
1927 ModestMsgEditWindowPrivate *priv;
1929 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1931 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1933 /* TODO: add images */
1934 *parts_size += priv->images_size;
1935 *parts_count += priv->images_count;
1940 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1943 ModestMsgEditWindowPrivate *priv = NULL;
1944 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1946 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1948 rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1950 return MODEST_MSG_EDIT_FORMAT_HTML;
1952 return MODEST_MSG_EDIT_FORMAT_TEXT;
1956 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1957 ModestMsgEditFormat format)
1959 ModestMsgEditWindowPrivate *priv;
1960 ModestWindowPrivate *parent_priv;
1962 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1963 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1964 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1967 case MODEST_MSG_EDIT_FORMAT_HTML:
1968 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1969 update_signature (self, priv->last_from_account, priv->last_from_account);
1970 if (parent_priv->toolbar)
1971 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
1972 MODEST_MSG_EDIT_WINDOW (self));
1974 case MODEST_MSG_EDIT_FORMAT_TEXT:
1975 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1976 if (parent_priv->toolbar)
1977 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
1978 MODEST_MSG_EDIT_WINDOW (self));
1981 g_return_if_reached ();
1985 ModestMsgEditFormatState *
1986 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1988 ModestMsgEditFormatState *format_state = NULL;
1989 ModestMsgEditWindowPrivate *priv;
1990 WPTextBufferFormat *buffer_format;
1992 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1994 buffer_format = g_new0 (WPTextBufferFormat, 1);
1995 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1997 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1999 format_state = g_new0 (ModestMsgEditFormatState, 1);
2000 format_state->bold = buffer_format->bold&0x1;
2001 format_state->italics = buffer_format->italic&0x1;
2002 format_state->bullet = buffer_format->bullet&0x1;
2003 format_state->color = buffer_format->color;
2004 format_state->font_size = buffer_format->font_size;
2005 format_state->font_family = wp_get_font_name (buffer_format->font);
2006 format_state->justification = buffer_format->justification;
2007 g_free (buffer_format);
2009 return format_state;
2014 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2015 const ModestMsgEditFormatState *format_state)
2017 ModestMsgEditWindowPrivate *priv;
2018 WPTextBufferFormat *buffer_format;
2019 WPTextBufferFormat *current_format;
2021 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2022 g_return_if_fail (format_state != NULL);
2024 buffer_format = g_new0 (WPTextBufferFormat, 1);
2025 current_format = g_new0 (WPTextBufferFormat, 1);
2027 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2028 gtk_widget_grab_focus (priv->msg_body);
2029 buffer_format->bold = (format_state->bold != FALSE);
2030 buffer_format->italic = (format_state->italics != FALSE);
2031 buffer_format->color = format_state->color;
2032 buffer_format->font_size = format_state->font_size;
2033 buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2034 buffer_format->justification = format_state->justification;
2035 buffer_format->bullet = format_state->bullet;
2037 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2039 buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2040 buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2041 buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2042 buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size);
2043 buffer_format->cs.font = (buffer_format->font != current_format->font);
2044 buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2045 buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2047 wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2048 if (buffer_format->cs.bold) {
2049 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2050 GINT_TO_POINTER (buffer_format->bold&0x1));
2052 if (buffer_format->cs.italic) {
2053 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2054 GINT_TO_POINTER (buffer_format->italic&0x1));
2056 if (buffer_format->cs.color) {
2057 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2058 GINT_TO_POINTER (&(buffer_format->color)));
2060 if (buffer_format->cs.font_size) {
2061 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2062 GINT_TO_POINTER (buffer_format->font_size));
2064 if (buffer_format->cs.justification) {
2065 switch (buffer_format->justification) {
2066 case GTK_JUSTIFY_LEFT:
2067 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2068 GINT_TO_POINTER(TRUE));
2070 case GTK_JUSTIFY_CENTER:
2071 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2072 GINT_TO_POINTER(TRUE));
2074 case GTK_JUSTIFY_RIGHT:
2075 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2076 GINT_TO_POINTER(TRUE));
2083 if (buffer_format->cs.font) {
2084 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2085 GINT_TO_POINTER (buffer_format->font));
2087 wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2088 if (buffer_format->cs.bullet) {
2089 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2090 GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2092 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2094 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2096 g_free (buffer_format);
2097 g_free (current_format);
2099 /* Check dimming rules */
2100 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2101 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2105 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2107 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2109 ModestWindowPrivate *parent_priv;
2110 ModestMsgEditWindowPrivate *priv;
2112 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2113 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2115 if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2116 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2117 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2118 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2120 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2121 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2122 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2125 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2127 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2128 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2130 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2131 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2133 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2134 /* modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2137 switch (buffer_format->justification)
2139 case GTK_JUSTIFY_LEFT:
2140 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2142 case GTK_JUSTIFY_CENTER:
2143 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2145 case GTK_JUSTIFY_RIGHT:
2146 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2153 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2155 g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button),
2156 G_CALLBACK (modest_msg_edit_window_color_button_change),
2158 hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2159 g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button),
2160 G_CALLBACK (modest_msg_edit_window_color_button_change),
2163 if (priv->current_size_index != buffer_format->font_size) {
2167 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2168 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2172 priv->current_size_index = buffer_format->font_size;
2174 gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2175 markup = g_strconcat ("<span font_family='Sans'>",
2176 size_text, "</span>", NULL);
2178 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2182 gtk_tree_path_free (path);
2185 if (priv->current_face_index != buffer_format->font) {
2189 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2190 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2194 priv->current_face_index = buffer_format->font;
2195 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2196 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2197 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2204 g_free (buffer_format);
2210 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2212 WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2213 ModestMsgEditWindowPrivate *priv;
2214 GtkWidget *dialog = NULL;
2216 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2217 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2219 dialog = hildon_color_chooser_new ();
2220 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2221 g_free (buffer_format);
2223 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2225 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2226 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2229 gtk_widget_destroy (dialog);
2234 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2236 ModestMsgEditWindowPrivate *priv;
2237 GtkWidget *dialog = NULL;
2238 GdkColor *old_color = NULL;
2240 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2241 old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2243 dialog = hildon_color_chooser_new ();
2244 hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2246 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2248 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2249 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2251 gtk_widget_destroy (dialog);
2256 create_stream_for_uri (const gchar* uri)
2261 TnyStream *result = NULL;
2263 GnomeVFSHandle *handle = NULL;
2264 GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2265 if (test == GNOME_VFS_OK) {
2266 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2267 /* Streams over OBEX (Bluetooth) are not seekable but
2268 * we expect them to be (we might need to read them
2269 * several times). So if this is a Bluetooth URI just
2270 * read the whole file into memory (this is not a fast
2271 * protocol so we can assume that these files are not
2272 * going to be very big) */
2273 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2274 (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2275 TnyStream *memstream = tny_camel_mem_stream_new ();
2276 tny_stream_write_to_stream (vfssstream, memstream);
2277 g_object_unref (vfssstream);
2280 result = vfssstream;
2288 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2291 ModestMsgEditWindowPrivate *priv;
2292 GtkWidget *dialog = NULL;
2294 GSList *uris = NULL;
2295 GSList *uri_node = NULL;
2297 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2299 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2300 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2301 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2303 modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2305 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2306 GTK_WINDOW (dialog), GTK_WINDOW (window));
2308 response = gtk_dialog_run (GTK_DIALOG (dialog));
2310 case GTK_RESPONSE_OK:
2312 gchar *current_folder;
2313 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2314 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2315 if (current_folder && current_folder != '\0') {
2317 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH,
2318 current_folder, &err);
2320 g_debug ("Error storing latest used folder: %s", err->message);
2324 g_free (current_folder);
2330 gtk_widget_destroy (dialog);
2332 g_object_ref (window);
2333 /* The operation could take some time so allow the dialog to be closed */
2334 while (gtk_events_pending ())
2335 gtk_main_iteration ();
2337 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2339 GnomeVFSHandle *handle = NULL;
2340 GnomeVFSResult result;
2341 GtkTextIter position;
2342 GtkTextMark *insert_mark;
2344 uri = (const gchar *) uri_node->data;
2345 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2346 if (result == GNOME_VFS_OK) {
2348 GnomeVFSFileInfo *info;
2349 gchar *filename, *basename, *escaped_filename;
2350 TnyMimePart *mime_part;
2352 const gchar *mime_type = NULL;
2353 GnomeVFSURI *vfs_uri;
2354 guint64 stream_size;
2356 gnome_vfs_close (handle);
2357 vfs_uri = gnome_vfs_uri_new (uri);
2359 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2360 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2361 g_free (escaped_filename);
2362 gnome_vfs_uri_unref (vfs_uri);
2363 info = gnome_vfs_file_info_new ();
2365 if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2366 | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2368 mime_type = gnome_vfs_file_info_get_mime_type (info);
2370 mime_part = tny_platform_factory_new_mime_part
2371 (modest_runtime_get_platform_factory ());
2373 TnyStream *stream = create_stream_for_uri (uri);
2375 if (stream == NULL) {
2377 modest_platform_information_banner (NULL, NULL,
2378 _FM("sfil_ib_opening_not_allowed"));
2380 g_object_unref (mime_part);
2381 gnome_vfs_file_info_unref (info);
2385 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2387 content_id = g_strdup_printf ("%d", priv->next_cid);
2388 tny_mime_part_set_content_id (mime_part, content_id);
2389 g_free (content_id);
2392 basename = g_path_get_basename (filename);
2393 tny_mime_part_set_filename (mime_part, basename);
2396 pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2398 if (pixbuf != NULL) {
2399 priv->images_size += stream_size;
2400 priv->images_count ++;
2401 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2402 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2403 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position,
2404 tny_mime_part_get_content_id (mime_part), pixbuf);
2405 g_object_unref (pixbuf);
2407 tny_list_prepend (priv->images, (GObject *) mime_part);
2408 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2410 modest_platform_information_banner (NULL, NULL,
2411 _("mail_ib_file_operation_failed"));
2415 g_object_unref (mime_part);
2416 gnome_vfs_file_info_unref (info);
2420 g_object_unref (window);
2424 on_attach_file_response (GtkDialog *dialog,
2428 GSList *uris = NULL;
2430 GnomeVFSFileSize total_size, allowed_size;
2431 ModestMsgEditWindow *window;
2432 ModestMsgEditWindowPrivate *priv;
2437 case GTK_RESPONSE_OK:
2439 gchar *current_folder;
2441 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2442 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2443 if (current_folder && current_folder != '\0') {
2445 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH,
2446 current_folder, &err);
2448 g_debug ("Error storing latest used folder: %s", err->message);
2452 g_free (current_folder);
2459 window = MODEST_MSG_EDIT_WINDOW (user_data);
2460 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2462 /* allowed size is the maximum size - what's already there */
2463 modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2464 &att_num, &att_size);
2465 allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2468 for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2470 const gchar *uri = (const gchar *) uri_node->data;
2473 modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2475 if (total_size > allowed_size) {
2476 g_debug ("%s: total size: %u",
2477 __FUNCTION__, (unsigned int)total_size);
2480 allowed_size -= total_size;
2482 g_slist_foreach (uris, (GFunc) g_free, NULL);
2483 g_slist_free (uris);
2485 gtk_widget_destroy (GTK_WIDGET (dialog));
2489 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2491 GtkWidget *dialog = NULL;
2492 ModestMsgEditWindowPrivate *priv;
2495 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2497 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2499 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2502 dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2503 GTK_FILE_CHOOSER_ACTION_OPEN);
2504 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2505 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2506 MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2507 if (conf_folder && conf_folder[0] != '\0') {
2508 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2511 /* Set the default folder to documents folder */
2512 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2515 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2516 ".documents", NULL);
2518 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2519 g_free (docs_folder);
2521 g_free (conf_folder);
2522 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2523 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2524 GTK_WINDOW (dialog), GTK_WINDOW (window));
2526 /* Connect to response & show */
2527 g_signal_connect (dialog, "response",
2528 G_CALLBACK (on_attach_file_response), window);
2529 gtk_widget_show (dialog);
2534 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2536 GnomeVFSFileSize allowed_size)
2539 GnomeVFSHandle *handle = NULL;
2540 ModestMsgEditWindowPrivate *priv;
2541 GnomeVFSResult result;
2542 GnomeVFSFileSize size = 0;
2543 g_return_val_if_fail (window, 0);
2544 g_return_val_if_fail (uri, 0);
2546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2548 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2549 if (result == GNOME_VFS_OK) {
2550 TnyMimePart *mime_part;
2552 const gchar *mime_type = NULL;
2554 gchar *escaped_filename;
2557 GnomeVFSFileInfo *info;
2558 GnomeVFSURI *vfs_uri;
2560 gnome_vfs_close (handle);
2561 vfs_uri = gnome_vfs_uri_new (uri);
2564 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2565 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2566 g_free (escaped_filename);
2567 gnome_vfs_uri_unref (vfs_uri);
2569 info = gnome_vfs_file_info_new ();
2571 if (gnome_vfs_get_file_info (uri,
2573 GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2575 mime_type = gnome_vfs_file_info_get_mime_type (info);
2576 mime_part = tny_platform_factory_new_mime_part
2577 (modest_runtime_get_platform_factory ());
2579 /* try to get the attachment's size; this may fail for weird
2580 * file systems, like obex, upnp... */
2581 if (allowed_size != 0 &&
2582 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2584 if (size > allowed_size) {
2585 modest_platform_information_banner (NULL, NULL,
2586 _("mail_ib_error_attachment_size"));
2591 g_debug ("%s: could not get attachment size", __FUNCTION__);
2593 stream = create_stream_for_uri (uri);
2595 if (stream == NULL) {
2597 modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2599 g_object_unref (mime_part);
2601 gnome_vfs_file_info_unref (info);
2605 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2606 g_object_unref (stream);
2608 content_id = g_strdup_printf ("%d", priv->next_cid);
2609 tny_mime_part_set_content_id (mime_part, content_id);
2610 g_free (content_id);
2613 basename = g_path_get_basename (filename);
2614 tny_mime_part_set_filename (mime_part, basename);
2617 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2618 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2620 info->size == 0, info->size);
2621 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2622 gtk_widget_show_all (priv->attachments_caption);
2623 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2625 g_object_unref (mime_part);
2626 gnome_vfs_file_info_unref (info);
2633 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2636 ModestMsgEditWindowPrivate *priv;
2639 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2640 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2642 if (att_list == NULL) {
2643 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2644 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2645 g_object_unref (att_list);
2649 g_object_ref (att_list);
2652 if (tny_list_get_length (att_list) == 0) {
2653 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2655 gboolean dialog_response;
2656 gchar *message = NULL;
2657 gchar *filename = NULL;
2659 if (tny_list_get_length (att_list) == 1) {
2661 iter = tny_list_create_iterator (att_list);
2662 part = (TnyMimePart *) tny_iterator_get_current (iter);
2663 g_object_unref (iter);
2664 if (TNY_IS_MSG (part)) {
2665 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2667 filename = tny_header_dup_subject (header);
2668 g_object_unref (header);
2670 if (filename == NULL) {
2671 filename = g_strdup (_("mail_va_no_subject"));
2674 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2676 g_object_unref (part);
2678 filename = g_strdup ("");
2680 message = g_strdup_printf (ngettext("emev_nc_delete_attachment",
2681 "emev_nc_delete_attachments",
2682 tny_list_get_length (att_list)), filename);
2685 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2689 if (dialog_response != GTK_RESPONSE_OK) {
2690 g_object_unref (att_list);
2694 for (iter = tny_list_create_iterator (att_list);
2695 !tny_iterator_is_done (iter);
2696 tny_iterator_next (iter)) {
2697 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2698 const gchar *att_id;
2699 tny_list_remove (priv->attachments, (GObject *) mime_part);
2701 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2703 if (tny_list_get_length (priv->attachments) == 0)
2704 gtk_widget_hide (priv->attachments_caption);
2705 att_id = tny_mime_part_get_content_id (mime_part);
2707 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2709 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2710 g_object_unref (mime_part);
2712 g_object_unref (iter);
2715 g_object_unref (att_list);
2717 /* if the last attachment has been removed, focus the Subject: field */
2718 if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2719 gtk_widget_grab_focus (priv->subject_field);
2723 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2726 ModestMsgEditWindowPrivate *priv;
2729 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2731 hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2733 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2735 gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2739 font_size_clicked (GtkToolButton *button,
2740 ModestMsgEditWindow *window)
2742 ModestMsgEditWindowPrivate *priv;
2743 GtkWidget *selector, *dialog;
2745 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2747 selector = hildon_touch_selector_new ();
2748 hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2749 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2751 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2752 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2753 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2755 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2759 WPTextBufferFormat format;
2761 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2763 memset (&format, 0, sizeof (format));
2764 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2766 format.cs.font_size = TRUE;
2767 format.cs.text_position = TRUE;
2768 format.cs.font = TRUE;
2769 format.font_size = new_index;
2770 /* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2772 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2773 GINT_TO_POINTER (new_index)))
2774 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2776 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2777 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2778 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
2779 size_text, "</span>", NULL);
2781 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2785 gtk_widget_destroy (dialog);
2787 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2792 font_face_clicked (GtkToolButton *button,
2793 ModestMsgEditWindow *window)
2795 ModestMsgEditWindowPrivate *priv;
2796 GtkWidget *selector, *dialog;
2797 GtkCellRenderer *renderer;
2799 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2801 selector = hildon_touch_selector_new ();
2802 renderer = gtk_cell_renderer_text_new ();
2803 g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2804 hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model,
2805 renderer, "family", 0, "text", 0, NULL);
2806 hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2808 dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2809 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2810 gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2812 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2813 gint new_font_index;
2817 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2818 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2819 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2823 gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2825 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2826 GINT_TO_POINTER(new_font_index)))
2827 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2829 markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2830 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2832 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2836 gtk_tree_path_free (path);
2839 gtk_widget_destroy (dialog);
2841 gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2846 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window,
2849 ModestMsgEditWindowPrivate *priv = NULL;
2850 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2852 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2853 if (!priv->update_caption_visibility)
2856 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2858 gtk_widget_show (priv->cc_caption);
2860 gtk_widget_hide (priv->cc_caption);
2862 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2866 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window,
2869 ModestMsgEditWindowPrivate *priv = NULL;
2870 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2872 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2873 if (!priv->update_caption_visibility)
2876 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2878 gtk_widget_show (priv->bcc_caption);
2880 gtk_widget_hide (priv->bcc_caption);
2882 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2886 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2887 ModestRecptEditor *editor)
2889 ModestMsgEditWindowPrivate *priv;
2891 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2892 g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2894 /* we check for low-mem; in that case, show a warning, and don't allow
2895 * for the addressbook
2897 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2900 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2902 if (editor == NULL) {
2903 GtkWidget *view_focus, *parent;
2904 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2906 /* This code should be kept in sync with ModestRecptEditor. The
2907 textview inside the recpt editor is the one that really gets the
2908 focus. As it's inside a scrolled window, and this one inside the
2909 hbox recpt editor inherits from, we'll need to go up in the
2910 hierarchy to know if the text view is part of the recpt editor
2911 or if it's a different text entry */
2912 parent = gtk_widget_get_parent (view_focus);
2913 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2914 editor = MODEST_RECPT_EDITOR (parent);
2917 editor = MODEST_RECPT_EDITOR (priv->to_field);
2920 modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2924 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2926 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2928 modest_msg_edit_window_open_addressbook (window, NULL);
2932 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2933 gboolean show_toolbar)
2935 ModestWindowPrivate *parent_priv;
2936 ModestMsgEditWindowPrivate *priv;
2938 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2939 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2940 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2942 /* We can not just use the code of
2943 modest_msg_edit_window_setup_toolbar because it has a
2944 mixture of both initialization and creation code. */
2946 gint current_format;
2947 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2948 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2949 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2950 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2952 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2955 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2957 modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, show_toolbar, NULL);
2958 if (hildon_check_button_get_active (HILDON_CHECK_BUTTON (priv->show_toolbar_button)) != show_toolbar) {
2959 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->show_toolbar_button), show_toolbar);
2964 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2965 TnyHeaderFlags priority_flags)
2967 ModestMsgEditWindowPrivate *priv;
2968 ModestWindowPrivate *parent_priv;
2970 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2972 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2973 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2975 if (priv->priority_flags != priority_flags) {
2976 GtkAction *priority_action = NULL;
2978 priv->priority_flags = priority_flags;
2980 switch (priority_flags) {
2981 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2982 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2983 MODEST_HEADER_ICON_HIGH,
2984 HILDON_ICON_SIZE_SMALL);
2985 gtk_widget_show (priv->priority_icon);
2986 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2987 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2989 case TNY_HEADER_FLAG_LOW_PRIORITY:
2990 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2991 MODEST_HEADER_ICON_LOW,
2992 HILDON_ICON_SIZE_SMALL);
2993 gtk_widget_show (priv->priority_icon);
2994 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2995 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2998 gtk_widget_hide (priv->priority_icon);
2999 priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3000 "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3003 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3004 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3006 gtk_widget_queue_resize (priv->subject_box);
3010 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3013 ModestMsgEditWindowPrivate *priv;
3014 ModestWindowPrivate *parent_priv;
3015 gint current_format;
3017 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3019 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3020 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3022 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3023 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3025 gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3027 if (current_format != file_format) {
3028 switch (file_format) {
3029 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3030 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3031 remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3032 update_signature (window, priv->last_from_account, priv->last_from_account);
3033 if (parent_priv->toolbar)
3034 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
3035 MODEST_MSG_EDIT_WINDOW (window));
3037 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3041 dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3042 response = gtk_dialog_run (GTK_DIALOG (dialog));
3043 gtk_widget_destroy (dialog);
3044 if (response == GTK_RESPONSE_OK) {
3045 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3046 if (parent_priv->toolbar)
3047 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
3048 MODEST_MSG_EDIT_WINDOW (window));
3050 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3051 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3056 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3057 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3058 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3063 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3066 ModestMsgEditWindowPrivate *priv;
3067 WPTextBufferFormat oldfmt, fmt;
3068 gint old_position = 0;
3072 GdkColor *color = NULL;
3073 gboolean bold, bold_set, italic, italic_set;
3074 gboolean underline, underline_set;
3075 gboolean strikethrough, strikethrough_set;
3076 gboolean position_set;
3077 gboolean font_size_set, font_set, color_set;
3080 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3081 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3083 dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3084 modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3085 GTK_WINDOW(dialog), GTK_WINDOW (window));
3087 /* First we get the currently selected font information */
3088 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3090 switch (oldfmt.text_position) {
3091 case TEXT_POSITION_NORMAL:
3094 case TEXT_POSITION_SUPERSCRIPT:
3102 g_object_set (G_OBJECT (dialog),
3103 "bold", oldfmt.bold != FALSE,
3104 "bold-set", !oldfmt.cs.bold,
3105 "underline", oldfmt.underline != FALSE,
3106 "underline-set", !oldfmt.cs.underline,
3107 "italic", oldfmt.italic != FALSE,
3108 "italic-set", !oldfmt.cs.italic,
3109 "strikethrough", oldfmt.strikethrough != FALSE,
3110 "strikethrough-set", !oldfmt.cs.strikethrough,
3111 "color", &oldfmt.color,
3112 "color-set", !oldfmt.cs.color,
3113 "size", wp_font_size[oldfmt.font_size],
3114 "size-set", !oldfmt.cs.font_size,
3115 "position", old_position,
3116 "position-set", !oldfmt.cs.text_position,
3117 "family", wp_get_font_name (oldfmt.font),
3118 "family-set", !oldfmt.cs.font,
3121 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
3122 GTK_WINDOW (dialog), GTK_WINDOW (window));
3123 gtk_widget_show_all (dialog);
3124 priv->font_dialog = dialog;
3125 response = gtk_dialog_run (GTK_DIALOG (dialog));
3126 priv->font_dialog = NULL;
3127 if (response == GTK_RESPONSE_OK) {
3129 g_object_get( dialog,
3131 "bold-set", &bold_set,
3132 "underline", &underline,
3133 "underline-set", &underline_set,
3135 "italic-set", &italic_set,
3136 "strikethrough", &strikethrough,
3137 "strikethrough-set", &strikethrough_set,
3139 "color-set", &color_set,
3141 "size-set", &font_size_set,
3142 "family", &font_name,
3143 "family-set", &font_set,
3144 "position", &position,
3145 "position-set", &position_set,
3150 if (response == GTK_RESPONSE_OK) {
3151 memset(&fmt, 0, sizeof(fmt));
3157 fmt.italic = italic;
3158 fmt.cs.italic = TRUE;
3160 if (underline_set) {
3161 fmt.underline = underline;
3162 fmt.cs.underline = TRUE;
3164 if (strikethrough_set) {
3165 fmt.strikethrough = strikethrough;
3166 fmt.cs.strikethrough = TRUE;
3171 ? TEXT_POSITION_NORMAL
3172 : ( ( position == 1 )
3173 ? TEXT_POSITION_SUPERSCRIPT
3174 : TEXT_POSITION_SUBSCRIPT );
3175 fmt.cs.text_position = TRUE;
3176 fmt.font_size = oldfmt.font_size;
3180 fmt.cs.color = TRUE;
3183 fmt.font = wp_get_font_index(font_name,
3188 if (font_size_set) {
3189 fmt.cs.font_size = TRUE;
3190 fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3192 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3193 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3195 gtk_widget_destroy (dialog);
3197 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3201 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3203 ModestMsgEditWindowPrivate *priv;
3204 ModestWindowPrivate *parent_priv;
3205 gboolean was_rich_text, is_rich_text;
3207 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3208 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3209 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3211 was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3213 wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3215 is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3217 if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3218 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
3219 MODEST_MSG_EDIT_WINDOW (window));
3222 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3223 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3227 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3229 ModestMsgEditWindowPrivate *priv;
3231 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3232 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3234 wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3236 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3237 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3242 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3244 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3246 priv->can_undo = can_undo;
3250 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3252 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3254 priv->can_redo = can_redo;
3258 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3260 ModestMsgEditWindowPrivate *priv;
3261 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3262 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3264 return priv->can_undo;
3268 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3270 ModestMsgEditWindowPrivate *priv;
3271 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3272 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3274 return priv->can_redo;
3279 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3282 GtkTextIter match_start, match_end;
3284 if (image_id == NULL)
3287 gtk_text_buffer_get_start_iter (buffer, &iter);
3289 while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3290 GSList *tags = gtk_text_iter_get_tags (&match_start);
3292 for (node = tags; node != NULL; node = g_slist_next (node)) {
3293 GtkTextTag *tag = (GtkTextTag *) node->data;
3294 if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3295 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3296 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3298 offset = gtk_text_iter_get_offset (&match_start);
3299 gtk_text_buffer_delete (buffer, &match_start, &match_end);
3300 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3304 gtk_text_iter_forward_char (&iter);
3309 message_is_empty (ModestMsgEditWindow *window)
3311 ModestMsgEditWindowPrivate *priv = NULL;
3313 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3314 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3316 /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3317 * so we can ignore markup.
3319 GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3322 count = gtk_text_buffer_get_char_count (buf);
3328 msg_body_focus (GtkWidget *focus,
3329 GdkEventFocus *event,
3333 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3334 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3335 modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3340 recpt_field_changed (GtkTextBuffer *buffer,
3341 ModestMsgEditWindow *editor)
3343 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3344 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3348 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3350 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3351 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3355 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3358 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3359 GtkTextBuffer *buffer;
3361 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3362 gtk_text_buffer_set_modified (buffer, modified);
3363 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3364 gtk_text_buffer_set_modified (buffer, modified);
3365 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3366 gtk_text_buffer_set_modified (buffer, modified);
3367 gtk_text_buffer_set_modified (priv->text_buffer, modified);
3371 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3373 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3374 const char *account_name;
3375 GtkTextBuffer *buffer;
3377 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3378 if (gtk_text_buffer_get_modified (buffer))
3380 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3381 if (gtk_text_buffer_get_modified (buffer))
3383 buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3384 if (gtk_text_buffer_get_modified (buffer))
3386 if (gtk_text_buffer_get_modified (priv->text_buffer))
3389 account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3390 if (priv->original_mailbox) {
3391 if (!account_name || strcmp (account_name, priv->original_mailbox))
3393 } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3404 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3406 ModestMsgEditWindowPrivate *priv = NULL;
3407 GSList *address_list = NULL;
3408 gboolean no_to, no_cc, no_bcc;
3410 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3411 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3413 /* check if there's no recipient added */
3414 no_to = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)));
3415 no_cc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field)));
3416 no_bcc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field)));
3419 if (no_to && no_cc && no_bcc) {
3420 /* no recipient contents, then select contacts */
3421 modest_msg_edit_window_open_addressbook (window, NULL);
3426 g_object_ref (window);
3427 if (!no_to && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3428 (add_to_addressbook) ? &address_list : NULL)) {
3429 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3430 g_object_unref (window);
3433 if (!no_cc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3434 (add_to_addressbook) ? &address_list : NULL)) {
3435 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3436 g_object_unref (window);
3439 if (!no_bcc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3440 (add_to_addressbook) ? &address_list : NULL)) {
3441 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3442 g_object_unref (window);
3446 /* Add contacts to address book */
3447 if (add_to_addressbook && address_list)
3448 modest_address_book_add_address_list (address_list);
3450 if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3451 !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3452 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3453 g_object_unref (window);
3460 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3462 GSList *recipients = NULL;
3463 ModestMsgEditWindowPrivate *priv;
3464 gchar *joined, *after_remove, *to, *cc, *bcc;
3466 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3468 /* First of all check names */
3469 if (!modest_msg_edit_window_check_names (self, FALSE))
3472 if (!modest_msg_edit_window_has_pending_addresses (self))
3475 /* Don't add the from obviously */
3476 to = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3477 cc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3478 bcc = g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3480 joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3485 after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3488 recipients = modest_text_utils_split_addresses_list (after_remove);
3489 g_free (after_remove);
3492 /* Offer the user to add recipients to the address book */
3493 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3494 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3499 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3500 ModestMsgEditWindow *window)
3502 modest_msg_edit_window_offer_attach_file (window);
3506 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3508 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3510 return priv->clipboard_text;
3514 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3516 ModestMsgEditWindow *window)
3518 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3519 GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3522 /* It could happen that the window was already closed */
3523 if (!GTK_WIDGET_VISIBLE (window))
3526 g_object_ref (window);
3527 text = gtk_clipboard_wait_for_text (selection_clipboard);
3529 if (priv->clipboard_text != NULL) {
3530 g_free (priv->clipboard_text);
3532 priv->clipboard_text = text;
3534 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3536 g_object_unref (window);
3539 static gboolean clipboard_owner_change_idle (gpointer userdata)
3541 ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3542 ModestMsgEditWindowPrivate *priv;
3544 gdk_threads_enter ();
3545 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3546 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3548 priv->clipboard_owner_idle = 0;
3549 modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3550 gdk_threads_leave ();
3556 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3558 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3559 if (priv->clipboard_owner_idle == 0) {
3560 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3561 clipboard_owner_change_idle,
3562 g_object_ref (window),
3568 subject_field_move_cursor (GtkEntry *entry,
3569 GtkMovementStep step,
3574 /* It could happen that the window was already closed */
3575 if (!GTK_WIDGET_VISIBLE (window))
3578 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3582 update_window_title (ModestMsgEditWindow *window)
3584 ModestMsgEditWindowPrivate *priv = NULL;
3585 const gchar *subject;
3587 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3588 subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3589 if (subject == NULL || subject[0] == '\0')
3590 subject = _("mail_va_new_email");
3592 gtk_window_set_title (GTK_WINDOW (window), subject);
3598 body_insert_text (GtkTextBuffer *buffer,
3599 GtkTextIter *location,
3602 ModestMsgEditWindow *window)
3604 GtkTextIter end_iter;
3611 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3613 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3615 offset = gtk_text_iter_get_offset (&end_iter);
3616 line = gtk_text_iter_get_line (&end_iter);
3620 while (text_offset < text + len) {
3621 if (*text_offset == '\n')
3623 if (text_lines + line >= MAX_BODY_LINES) {
3624 len = text_offset - text;
3630 utf8_len = g_utf8_strlen (text, len);
3632 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3633 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3634 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3639 utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3641 /* Prevent endless recursion */
3642 result = g_strndup (text, utf8_end - text);
3643 g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3644 g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3645 (gpointer) result, (gpointer) (utf8_end - text),
3647 g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3651 if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3652 if (priv->max_chars_banner == NULL) {
3653 priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL,
3654 _CS("ckdg_ib_maximum_characters_reached"));
3655 g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3661 subject_field_changed (GtkEditable *editable,
3662 ModestMsgEditWindow *window)
3664 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3665 update_window_title (window);
3666 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3667 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3668 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3671 subject_field_insert_text (GtkEditable *editable,
3673 gint new_text_length,
3675 ModestMsgEditWindow *window)
3677 GString *result = g_string_new ("");
3679 gint result_len = 0;
3680 const gchar *entry_text = NULL;
3683 entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3684 old_length = g_utf8_strlen (entry_text, -1);
3686 for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3687 gunichar c = g_utf8_get_char_validated (current, 8);
3688 /* Invalid unichar, stop */
3694 result = g_string_append_unichar (result, c);
3698 if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3699 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3702 /* Prevent endless recursion */
3703 g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3704 g_signal_emit_by_name (editable, "insert-text",
3705 (gpointer) result->str, (gpointer) result->len,
3706 (gpointer) position, (gpointer) window);
3707 g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3711 if (result_len + old_length > 1000) {
3712 hildon_banner_show_information (GTK_WIDGET (window), NULL,
3713 _CS("ckdg_ib_maximum_characters_reached"));
3715 g_string_free (result, TRUE);
3719 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3722 ModestMsgEditWindowPrivate *priv = NULL;
3724 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3725 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3727 gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3730 gtk_widget_show_all (priv->find_toolbar);
3731 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3733 gtk_widget_hide_all (priv->find_toolbar);
3734 gtk_widget_grab_focus (priv->msg_body);
3739 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3741 GtkTextIter *match_start,
3742 GtkTextIter *match_end)
3744 GtkTextIter end_iter;
3745 gchar *str_casefold;
3748 gchar *range_casefold;
3751 gboolean result = FALSE;
3758 gtk_text_iter_forward_to_end (&end_iter);
3760 str_casefold = g_utf8_casefold (str, -1);
3761 str_chars_n = strlen (str);
3763 range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3764 range_casefold = g_utf8_casefold (range_text, -1);
3765 range_chars_n = strlen (range_casefold);
3767 if (range_chars_n < str_chars_n) {
3768 g_free (str_casefold);
3769 g_free (range_text);
3770 g_free (range_casefold);
3774 for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3775 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3776 if (!g_utf8_collate (range_subtext, str_casefold)) {
3777 gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3779 if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3780 match_start, match_end, NULL)) {
3781 g_debug ("Matched string with collate, but not matched in model");
3783 g_free (found_text);
3785 g_free (range_subtext);
3789 g_free (str_casefold);
3790 g_free (range_text);
3791 g_free (range_casefold);
3798 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3799 ModestMsgEditWindow *window)
3801 gchar *current_search = NULL;
3802 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3804 GtkTextIter selection_start, selection_end;
3805 GtkTextIter match_start, match_end;
3806 gboolean continue_search = FALSE;
3808 if (message_is_empty (window)) {
3809 g_free (priv->last_search);
3810 priv->last_search = NULL;
3811 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3815 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
3816 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3817 g_free (current_search);
3818 g_free (priv->last_search);
3819 priv->last_search = NULL;
3820 /* Information banner about empty search */
3821 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3825 if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3826 continue_search = TRUE;
3828 g_free (priv->last_search);
3829 priv->last_search = g_strdup (current_search);
3832 if (continue_search) {
3833 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3834 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search,
3835 &match_start, &match_end);
3837 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3839 GtkTextIter buffer_start;
3840 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3841 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search,
3842 &match_start, &match_end);
3844 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3847 /* Mark as selected the string found in search */
3849 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3850 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3851 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3853 g_free (priv->last_search);
3854 priv->last_search = NULL;
3856 g_free (current_search);
3860 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3862 ModestMsgEditWindowPrivate *priv;
3864 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3869 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window,
3872 ModestMsgEditWindowPrivate *priv;
3874 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3879 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3880 ModestMsgEditWindow *window)
3882 modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3886 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3889 ModestMsgEditWindowPrivate *priv;
3890 TnyHeader *header = NULL;
3892 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3893 g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3895 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3897 if (priv->draft_msg != NULL) {
3898 g_object_unref (priv->draft_msg);
3901 if (draft != NULL) {
3902 g_object_ref (draft);
3903 header = tny_msg_get_header (draft);
3904 if (priv->msg_uid) {
3905 g_free (priv->msg_uid);
3906 priv->msg_uid = NULL;
3908 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3911 priv->draft_msg = draft;
3915 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag,
3916 GtkTextIter *start, GtkTextIter *end,
3919 ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3920 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3923 if (tag == NULL) return;
3924 g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3925 if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3926 replace_with_images (window, priv->images);
3931 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3934 ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3936 g_return_if_fail (TNY_IS_MIME_PART (part));
3937 tny_list_prepend (priv->attachments, (GObject *) part);
3938 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3939 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3940 gtk_widget_show_all (priv->attachments_caption);
3941 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3945 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3947 ModestMsgEditWindowPrivate *priv;
3949 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);
3950 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3952 return priv->msg_uid;
3956 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3957 ModestMsgEditWindowWidgetType widget_type)
3959 ModestMsgEditWindowPrivate *priv;
3961 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3962 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3964 switch (widget_type) {
3965 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3966 return priv->msg_body;
3968 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3969 return priv->to_field;
3971 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3972 return priv->cc_field;
3974 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3975 return priv->bcc_field;
3977 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3978 return priv->subject_field;
3980 case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3981 return priv->attachments_view;
3989 remove_tags (WPTextBuffer *buffer)
3991 GtkTextIter start, end;
3993 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3994 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3996 gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4000 on_account_removed (TnyAccountStore *account_store,
4001 TnyAccount *account,
4004 /* Do nothing if it's a store account, because we use the
4005 transport to send the messages */
4006 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4007 const gchar *parent_acc = NULL;
4008 const gchar *our_acc = NULL;
4010 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4011 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4012 /* Close this window if I'm showing a message of the removed account */
4013 if (strcmp (parent_acc, our_acc) == 0)
4014 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4019 update_signature (ModestMsgEditWindow *self,
4020 const gchar *old_account,
4021 const gchar *new_account)
4023 ModestMsgEditWindowPrivate *priv;
4024 gboolean has_old_signature, has_new_signature;
4026 ModestAccountMgr *mgr;
4029 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4031 gtk_text_buffer_begin_user_action (priv->text_buffer);
4033 gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4034 mgr = modest_runtime_get_account_mgr ();
4038 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4039 if (has_old_signature) {
4040 GtkTextIter match_start, match_end;
4042 MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4043 seems that the search has some problems
4044 with the blank space at the end */
4045 if (gtk_text_iter_forward_search (&iter, "--",
4046 GTK_TEXT_SEARCH_TEXT_ONLY,
4047 &match_start, NULL, NULL)) {
4048 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4049 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4051 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4052 &match_start, &match_end, NULL)) {
4056 gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4061 priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4062 signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4063 if (has_new_signature) {
4066 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4067 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4069 is_rich = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
4071 WPTextBufferFormat *fmt;
4072 GdkColor style_color;
4073 if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
4074 gdk_color_parse ("grey", &style_color);
4076 fmt = g_new0 (WPTextBufferFormat, 1);
4077 fmt->color = style_color;
4078 fmt->cs.color = 0x1;
4079 wp_text_buffer_insert_with_attribute (WP_TEXT_BUFFER (priv->text_buffer), &iter,
4083 g_free (full_signature);
4085 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4089 gtk_text_buffer_end_user_action (priv->text_buffer);
4092 static void update_branding (ModestMsgEditWindow *self,
4093 const gchar *new_account)
4095 ModestMsgEditWindowPrivate *priv;
4096 ModestAccountMgr *mgr;
4097 const GdkPixbuf *new_icon = NULL;
4098 gchar *new_label = NULL;
4099 gboolean show = FALSE;
4101 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4103 mgr = modest_runtime_get_account_mgr ();
4105 modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4107 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4108 gtk_widget_show (priv->brand_icon);
4111 gtk_widget_hide (priv->brand_icon);
4114 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4115 gtk_widget_show (priv->brand_label);
4119 gtk_widget_hide (priv->brand_label);
4123 gtk_widget_show (priv->brand_container);
4125 gtk_widget_hide (priv->brand_container);
4129 from_field_changed (HildonPickerButton *button,
4130 ModestMsgEditWindow *self)
4132 ModestMsgEditWindowPrivate *priv;
4133 gchar *old_account, *new_account;
4135 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4137 old_account = priv->last_from_account;
4138 new_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4141 g_warning ("%s, could not get the new account", __FUNCTION__);
4145 /* If the From is the same do nothing */
4146 if (old_account && new_account && !strcmp (old_account, new_account))
4149 priv->last_from_account = new_account;
4151 update_signature (self, old_account, new_account);
4152 update_branding (self, new_account);
4156 typedef struct _MessageSettingsHelper {
4157 ModestMsgEditWindow *window;
4158 GSList *priority_group;
4159 GSList *format_group;
4160 GtkToggleButton *current_priority;
4161 GtkToggleButton *current_format;
4162 } MessageSettingsHelper;
4165 on_priority_toggle (GtkToggleButton *button,
4166 MessageSettingsHelper *helper)
4169 ModestMsgEditWindowPrivate *priv;
4171 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4172 if (gtk_toggle_button_get_active (button)) {
4174 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4175 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4176 if ((node_button != button) &&
4177 gtk_toggle_button_get_active (node_button)) {
4178 gtk_toggle_button_set_active (node_button, FALSE);
4181 helper->current_priority = button;
4183 gboolean found = FALSE;
4184 /* If no one is active, activate it again */
4185 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4186 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4187 if (gtk_toggle_button_get_active (node_button)) {
4193 gtk_toggle_button_set_active (button, TRUE);
4199 on_format_toggle (GtkToggleButton *button,
4200 MessageSettingsHelper *helper)
4203 ModestMsgEditWindowPrivate *priv;
4205 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4206 if (gtk_toggle_button_get_active (button)) {
4208 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4209 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4210 if ((node_button != button) &&
4211 gtk_toggle_button_get_active (node_button)) {
4212 gtk_toggle_button_set_active (node_button, FALSE);
4215 helper->current_format = button;
4217 gboolean found = FALSE;
4218 /* If no one is active, activate it again */
4219 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4220 GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4221 if (gtk_toggle_button_get_active (node_button)) {
4227 gtk_toggle_button_set_active (button, TRUE);
4234 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4239 GtkWidget *priority_hbox;
4240 GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4241 GtkWidget *captioned;
4242 GtkSizeGroup *title_sizegroup, *value_sizegroup;
4243 GtkWidget *format_hbox;
4244 GtkWidget *html_toggle, *text_toggle;
4245 ModestMsgEditWindowPrivate *priv;
4246 MessageSettingsHelper helper = {0,};
4248 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4249 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4250 helper.window = window;
4251 helper.priority_group = NULL;
4252 helper.format_group = NULL;
4254 title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4255 value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4257 dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4258 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4259 _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4260 vbox = gtk_vbox_new (FALSE, 0);
4261 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4262 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4263 gtk_container_add (GTK_CONTAINER (align), vbox);
4264 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4265 gtk_widget_show (align);
4266 gtk_widget_show (vbox);
4268 /* Priority toggles */
4269 priority_hbox = gtk_hbox_new (TRUE, 0);
4270 high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4271 gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4272 helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4273 g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4274 medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4275 gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4276 helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4277 g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4278 low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4279 gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4280 helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4281 g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4282 gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4283 gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4284 gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4285 gtk_widget_show_all (priority_hbox);
4286 captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4287 _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4288 gtk_widget_show (captioned);
4289 gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4291 /* format toggles */
4292 format_hbox = gtk_hbox_new (TRUE, 0);
4293 html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4294 gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4295 helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4296 g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4297 g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4298 text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4299 gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4300 helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4301 g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4302 g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4303 gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4304 gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4305 gtk_widget_show_all (format_hbox);
4306 gtk_widget_show (format_hbox);
4307 gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4310 g_object_unref (title_sizegroup);
4311 g_object_unref (value_sizegroup);
4313 /* Set current values */
4314 switch (priv->priority_flags) {
4315 case TNY_HEADER_FLAG_HIGH_PRIORITY:
4316 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4317 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4319 case TNY_HEADER_FLAG_LOW_PRIORITY:
4320 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4321 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4324 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4325 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4329 switch (modest_msg_edit_window_get_format (window)) {
4330 case MODEST_MSG_EDIT_FORMAT_TEXT:
4331 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4332 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4334 case MODEST_MSG_EDIT_FORMAT_HTML:
4336 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4337 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4341 /* Signal connects */
4342 g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4343 g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4344 g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4345 g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4346 g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4348 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4349 GTK_WINDOW (dialog), GTK_WINDOW (window));
4351 /* Save settings if the user clicked on done */
4352 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4353 TnyHeaderFlags flags;
4354 ModestMsgEditFormat old_format, new_format;
4356 /* Set priority flags */
4357 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4358 if (priv->priority_flags != flags)
4359 modest_msg_edit_window_set_priority_flags (window, flags);
4361 /* Set edit format */
4362 old_format = modest_msg_edit_window_get_format (window);
4363 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4364 if (old_format != new_format) {
4365 gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4366 modest_msg_edit_window_set_file_format (window, file_format);
4370 gtk_widget_destroy (dialog);
4371 g_slist_free (helper.priority_group);
4375 on_message_settings (GtkAction *action,
4376 ModestMsgEditWindow *window)
4378 modest_msg_edit_window_show_msg_settings_dialog (window);
4382 on_show_toolbar_button_toggled (HildonCheckButton *button,
4383 ModestMsgEditWindow *window)
4385 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4387 modest_msg_edit_window_show_toolbar (MODEST_WINDOW (window),
4388 hildon_check_button_get_active (button));
4392 on_cc_button_toggled (HildonCheckButton *button,
4393 ModestMsgEditWindow *window)
4395 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4397 modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4398 hildon_check_button_get_active (button));
4402 on_bcc_button_toggled (HildonCheckButton *button,
4403 ModestMsgEditWindow *window)
4405 g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4407 modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4408 hildon_check_button_get_active (button));
4412 setup_menu (ModestMsgEditWindow *self)
4414 ModestMsgEditWindowPrivate *priv = NULL;
4416 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4418 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4420 /* Settings menu buttons */
4421 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4422 APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4424 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4425 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4426 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4427 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4428 APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4429 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4431 priv->cc_button = hildon_check_button_new (0);
4432 gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4433 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4435 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4437 g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4438 G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4439 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4440 gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4442 priv->bcc_button = hildon_check_button_new (0);
4443 gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4444 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4446 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4448 g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4449 G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4450 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4451 gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4453 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4454 APP_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4456 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4457 APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4458 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4459 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4460 APP_MENU_CALLBACK (on_message_settings),
4462 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4463 APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4465 priv->show_toolbar_button = hildon_check_button_new (0);
4466 gtk_button_set_label (GTK_BUTTON (priv->show_toolbar_button), _("mcen_bd_show_toolbar"));
4467 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
4469 modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->show_toolbar_button),
4470 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_show_toolbar));
4471 g_signal_connect (G_OBJECT (priv->show_toolbar_button), "toggled",
4472 G_CALLBACK (on_show_toolbar_button_toggled), (gpointer) self);
4473 gtk_button_set_alignment (GTK_BUTTON (priv->show_toolbar_button), 0.5, 0.5);
4474 gtk_button_set_alignment (GTK_BUTTON (priv->show_toolbar_button), 0.5, 0.5);
4479 emit_open_addressbook (GtkButton *button,
4480 ModestRecptEditor *editor)
4482 g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4486 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4487 const gchar *label, GtkWidget *control)
4489 GtkWidget *abook_button;
4492 GtkWidget *label_widget;
4494 box = gtk_hbox_new (FALSE, 0);
4496 align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4497 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4499 abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4500 label_widget = gtk_label_new (label);
4501 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4502 gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4504 gtk_container_add (GTK_CONTAINER (align), abook_button);
4505 gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4506 gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4507 gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4508 if (title_size_group)
4509 gtk_size_group_add_widget (title_size_group, label_widget);
4510 if (value_size_group)
4511 gtk_size_group_add_widget (value_size_group, control);
4513 g_signal_connect (G_OBJECT (abook_button), "clicked",
4514 G_CALLBACK (emit_open_addressbook), control);
4520 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4522 ModestMsgEditWindowPrivate *priv = NULL;
4524 g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4526 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4527 priv->max_chars_banner = NULL;
4531 has_pending_addresses (ModestRecptEditor *recpt_editor)
4533 const gchar *recipients = NULL;
4534 GSList *start_indexes = NULL, *end_indexes = NULL;
4535 GSList *current_start, *current_end;
4536 GtkTextBuffer *buffer;
4537 gint offset_delta = 0;
4539 gboolean has_recipients_to_add = FALSE;
4541 recipients = modest_recpt_editor_get_recipients (recpt_editor);
4542 last_length = g_utf8_strlen (recipients, -1);
4543 modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4548 current_start = start_indexes;
4549 current_end = end_indexes;
4550 buffer = modest_recpt_editor_get_buffer (recpt_editor);
4552 while (current_start && !has_recipients_to_add) {
4554 gchar *start_ptr, *end_ptr;
4555 gint start_pos, end_pos;
4557 start_pos = (*((gint*) current_start->data)) + offset_delta;
4558 end_pos = (*((gint*) current_end->data)) + offset_delta;
4560 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4561 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4563 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4565 if (modest_text_utils_validate_recipient (address, NULL)) {
4566 if (!modest_address_book_has_address (address)) {
4567 has_recipients_to_add = TRUE;
4570 current_start = g_slist_next (current_start);
4571 current_end = g_slist_next (current_end);
4573 return has_recipients_to_add;
4577 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4579 ModestMsgEditWindowPrivate *priv = NULL;
4581 g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4583 priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4585 if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4586 !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4587 !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))