Set grey color for the arrow in size tool button with sensitiveness
[modest] / src / hildon2 / modest-msg-edit-window.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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.
16  *
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.
28  */
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n.h>
32 #include <fcntl.h>
33 #include <glib/gstdio.h>
34 #include <string.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
40 #include <config.h>
41
42 #include <modest-account-mgr.h>
43 #include <modest-account-mgr-helpers.h>
44
45 #include <widgets/modest-msg-edit-window.h>
46 #include <modest-selector-picker.h>
47 #include <widgets/modest-recpt-editor.h>
48 #include <widgets/modest-attachments-view.h>
49
50 #include <modest-runtime.h>
51
52 #include "modest-platform.h"
53 #include "modest-icon-names.h"
54 #include "modest-widget-memory.h"
55 #include "modest-window-priv.h"
56 #include "modest-mail-operation.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-tny-folder.h"
60 #include "modest-tny-account.h"
61 #include "modest-address-book.h"
62 #include "modest-text-utils.h"
63 #include <tny-simple-list.h>
64 #include <modest-wp-text-view.h>
65 #include <wptextbuffer.h>
66 #include <hildon/hildon-pannable-area.h>
67 #include <hildon/hildon-touch-selector.h>
68 #include <hildon/hildon-picker-dialog.h>
69 #include "modest-msg-edit-window-ui-dimming.h"
70
71 #include "modest-hildon-includes.h"
72 #ifdef MODEST_HAVE_HILDON0_WIDGETS
73 #include <hildon-widgets/hildon-color-chooser.h>
74 #endif
75 #include "widgets/modest-msg-edit-window-ui.h"
76 #ifdef MODEST_HAVE_HILDON0_WIDGETS
77 #include <libgnomevfs/gnome-vfs-mime-utils.h>
78 #else
79 #include <libgnomevfs/gnome-vfs-mime.h>
80 #endif
81 #include <modest-utils.h>
82 #include "modest-maemo-utils.h"
83 #include <modest-ui-constants.h>
84
85
86 #define DEFAULT_FONT_SIZE 3
87 #define DEFAULT_FONT 2
88 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
89 #define DEFAULT_MAIN_VBOX_SPACING 6
90 #define SUBJECT_MAX_LENGTH 1000
91 #define IMAGE_MAX_WIDTH 560
92 #define DEFAULT_FONT_SCALE 1.5
93 #define ATTACHMENT_BUTTON_WIDTH 118
94
95 static gboolean is_wp_text_buffer_started = FALSE;
96
97 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
98 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
99 static void  modest_msg_edit_window_finalize     (GObject *obj);
100
101 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
102 static void  body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
103 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
104
105 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
106 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
107 static void  text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
108 static void  text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
109                                     GtkTextIter *start, GtkTextIter *end,
110                                     gpointer userdata);
111 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
112 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
113 static void  subject_field_insert_text (GtkEditable *editable, 
114                                         gchar *new_text,
115                                         gint new_text_length,
116                                         gint *position,
117                                         ModestMsgEditWindow *window);
118 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
119                                                          gpointer userdata);
120 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
121
122 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
123                                                      ModestRecptEditor *editor);
124 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
125                                                            ModestMsgEditWindow *window);
126
127 /* ModestWindow methods implementation */
128 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
129 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
130                                                    gboolean show_toolbar);
131 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
132                                                            GdkEvent *event,
133                                                            ModestMsgEditWindow *window);
134 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
135 static void subject_field_move_cursor (GtkEntry *entry,
136                                        GtkMovementStep step,
137                                        gint a1,
138                                        gboolean a2,
139                                        gpointer userdata);
140 static void update_window_title (ModestMsgEditWindow *window);
141
142 /* Find toolbar */
143 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
144                                                         ModestMsgEditWindow *window);
145 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
146                                                        ModestMsgEditWindow *window);
147 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
148                                                           const gchar *str,
149                                                           GtkTextIter *match_start,
150                                                           GtkTextIter *match_end);
151
152 static void remove_tags (WPTextBuffer *buffer);
153
154 static void on_account_removed (TnyAccountStore *account_store, 
155                                 TnyAccount *account,
156                                 gpointer user_data);
157
158 static void init_window (ModestMsgEditWindow *obj);
159
160 gboolean scroll_drag_timeout (gpointer userdata);
161 static void correct_scroll (ModestMsgEditWindow *w);
162 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
163 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
164                                          ModestMsgEditWindow *userdata);
165 static void text_buffer_mark_set (GtkTextBuffer *buffer,
166                                   GtkTextIter *iter,
167                                   GtkTextMark *mark,
168                                   ModestMsgEditWindow *userdata);
169 static void on_message_settings (GtkAction *action,
170                                  ModestMsgEditWindow *window);
171 static void setup_menu (ModestMsgEditWindow *self);
172
173 static void from_field_changed (HildonPickerButton *button,
174                                 ModestMsgEditWindow *self);
175 static void font_size_clicked (GtkToolButton *button,
176                                ModestMsgEditWindow *window);
177 static void font_face_clicked (GtkToolButton *button,
178                                ModestMsgEditWindow *window);
179 static void DEBUG_BUFFER (WPTextBuffer *buffer)
180 {
181 #ifdef DEBUG
182         GtkTextIter iter;
183         g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
184
185         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
186         while (!gtk_text_iter_is_end (&iter)) {
187                 GString *output = g_string_new ("");
188                 GSList *toggled_tags;
189                 GSList *node;
190
191                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
192                 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
193                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
194                         GtkTextTag *tag = (GtkTextTag *) node->data;
195                         const gchar *name;
196                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
197                         output = g_string_append (output, name);
198                         g_string_append (output, " ");
199                 }
200                 output = g_string_append (output, "] OPENED [ ");
201                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
202                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
203                         GtkTextTag *tag = (GtkTextTag *) node->data;
204                         const gchar *name;
205                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
206                         output = g_string_append (output, name);
207                         g_string_append (output, " ");
208                 }
209                 output = g_string_append (output, "]\n");
210                 g_message ("%s", output->str);
211                 g_string_free (output, TRUE);
212                 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
213         }
214         g_message ("END BUFFER");
215 #endif
216 }
217
218 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
219         { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
220 };
221
222
223 /* static gboolean */
224 /* on_key_pressed (GtkWidget *self, */
225 /*              GdkEventKey *event, */
226 /*              gpointer user_data); */
227
228 /* list my signals */
229 enum {
230         /* MY_SIGNAL_1, */
231         /* MY_SIGNAL_2, */
232         LAST_SIGNAL
233 };
234
235 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
236 struct _ModestMsgEditWindowPrivate {
237         GtkWidget   *msg_body;
238         GtkWidget   *header_box;
239         
240         ModestPairList *from_field_protos;
241         GtkWidget   *from_field;
242         gchar       *last_from_account;
243         gchar       *original_account_name;
244         
245         GtkWidget   *to_field;
246         GtkWidget   *cc_field;
247         GtkWidget   *bcc_field;
248         GtkWidget   *subject_field;
249         GtkWidget   *attachments_view;
250         GtkWidget   *priority_icon;
251         GtkWidget   *subject_box;
252         GtkWidget   *add_attachment_button;
253
254         GtkWidget   *cc_caption;
255         GtkWidget   *bcc_caption;
256         gboolean     update_caption_visibility;
257         GtkWidget   *attachments_caption;
258
259         GtkTextBuffer *text_buffer;
260
261         GtkWidget   *font_size_toolitem;
262         GtkWidget   *font_face_toolitem;
263         GtkWidget   *font_color_button;
264         GtkWidget   *font_color_toolitem;
265         GSList      *font_items_group;
266         GtkTreeModel *faces_model;
267         gint         current_face_index;
268         GtkWidget   *font_tool_button_label;
269         GtkTreeModel *sizes_model;
270         gint         current_size_index;
271         GtkWidget   *size_tool_button_label;
272
273         GtkWidget   *find_toolbar;
274         gchar       *last_search;
275
276         GtkWidget   *font_dialog;
277
278         GtkWidget   *pannable;
279         guint        correct_scroll_idle;
280         guint        scroll_drag_timeout_id;
281         gdouble      last_upper;
282
283         gint next_cid;
284         TnyList *attachments;
285         TnyList *images;
286         guint64 images_size;
287         gint images_count;
288
289         TnyHeaderFlags priority_flags;
290
291         gboolean    can_undo, can_redo;
292         gulong      clipboard_change_handler_id;
293         gulong      default_clipboard_change_handler_id;
294         gulong      account_removed_handler_id;
295         guint       clipboard_owner_idle;
296         gchar       *clipboard_text;
297
298         TnyMsg      *draft_msg;
299         TnyMsg      *outbox_msg;
300         gchar       *msg_uid;
301
302         gboolean    sent;
303
304         GtkWidget   *app_menu;
305         GtkWidget   *cc_button;
306         GtkWidget   *bcc_button;
307 };
308
309 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
310                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
311                                                     ModestMsgEditWindowPrivate))
312 /* globals */
313 static GtkWindowClass *parent_class = NULL;
314
315 /* uncomment the following if you have defined any signals */
316 /* static guint signals[LAST_SIGNAL] = {0}; */
317
318 GType
319 modest_msg_edit_window_get_type (void)
320 {
321         static GType my_type = 0;
322         if (!my_type) {
323                 static const GTypeInfo my_info = {
324                         sizeof(ModestMsgEditWindowClass),
325                         NULL,           /* base init */
326                         NULL,           /* base finalize */
327                         (GClassInitFunc) modest_msg_edit_window_class_init,
328                         NULL,           /* class finalize */
329                         NULL,           /* class data */
330                         sizeof(ModestMsgEditWindow),
331                         1,              /* n_preallocs */
332                         (GInstanceInitFunc) modest_msg_edit_window_init,
333                         NULL
334                 };
335                 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
336                                                   "ModestMsgEditWindow",
337                                                   &my_info, 0);
338
339         }
340         return my_type;
341 }
342
343 static void
344 save_state (ModestWindow *self)
345 {
346         modest_widget_memory_save (modest_runtime_get_conf(),
347                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
348 }
349
350
351 static void
352 restore_settings (ModestMsgEditWindow *self)
353 {
354         ModestConf *conf = NULL;
355
356         conf = modest_runtime_get_conf ();
357
358         /* Dim at start clipboard actions */
359         modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
360 }
361
362
363 static void
364 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
365 {
366         GObjectClass *gobject_class;
367         ModestWindowClass *modest_window_class;
368         gobject_class = (GObjectClass*) klass;
369         modest_window_class = (ModestWindowClass*) klass;
370
371         parent_class            = g_type_class_peek_parent (klass);
372         gobject_class->finalize = modest_msg_edit_window_finalize;
373
374         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
375         modest_window_class->save_state_func = save_state;
376         modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
377
378         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
379 }
380
381 static void
382 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
383 {
384         ModestMsgEditWindowPrivate *priv;
385         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
386
387         priv->msg_body      = NULL;
388         priv->from_field    = NULL;
389         priv->to_field      = NULL;
390         priv->cc_field      = NULL;
391         priv->bcc_field     = NULL;
392         priv->subject_field = NULL;
393         priv->attachments   = TNY_LIST (tny_simple_list_new ());
394         priv->images        = TNY_LIST (tny_simple_list_new ());
395         priv->images_size   = 0;
396         priv->images_count  = 0;
397         priv->next_cid      = 0;
398
399         priv->cc_caption    = NULL;
400         priv->bcc_caption    = NULL;
401         priv->update_caption_visibility = FALSE;
402
403         priv->priority_flags = 0;
404
405         priv->find_toolbar = NULL;
406         priv->last_search = NULL;
407
408         priv->draft_msg = NULL;
409         priv->outbox_msg = NULL;
410         priv->msg_uid = NULL;
411
412         priv->can_undo = FALSE;
413         priv->can_redo = FALSE;
414         priv->clipboard_change_handler_id = 0;
415         priv->default_clipboard_change_handler_id = 0;
416         priv->account_removed_handler_id = 0;
417         priv->clipboard_owner_idle = 0;
418         priv->clipboard_text = NULL;
419         priv->sent = FALSE;
420
421         priv->scroll_drag_timeout_id = 0;
422         priv->correct_scroll_idle = 0;
423         priv->last_upper = 0.0;
424
425         priv->font_dialog = NULL;
426         priv->app_menu = NULL;
427
428         if (!is_wp_text_buffer_started) {
429                 is_wp_text_buffer_started = TRUE;
430                 wp_text_buffer_library_init ();
431         }
432
433         init_window (obj);
434         
435         hildon_program_add_window (hildon_program_get_instance(),
436                                    HILDON_WINDOW(obj));
437 }
438
439
440 /** 
441  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
442  */
443 static ModestPairList*
444 get_transports (void)
445 {
446         GSList *transports = NULL;
447         
448         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
449         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
450                                                              TRUE /* only enabled accounts. */); 
451                                                 
452         GSList *cursor = accounts;
453         while (cursor) {
454                 gchar *account_name = cursor->data;
455                 gchar *from_string  = NULL;
456                 if (account_name) {
457                         from_string = modest_account_mgr_get_from_string (account_mgr,
458                                                                           account_name);
459                 }
460                 
461                 if (from_string && account_name) {
462                         gchar *name = account_name;
463                         ModestPair *pair = modest_pair_new ((gpointer) name,
464                                                 (gpointer) from_string , TRUE);
465                         transports = g_slist_prepend (transports, pair);
466                 }
467                 
468                 cursor = cursor->next;
469         }
470         g_slist_free (accounts); /* only free the accounts, not the elements,
471                                   * because they are used in the pairlist */
472         return transports;
473 }
474
475 static void window_focus (GtkWindow *window,
476                           GtkWidget *widget,
477                           gpointer userdata)
478 {
479         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
480 }
481
482 gboolean
483 scroll_drag_timeout (gpointer userdata)
484 {
485         ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
486         ModestMsgEditWindowPrivate *priv;
487
488         /* It could happen that the window was already closed */
489         if (!GTK_WIDGET_VISIBLE (win))
490                 return FALSE;
491
492         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
493
494         correct_scroll_without_drag_check (win, TRUE);
495
496         priv->scroll_drag_timeout_id = 0;
497
498         return FALSE;
499 }
500
501 static gboolean 
502 correct_scroll_without_drag_check_idle (gpointer userdata)
503 {
504         ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
505         ModestMsgEditWindowPrivate *priv;
506         GtkTextIter iter;
507         GdkRectangle rectangle;
508         gint offset_min, offset_max;
509         GtkTextMark *insert;
510         GtkAdjustment *vadj;
511
512         /* It could happen that the window was already closed */
513         if (!GTK_WIDGET_VISIBLE (w))
514                 return FALSE;
515
516         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
517
518         insert = gtk_text_buffer_get_insert (priv->text_buffer);
519         gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
520
521         gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
522         offset_min = priv->msg_body->allocation.y + rectangle.y;
523         offset_max = offset_min + rectangle.height;
524
525         vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
526         offset_min = MAX (offset_min - 48, 0);
527         offset_max = MIN (offset_max + 48, vadj->upper);
528
529         gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
530
531         priv->correct_scroll_idle = 0;
532         return FALSE;
533 }
534
535 static void
536 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
537 {
538         ModestMsgEditWindowPrivate *priv;
539
540         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
541
542         if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
543                 return;
544
545         if (priv->correct_scroll_idle > 0) {
546                 return;
547         }
548
549         priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
550                                                      (GSourceFunc) correct_scroll_without_drag_check_idle,
551                                                      g_object_ref (w),
552                                                      g_object_unref);
553 }
554
555 static void
556 correct_scroll (ModestMsgEditWindow *w)
557 {
558         ModestMsgEditWindowPrivate *priv;
559
560         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
561         if (gtk_grab_get_current () == priv->msg_body) {
562                 if (priv->scroll_drag_timeout_id == 0) {
563                         priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
564                                                                            500,
565                                                                            (GSourceFunc) scroll_drag_timeout,
566                                                                            g_object_ref (w),
567                                                                            g_object_unref);
568                 }
569                 return;
570         }
571
572         correct_scroll_without_drag_check (w, TRUE);
573 }
574
575 static void
576 text_buffer_end_user_action (GtkTextBuffer *buffer,
577                              ModestMsgEditWindow *userdata)
578 {
579
580         correct_scroll (userdata);
581 }
582
583 static void
584 text_buffer_mark_set (GtkTextBuffer *buffer,
585                       GtkTextIter *iter,
586                       GtkTextMark *mark,
587                       ModestMsgEditWindow *userdata)
588 {
589         gtk_text_buffer_begin_user_action (buffer);
590         gtk_text_buffer_end_user_action (buffer);
591 }
592
593 static void
594 cut_clipboard_check (GtkTextView *text_view,
595                      gpointer userdata)
596 {
597         GtkTextBuffer *buffer;
598         
599         buffer = gtk_text_view_get_buffer (text_view);
600         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
601                 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
602         }
603 }
604
605 static void
606 copy_clipboard_check (GtkTextView *text_view,
607                      gpointer userdata)
608 {
609         GtkTextBuffer *buffer;
610         
611         buffer = gtk_text_view_get_buffer (text_view);
612         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
613                 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
614         }
615 }
616
617 static void
618 attachment_deleted (ModestAttachmentsView *attachments_view,
619                     gpointer user_data)
620 {
621         modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
622                                                    NULL);
623 }
624
625 static void
626 connect_signals (ModestMsgEditWindow *obj)
627 {
628         ModestMsgEditWindowPrivate *priv;
629
630         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
631
632         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
633                           G_CALLBACK (text_buffer_refresh_attributes), obj);
634         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
635                           G_CALLBACK (text_buffer_can_undo), obj);
636         g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
637                           G_CALLBACK (text_buffer_can_redo), obj);
638         g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
639                           G_CALLBACK (body_changed), obj);
640         g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
641                           G_CALLBACK (body_changed), obj);
642         g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
643                           G_CALLBACK (text_buffer_end_user_action), obj);
644         g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
645                           G_CALLBACK (text_buffer_mark_set), obj);
646         g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
647                                 G_CALLBACK (text_buffer_apply_tag), obj);
648         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
649                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
650         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
651                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
652         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
653                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
654
655         g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
656                           G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
657         g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
658                           G_CALLBACK (from_field_changed), obj);
659
660         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
661                           G_CALLBACK (msg_body_focus), obj);
662         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
663                           G_CALLBACK (msg_body_focus), obj);
664         g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
665         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
666                           "changed", G_CALLBACK (recpt_field_changed), obj);
667         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
668                           "changed", G_CALLBACK (recpt_field_changed), obj);
669         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
670                           "changed", G_CALLBACK (recpt_field_changed), obj);
671         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
672         g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
673         g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
674
675         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
676         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
677  
678         priv->clipboard_change_handler_id = 
679                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
680                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
681         priv->default_clipboard_change_handler_id = 
682                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
683                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
684
685         g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
686         g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
687         g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
688 }
689
690 static void
691 init_wp_text_view_style ()
692 {
693         static gboolean initialized = FALSE;
694
695         if (!initialized) {
696                 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
697                 initialized = TRUE;
698         }
699 }       
700
701 static void
702 init_window (ModestMsgEditWindow *obj)
703 {
704         GtkWidget *to_caption, *subject_caption;
705         GtkWidget *main_vbox;
706         GtkWidget *add_attachment_align;
707         ModestMsgEditWindowPrivate *priv;
708         GtkActionGroup *action_group;
709         ModestWindowPrivate *parent_priv;
710         GdkPixbuf *window_icon = NULL;
711         GError *error = NULL;
712
713         GtkSizeGroup *title_size_group;
714         GtkSizeGroup *value_size_group;
715         GtkWidget *attachment_icon;
716         GtkWidget *window_box;
717         GtkWidget *window_align;
718 #if (GTK_MINOR_VERSION >= 10)
719         GdkAtom deserialize_type;
720 #endif
721
722         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
723         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
724
725         parent_priv->ui_manager = gtk_ui_manager_new();
726         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
727         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
728
729         /* Add common actions */
730         gtk_action_group_add_actions (action_group,
731                                       modest_msg_edit_action_entries,
732                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
733                                       obj);
734         gtk_action_group_add_actions (action_group,
735                                       hildon2_msg_edit_action_entries,
736                                       G_N_ELEMENTS (hildon2_msg_edit_action_entries),
737                                       obj);
738         gtk_action_group_add_toggle_actions (action_group,
739                                              modest_msg_edit_toggle_action_entries,
740                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
741                                              obj);
742         gtk_action_group_add_radio_actions (action_group,
743                                             modest_msg_edit_alignment_radio_action_entries,
744                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
745                                             GTK_JUSTIFY_LEFT,
746                                             G_CALLBACK (modest_ui_actions_on_change_justify),
747                                             obj);
748         gtk_action_group_add_radio_actions (action_group,
749                                             modest_msg_edit_priority_action_entries,
750                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
751                                             0,
752                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
753                                             obj);
754         gtk_action_group_add_radio_actions (action_group,
755                                             modest_msg_edit_file_format_action_entries,
756                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
757                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
758                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
759                                             obj);
760         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
761         g_object_unref (action_group);
762
763         /* Load the UI definition */
764         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
765                                          &error);
766         if (error != NULL) {
767                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
768                 g_clear_error (&error);
769         }
770
771         /* Add accelerators */
772         gtk_window_add_accel_group (GTK_WINDOW (obj), 
773                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
774
775         parent_priv->menubar = NULL;
776
777         title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
778         value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
779
780         /* Note: This ModestPairList* must exist for as long as the picker
781          * that uses it, because the ModestSelectorPicker uses the ID opaquely, 
782          * so it can't know how to manage its memory. */ 
783         priv->from_field    = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
784                                                           HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
785                                                           NULL, g_str_equal);
786         modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group, 
787                                                _("mail_va_from"), priv->from_field);
788
789         priv->to_field      = modest_recpt_editor_new ();
790         priv->cc_field      = modest_recpt_editor_new ();
791         priv->bcc_field     = modest_recpt_editor_new ();
792         priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
793         priv->priority_icon = gtk_image_new ();
794         gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
795         priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
796         gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
797         g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
798         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
799                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
800         gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
801         priv->add_attachment_button = hildon_button_new (MODEST_EDITABLE_SIZE, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
802         gtk_widget_set_size_request (priv->add_attachment_button, ATTACHMENT_BUTTON_WIDTH, -1);
803         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
804         gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
805         attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
806         hildon_button_set_image (HILDON_BUTTON (priv->add_attachment_button), attachment_icon);
807         add_attachment_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
808         gtk_alignment_set_padding (GTK_ALIGNMENT (add_attachment_align), 0, 0, MODEST_MARGIN_DEFAULT, 0);
809         gtk_container_add (GTK_CONTAINER (add_attachment_align), priv->add_attachment_button);
810         gtk_box_pack_start (GTK_BOX (priv->subject_box), add_attachment_align, FALSE, FALSE, 0);
811         priv->attachments_view = modest_attachments_view_new (NULL);
812         modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
813                                            MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
814         
815         priv->header_box = gtk_vbox_new (FALSE, 0);
816         
817         to_caption = modest_maemo_utils_create_captioned_with_size_type 
818                 (title_size_group, value_size_group,
819                  _("mail_va_to"), FALSE, priv->to_field,
820                  HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
821         priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type 
822                 (title_size_group, value_size_group,
823                  _("mail_va_cc"), FALSE, priv->cc_field,
824                  HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
825         priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
826                 (title_size_group, value_size_group,
827                  _("mail_va_hotfix1"), FALSE, priv->bcc_field,
828                  HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
829         subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
830                                                                _("mail_va_subject"), FALSE, priv->subject_box);
831         priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
832                                                                                         _("mail_va_attachment"), 
833                                                                                         FALSE,
834                                                                                         priv->attachments_view,
835                                                                                         HILDON_SIZE_AUTO_WIDTH |
836                                                                                         HILDON_SIZE_AUTO_HEIGHT);
837         /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
838         /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
839         /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
840         g_object_unref (title_size_group);
841         g_object_unref (value_size_group);
842
843         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
844         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
845         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
846         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
847         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
848         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
849         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
850
851         init_wp_text_view_style ();
852
853         priv->msg_body = modest_wp_text_view_new ();
854         
855
856         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
857         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
858         g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
859         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
860 #if (GTK_MINOR_VERSION >= 10)
861         gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
862         deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), 
863                                                                        NULL);
864         gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer), 
865                                                          deserialize_type, TRUE);
866 #endif
867         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
868
869         priv->find_toolbar = hildon_find_toolbar_new (NULL);
870         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
871
872 /*      g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
873
874         priv->pannable = hildon_pannable_area_new ();
875         
876         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
877         window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
878         gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
879
880         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
881         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
882         gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
883
884         hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
885         gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), 
886                                              hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable)));
887         gtk_widget_show_all (GTK_WIDGET(priv->pannable));
888         
889         window_box = gtk_vbox_new (FALSE, 0);
890         gtk_container_add (GTK_CONTAINER(obj), window_box);
891
892         gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
893
894         /* Set window icon */
895         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG); 
896         if (window_icon) {
897                 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
898                 g_object_unref (window_icon);
899         }       
900 }
901         
902 static void
903 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
904 {
905         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
906
907         if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
908             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
909                                            priv->clipboard_change_handler_id))
910                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
911                                              priv->clipboard_change_handler_id);
912         if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
913             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
914                                            priv->default_clipboard_change_handler_id))
915                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
916                                              priv->default_clipboard_change_handler_id);
917
918         if (priv->account_removed_handler_id && 
919             g_signal_handler_is_connected (modest_runtime_get_account_store (), 
920                                            priv->account_removed_handler_id))
921                 g_signal_handler_disconnect(modest_runtime_get_account_store (), 
922                                            priv->account_removed_handler_id);
923 }
924
925 static void
926 modest_msg_edit_window_finalize (GObject *obj)
927 {
928         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
929         
930         /* Sanity check: shouldn't be needed, the window mgr should
931            call this function before */
932         modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
933
934         if (priv->font_dialog != NULL) {
935                 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
936         }
937
938         if (priv->clipboard_text != NULL) {
939                 g_free (priv->clipboard_text);
940                 priv->clipboard_text = NULL;
941         }
942         
943         if (priv->draft_msg != NULL) {
944                 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
945                 if (TNY_IS_HEADER (header)) {
946                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
947                         modest_window_mgr_unregister_header (mgr, header);
948                 }
949                 g_object_unref (priv->draft_msg);
950                 priv->draft_msg = NULL;
951         }
952         if (priv->outbox_msg != NULL) {
953                 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
954                 if (TNY_IS_HEADER (header)) {
955                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
956                         modest_window_mgr_unregister_header (mgr, header);
957                 }
958                 g_object_unref (priv->outbox_msg);
959                 priv->outbox_msg = NULL;
960         }
961         if (priv->correct_scroll_idle > 0) {
962                 g_source_remove (priv->correct_scroll_idle);
963                 priv->correct_scroll_idle = 0;
964         }
965         if (priv->scroll_drag_timeout_id > 0) {
966                 g_source_remove (priv->scroll_drag_timeout_id);
967                 priv->scroll_drag_timeout_id = 0;
968         }
969         if (priv->clipboard_owner_idle > 0) {
970                 g_source_remove (priv->clipboard_owner_idle);
971                 priv->clipboard_owner_idle = 0;
972         }
973         if (priv->original_account_name)
974                 g_free (priv->original_account_name);
975         g_free (priv->msg_uid);
976         g_free (priv->last_search);
977         g_object_unref (priv->faces_model);
978         g_object_unref (priv->sizes_model);
979         g_object_unref (priv->attachments);
980         g_object_unref (priv->images);
981
982         /* This had to stay alive for as long as the picker that used it: */
983         modest_pair_list_free (priv->from_field_protos);
984         
985         G_OBJECT_CLASS(parent_class)->finalize (obj);
986 }
987
988 static void
989 pixbuf_size_prepared (GdkPixbufLoader *loader,
990                       gint width,
991                       gint height,
992                       ModestMsgEditWindow *self)
993 {
994         gint new_height, new_width;
995         gboolean set_size;
996         
997         new_height = height;
998         new_width = width;
999         set_size = FALSE;
1000
1001         if (width > IMAGE_MAX_WIDTH) {
1002                 new_height = height * IMAGE_MAX_WIDTH / width;
1003                 new_width = IMAGE_MAX_WIDTH;
1004         }
1005
1006         gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1007 }
1008
1009 static GdkPixbuf *
1010 pixbuf_from_stream (TnyStream *stream,
1011                     const gchar *mime_type,
1012                     guint64 *stream_size,
1013                     ModestMsgEditWindow *self)
1014 {
1015         GdkPixbufLoader *loader;
1016         GdkPixbuf *pixbuf;
1017         guint64 size;
1018         GError *error = NULL;
1019
1020         size = 0;
1021
1022         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1023
1024         if (loader == NULL) {
1025                 if (stream_size)
1026                         *stream_size = 0;
1027                 return NULL;
1028         }
1029         g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1030
1031         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1032
1033         tny_stream_reset (TNY_STREAM (stream));
1034         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1035                 unsigned char read_buffer[128];
1036                 gint readed;
1037                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1038                 size += readed;
1039                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1040                         break;
1041                 }
1042                 /* Allow some UI responsiveness */
1043                 while (gtk_events_pending ())
1044                         gtk_main_iteration ();
1045         }
1046         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1047
1048         gdk_pixbuf_loader_close (loader, &error);
1049
1050         if (error)
1051                 g_error_free (error);
1052         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1053         if (pixbuf) 
1054                 g_object_ref (pixbuf);
1055         g_object_unref (loader);
1056
1057         if (!pixbuf)
1058                 return NULL;
1059
1060         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1061                 GdkPixbuf *new_pixbuf;
1062                 gint new_height;
1063                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1064                         gdk_pixbuf_get_width (pixbuf);
1065                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1066                 g_object_unref (pixbuf);
1067                 pixbuf = new_pixbuf;
1068         }
1069
1070         if (stream_size)
1071                 *stream_size = size;
1072
1073         return pixbuf;
1074 }
1075
1076 static void
1077 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1078 {
1079         ModestMsgEditWindowPrivate *priv;
1080         TnyIterator *iter;
1081
1082         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1083
1084         g_object_ref (self);
1085         for (iter = tny_list_create_iterator (attachments);
1086              !tny_iterator_is_done (iter);
1087              tny_iterator_next (iter)) {
1088                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1089                 const gchar *cid = tny_mime_part_get_content_id (part);
1090                 const gchar *mime_type = tny_mime_part_get_content_type (part);
1091                 if ((cid != NULL)&&(mime_type != NULL)) {
1092                         guint64 stream_size;
1093                         TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1094                         GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1095
1096
1097                         g_object_unref (stream);
1098
1099                         if (pixbuf != NULL) {
1100                                 priv->images_count ++;
1101                                 priv->images_size += stream_size;
1102                                 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1103                                 g_object_unref (pixbuf);
1104                         }
1105                 }
1106                 g_object_unref (part);
1107         }
1108         g_object_unref (iter);
1109         g_object_unref (self);
1110 }
1111
1112 static void
1113 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1114 {
1115         TnyMimePart *parent = NULL;
1116         const gchar *content_type = NULL;
1117         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1118
1119         content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1120
1121         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1122                 parent = g_object_ref (msg);
1123         } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1124                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1125                 TnyIterator *iter;
1126
1127                 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1128                 iter = tny_list_create_iterator (parts);
1129                 while (!tny_iterator_is_done (iter)) {
1130                         TnyMimePart *part;
1131                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1132                         content_type = tny_mime_part_get_content_type (part);
1133                         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1134                                 parent = part;
1135                                 break;
1136                         } else {
1137                                 g_object_unref (part);
1138                         }
1139                         tny_iterator_next (iter);
1140                 }
1141                 g_object_unref (iter);
1142                 g_object_unref (parts);
1143         }
1144
1145         if (parent != NULL) {
1146                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1147                 TnyIterator *iter;
1148
1149                 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1150                 iter = tny_list_create_iterator (parts);
1151                 while (!tny_iterator_is_done (iter)) {
1152                         TnyMimePart *part;
1153                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1154                         content_type = tny_mime_part_get_content_type (part);
1155                         if (content_type && g_str_has_prefix (content_type, "image/")) {
1156                                 tny_list_prepend (priv->images, (GObject *) part);
1157                         } 
1158                         g_object_unref (part);
1159                         tny_iterator_next (iter);
1160                 }
1161                 g_object_unref (iter);
1162                 g_object_unref (parts);
1163                 g_object_unref (parent);
1164         }
1165 }
1166
1167 static void
1168 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1169 {
1170         TnyIterator *iter;
1171         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1172
1173         for (iter = tny_list_create_iterator (attachments) ; 
1174              !tny_iterator_is_done (iter);
1175              tny_iterator_next (iter)) {
1176                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1177                 const gchar *cid = tny_mime_part_get_content_id (part);
1178                 if (cid != NULL) {
1179                         char *invalid = NULL;
1180                         gint int_cid = strtol (cid, &invalid, 10);
1181                         if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1182                                 priv->next_cid = int_cid + 1;
1183                         }
1184                 }
1185                 g_object_unref (part);
1186         }
1187         g_object_unref (iter);
1188 }
1189
1190 static void
1191 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1192 {
1193         TnyHeader *header;
1194         gchar *to, *cc, *bcc, *subject;
1195         gchar *body;
1196         ModestMsgEditWindowPrivate *priv;
1197         ModestWindowPrivate *parent_priv;
1198         GtkTextIter iter;
1199         TnyHeaderFlags priority_flags;
1200         TnyFolder *msg_folder;
1201         gboolean is_html = FALSE;
1202         gboolean field_view_set;
1203         
1204         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1205         g_return_if_fail (TNY_IS_MSG (msg));
1206
1207         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1208         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1209
1210         header = tny_msg_get_header (msg);
1211         to      = tny_header_dup_to (header);
1212         cc      = tny_header_dup_cc (header);
1213         bcc     = tny_header_dup_bcc (header);
1214         subject = tny_header_dup_subject (header);
1215         priority_flags = tny_header_get_priority (header);
1216
1217         if (to)
1218                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
1219
1220         field_view_set = TRUE;
1221         if (cc) {
1222                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
1223                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1224                 gtk_widget_show (priv->cc_caption);
1225         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1226                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1227                 gtk_widget_hide (priv->cc_caption);
1228                 field_view_set = FALSE;
1229         }
1230         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1231
1232         field_view_set = TRUE;
1233         if (bcc) {
1234                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1235                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1236                 gtk_widget_show (priv->bcc_caption);
1237         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1238                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1239                 gtk_widget_hide (priv->bcc_caption);
1240                 field_view_set = FALSE;
1241         }
1242         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1243
1244
1245         if (subject)
1246                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1247         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1248                                                    priority_flags);
1249
1250         update_window_title (self);
1251
1252         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1253         body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1254
1255         if ((body == NULL)||(body[0] == '\0')) {
1256                 g_free (body);
1257                 body = modest_text_utils_convert_to_html ("");
1258                 is_html = FALSE;
1259         }
1260         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1261         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1262                                             (gchar *) body,
1263                                             strlen (body));
1264         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1265         g_free (body);
1266
1267         /* Add attachments to the view */
1268         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1269         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1270         if (tny_list_get_length (priv->attachments) == 0) {
1271                 gtk_widget_hide (priv->attachments_caption);
1272         } else {
1273                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1274                 gtk_widget_show_all (priv->attachments_caption);
1275         }
1276         get_related_images (self, msg);
1277         update_next_cid (self, priv->attachments);
1278         update_next_cid (self, priv->images);
1279         replace_with_images (self, priv->images);
1280
1281         if (preserve_is_rich && !is_html) {
1282                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1283         /* Get the default format required from configuration */
1284         } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1285                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1286         }
1287
1288         /* Set the default focus depending on having already a To: field or not */
1289         if ((!to)||(*to == '\0')) {
1290                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1291         } else {
1292                 gtk_widget_grab_focus (priv->msg_body);
1293         }
1294
1295         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1296
1297         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1298         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1299
1300         modest_msg_edit_window_set_modified (self, FALSE);
1301
1302         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1303         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1304         text_buffer_can_undo (priv->text_buffer, FALSE, self);
1305         text_buffer_can_redo (priv->text_buffer, FALSE, self);
1306
1307         if (priv->msg_uid) {
1308                 g_free (priv->msg_uid);
1309                 priv->msg_uid = NULL;
1310         }
1311
1312         /* we should set a reference to the incoming message if it is a draft */
1313         msg_folder = tny_msg_get_folder (msg);
1314         if (msg_folder) {               
1315                 if (modest_tny_folder_is_local_folder (msg_folder)) {
1316                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1317                         if (type == TNY_FOLDER_TYPE_INVALID)
1318                                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1319                         
1320                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
1321                                 priv->draft_msg = g_object_ref(msg);
1322                         if (type == TNY_FOLDER_TYPE_OUTBOX)
1323                                 priv->outbox_msg = g_object_ref(msg);
1324                         priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1325                 }
1326                 g_object_unref (msg_folder);
1327         }
1328
1329         g_free (to);
1330         g_free (subject);
1331         g_free (cc);
1332         g_free (bcc);
1333 }
1334
1335
1336 static void
1337 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1338 {
1339         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1340         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1341         GtkWidget *placeholder;
1342         GtkWidget *tool_item;
1343         gint insert_index;
1344         gchar size_text[5];
1345         gint size_index;
1346         gint font_index;
1347         GtkWidget *sizes_menu;
1348         GtkWidget *fonts_menu;
1349         gchar *markup;
1350         GtkWidget *arrow;
1351         GtkWidget *hbox;
1352
1353         /* Toolbar */
1354         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1355         gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1356         gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1357         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1358
1359         /* Font color placeholder */
1360         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1361         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1362
1363         /* font color */
1364         priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1365         priv->font_color_button = hildon_color_button_new ();
1366         gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1367         GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1368         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1369         gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1370         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1371         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1372         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1373         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), 
1374                                   "notify::color", 
1375                                   G_CALLBACK (modest_msg_edit_window_color_button_change), 
1376                                   window);
1377
1378         /* Font size and face placeholder */
1379         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1380         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1381         /* font_size */
1382         tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1383         priv->size_tool_button_label = gtk_label_new (NULL);
1384         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1385         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1386                               size_text, "</span>", NULL);
1387         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1388         gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1389         g_free (markup);
1390         hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1391         hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1392         gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1393         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1394         gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1395         gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1396         gtk_widget_set_sensitive (arrow, FALSE);
1397         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1398         sizes_menu = gtk_menu_new ();
1399         priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1400         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1401                 GtkTreeIter iter;
1402
1403                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1404                 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1405
1406                 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter, 
1407                                     0, size_text,
1408                                     -1);
1409
1410                 if (wp_font_size[size_index] == 12)
1411                         priv->current_size_index = size_index;
1412                                         
1413         }
1414
1415         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1416         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1417         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1418         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1419         priv->font_size_toolitem = tool_item;
1420
1421         /* font face */
1422         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1423         priv->font_tool_button_label = gtk_label_new (NULL);
1424         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1425         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1426         g_free(markup);
1427         hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1428         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1429         fonts_menu = gtk_menu_new ();
1430         priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1431         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1432                 GtkTreeIter iter;
1433
1434                 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1435
1436                 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter, 
1437                                     0, wp_get_font_name (font_index),
1438                                     -1);
1439
1440                 if (font_index == DEFAULT_FONT)
1441                         priv->current_face_index = font_index;
1442         }
1443         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1444         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1445         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1446         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1447         priv->font_face_toolitem = tool_item;
1448
1449         /* Set expand and homogeneous for remaining items */
1450         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1451         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1452         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1453         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1454         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1455         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1456         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1457         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1458         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1459
1460         /* Explicitelly show all the toolbar (a normal gtk_widget_show
1461            will not show the tool items added to the placeholders) */
1462         gtk_widget_show_all (parent_priv->toolbar);
1463
1464         /* Set the no show all *after* showing all items. We do not
1465            want the toolbar to be shown with a show all because it
1466            could go agains the gconf setting regarding showing or not
1467            the toolbar of the editor window */
1468         gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1469 }
1470
1471
1472
1473 ModestWindow*
1474 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1475 {
1476         GObject *obj;
1477         ModestWindowPrivate *parent_priv;
1478         ModestMsgEditWindowPrivate *priv;
1479         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1480         ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1481         ModestWindowMgr *mgr = NULL;
1482
1483         g_return_val_if_fail (msg, NULL);
1484         g_return_val_if_fail (account_name, NULL);
1485
1486         mgr = modest_runtime_get_window_mgr ();
1487         
1488         obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1489
1490         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1491         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1492
1493         /* Menubar. Update the state of some toggles */
1494         priv->from_field_protos = get_transports ();
1495         modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1496         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1497         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1498         hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1499                                  _("mail_va_from"));
1500         hildon_button_set_value (HILDON_BUTTON (priv->from_field), 
1501                                  hildon_touch_selector_get_current_text 
1502                                  (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1503         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1504         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1505
1506         /* Init window */
1507         connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1508
1509         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1510                 
1511         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1512
1513         priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1514
1515         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1516         clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1517         /* Add common dimming rules */
1518         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1519                                               modest_msg_edit_window_toolbar_dimming_entries,
1520                                               G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1521                                               MODEST_WINDOW (obj));
1522         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1523                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1524                                                     MODEST_WINDOW (obj));
1525         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1526                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1527                                                     MODEST_WINDOW (obj));
1528         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1529                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1530                                                     MODEST_WINDOW (obj));
1531         /* Insert dimming rules group for this window */
1532         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1533         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1534
1535         /* Setup app menu */
1536         setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1537
1538         /* Checks the dimming rules */
1539         g_object_unref (toolbar_rules_group);
1540         g_object_unref (clipboard_rules_group);
1541         gtk_widget_hide (priv->priority_icon);
1542         gtk_widget_queue_resize (priv->subject_box);
1543         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1544
1545         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1546
1547         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1548         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1549         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1550         priv->update_caption_visibility = TRUE;
1551
1552         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1553
1554         /* Track account-removed signal, this window should be closed
1555            in the case we're creating a mail associated to the account
1556            that is deleted */
1557         priv->account_removed_handler_id = 
1558                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1559                                   "account_removed",
1560                                   G_CALLBACK(on_account_removed),
1561                                   obj);
1562
1563         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1564
1565         return (ModestWindow*) obj;
1566 }
1567
1568 static gint
1569 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1570 {
1571         GString **string_buffer = (GString **) user_data;
1572
1573         *string_buffer = g_string_append (*string_buffer, buffer);
1574    
1575         return 0;
1576 }
1577
1578 /**
1579  * @result: A new string which should be freed with g_free().
1580  */
1581 static gchar *
1582 get_formatted_data (ModestMsgEditWindow *edit_window)
1583 {
1584         ModestMsgEditWindowPrivate *priv;
1585         GString *string_buffer = g_string_new ("");
1586         
1587         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1588
1589         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1590
1591         modest_text_utils_hyperlinkify (string_buffer);
1592
1593         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1594
1595         return g_string_free (string_buffer, FALSE);
1596                                                                         
1597 }
1598
1599 MsgData * 
1600 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1601 {
1602         MsgData *data;
1603         const gchar *account_name;
1604         ModestMsgEditWindowPrivate *priv;
1605         TnyIterator *att_iter;
1606         
1607         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1608
1609         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1610                                                                         
1611         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1612         g_return_val_if_fail (account_name, NULL);
1613         
1614         
1615         /* don't free these (except from) */
1616         data = g_slice_new0 (MsgData);
1617         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1618                                                              account_name);
1619         data->account_name = g_strdup (account_name);
1620         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1621         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1622         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1623         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1624         if (priv->draft_msg) {
1625                 data->draft_msg = g_object_ref (priv->draft_msg);
1626         } else if (priv->outbox_msg) {
1627                 data->draft_msg = g_object_ref (priv->outbox_msg);
1628         } else {
1629                 data->draft_msg = NULL;
1630         }
1631
1632         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1633         GtkTextIter b, e;
1634         gtk_text_buffer_get_bounds (buf, &b, &e);
1635         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1636
1637         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1638                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1639         else
1640                 data->html_body = NULL;
1641
1642         /* deep-copy the data */
1643         att_iter = tny_list_create_iterator (priv->attachments);
1644         data->attachments = NULL;
1645         while (!tny_iterator_is_done (att_iter)) {
1646                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1647                 if (!(TNY_IS_MIME_PART(part))) {
1648                         g_warning ("strange data in attachment list");
1649                         g_object_unref (part);
1650                         tny_iterator_next (att_iter);
1651                         continue;
1652                 }
1653                 data->attachments = g_list_append (data->attachments,
1654                                                    part);
1655                 tny_iterator_next (att_iter);
1656         }
1657         g_object_unref (att_iter);
1658
1659         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1660         att_iter = tny_list_create_iterator (priv->images);
1661         data->images = NULL;
1662         while (!tny_iterator_is_done (att_iter)) {
1663                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1664                 const gchar *cid;
1665                 if (!(TNY_IS_MIME_PART(part))) {
1666                         g_warning ("strange data in attachment list");
1667                         g_object_unref (part);
1668                         tny_iterator_next (att_iter);
1669                         continue;
1670                 }
1671                 cid = tny_mime_part_get_content_id (part);
1672                 if (cid) {                      
1673                         gchar *image_tag_id;
1674                         GtkTextTag *image_tag;
1675                         GtkTextIter iter;
1676                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1677                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1678                         g_free (image_tag_id);
1679                         
1680                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1681                         if (image_tag && 
1682                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1683                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1684                                 data->images = g_list_append (data->images,
1685                                                               g_object_ref (part));
1686                 }
1687                 g_object_unref (part);
1688                 tny_iterator_next (att_iter);
1689         }
1690         g_object_unref (att_iter);
1691         
1692         data->priority_flags = priv->priority_flags;
1693
1694         return data;
1695 }
1696
1697
1698 static void
1699 unref_gobject (GObject *obj, gpointer data)
1700 {
1701         if (!G_IS_OBJECT(obj))
1702                 return;
1703         g_object_unref (obj);
1704 }
1705
1706 void 
1707 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1708                                                       MsgData *data)
1709 {
1710         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1711
1712         if (!data)
1713                 return;
1714
1715         g_free (data->to);
1716         g_free (data->cc);
1717         g_free (data->bcc);
1718         g_free (data->from);
1719         g_free (data->subject);
1720         g_free (data->plain_body);
1721         g_free (data->html_body);
1722         g_free (data->account_name);
1723         
1724         if (data->draft_msg != NULL) {
1725                 g_object_unref (data->draft_msg);
1726                 data->draft_msg = NULL;
1727         }
1728         
1729         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1730         g_list_free (data->attachments);
1731         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1732         g_list_free (data->images);
1733         
1734         g_slice_free (MsgData, data);
1735 }
1736
1737 void                    
1738 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1739                                        gint *parts_count,
1740                                        guint64 *parts_size)
1741 {
1742         ModestMsgEditWindowPrivate *priv;
1743
1744         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1745
1746         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1747
1748         /* TODO: add images */
1749         *parts_size += priv->images_size;
1750         *parts_count += priv->images_count;
1751
1752 }
1753
1754 ModestMsgEditFormat
1755 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1756 {
1757         gboolean rich_text;
1758         ModestMsgEditWindowPrivate *priv = NULL;
1759         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1760
1761         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1762
1763         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1764         if (rich_text)
1765                 return MODEST_MSG_EDIT_FORMAT_HTML;
1766         else
1767                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1768 }
1769
1770 void
1771 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1772                                    ModestMsgEditFormat format)
1773 {
1774         ModestMsgEditWindowPrivate *priv;
1775
1776         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1777         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1778
1779         switch (format) {
1780         case MODEST_MSG_EDIT_FORMAT_HTML:
1781                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1782                 break;
1783         case MODEST_MSG_EDIT_FORMAT_TEXT:
1784                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1785                 break;
1786         default:
1787                 g_return_if_reached ();
1788         }
1789 }
1790
1791 ModestMsgEditFormatState *
1792 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1793 {
1794         ModestMsgEditFormatState *format_state = NULL;
1795         ModestMsgEditWindowPrivate *priv;
1796         WPTextBufferFormat *buffer_format;
1797
1798         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1799
1800         buffer_format = g_new0 (WPTextBufferFormat, 1);
1801         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1802
1803         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1804
1805         format_state = g_new0 (ModestMsgEditFormatState, 1);
1806         format_state->bold = buffer_format->bold&0x1;
1807         format_state->italics = buffer_format->italic&0x1;
1808         format_state->bullet = buffer_format->bullet&0x1;
1809         format_state->color = buffer_format->color;
1810         format_state->font_size = buffer_format->font_size;
1811         format_state->font_family = wp_get_font_name (buffer_format->font);
1812         format_state->justification = buffer_format->justification;
1813         g_free (buffer_format);
1814
1815         return format_state;
1816  
1817 }
1818
1819 void
1820 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1821                                          const ModestMsgEditFormatState *format_state)
1822 {
1823         ModestMsgEditWindowPrivate *priv;
1824         WPTextBufferFormat *buffer_format;
1825         WPTextBufferFormat *current_format;
1826
1827         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1828         g_return_if_fail (format_state != NULL);
1829
1830         buffer_format = g_new0 (WPTextBufferFormat, 1);
1831         current_format = g_new0 (WPTextBufferFormat, 1);
1832
1833         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1834         gtk_widget_grab_focus (priv->msg_body);
1835         buffer_format->bold = (format_state->bold != FALSE);
1836         buffer_format->italic = (format_state->italics != FALSE);
1837         buffer_format->color = format_state->color;
1838         buffer_format->font_size = format_state->font_size;
1839         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1840         buffer_format->justification = format_state->justification;
1841         buffer_format->bullet = format_state->bullet;
1842
1843         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1844
1845         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1846         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1847         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1848         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1849         buffer_format->cs.font = (buffer_format->font != current_format->font);
1850         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1851         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1852
1853         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1854         if (buffer_format->cs.bold) {
1855                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1856                                               GINT_TO_POINTER (buffer_format->bold&0x1));
1857         }
1858         if (buffer_format->cs.italic) {
1859                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1860                                               GINT_TO_POINTER (buffer_format->italic&0x1));
1861         }
1862         if (buffer_format->cs.color) {
1863                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1864                                               GINT_TO_POINTER (&(buffer_format->color)));
1865         }
1866         if (buffer_format->cs.font_size) {
1867                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1868                                               GINT_TO_POINTER (buffer_format->font_size));
1869         }
1870         if (buffer_format->cs.justification) {
1871                 switch (buffer_format->justification) {
1872                 case GTK_JUSTIFY_LEFT:
1873                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1874                                                       GINT_TO_POINTER(TRUE));
1875                         break;
1876                 case GTK_JUSTIFY_CENTER:
1877                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1878                                                       GINT_TO_POINTER(TRUE));
1879                         break;
1880                 case GTK_JUSTIFY_RIGHT:
1881                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1882                                                       GINT_TO_POINTER(TRUE));
1883                         break;
1884                 default:
1885                         break;
1886                 }
1887                         
1888         }
1889         if (buffer_format->cs.font) {
1890                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1891                                               GINT_TO_POINTER (buffer_format->font));
1892         }
1893         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1894         if (buffer_format->cs.bullet) {
1895                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1896                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1897         }
1898 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1899         
1900         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1901         
1902         g_free (buffer_format);
1903         g_free (current_format);
1904
1905         /* Check dimming rules */
1906         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1907         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1908 }
1909
1910 static void
1911 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1912 {
1913         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1914         GtkAction *action;
1915         ModestWindowPrivate *parent_priv;
1916         ModestMsgEditWindowPrivate *priv;
1917         
1918         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1919         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1920
1921         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1922                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1923                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1924                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1925         } else {
1926                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1927                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1928                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1929         }
1930
1931         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1932
1933         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1934         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1935
1936         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1937         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1938
1939 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1940 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1941
1942         action = NULL;
1943         switch (buffer_format->justification)
1944         {
1945         case GTK_JUSTIFY_LEFT:
1946                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1947                 break;
1948         case GTK_JUSTIFY_CENTER:
1949                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1950                 break;
1951         case GTK_JUSTIFY_RIGHT:
1952                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1953                 break;
1954         default:
1955                 break;
1956         }
1957         
1958         if (action != NULL)
1959                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1960         
1961         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1962                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1963                                          window);
1964         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1965         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1966                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1967                                            window);
1968
1969         if (priv->current_size_index != buffer_format->font_size) {
1970                 GtkTreeIter iter;
1971                 GtkTreePath *path;
1972
1973                 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1974                 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1975                         gchar *size_text;
1976                         gchar *markup;
1977
1978                         priv->current_size_index = buffer_format->font_size;
1979
1980                         gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
1981                         markup = g_strconcat ("<span font_family='Sans'>", 
1982                                               size_text, "</span>", NULL);
1983                         
1984                         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1985                         g_free (markup);
1986                         g_free (size_text);
1987                 }
1988                 gtk_tree_path_free (path);              
1989         }
1990
1991         if (priv->current_face_index != buffer_format->font) {
1992                 GtkTreeIter iter;
1993                 GtkTreePath *path;
1994
1995                 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
1996                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
1997                         gchar *face_name;
1998                         gchar *markup;
1999
2000                         priv->current_face_index = buffer_format->font;
2001                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2002                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2003                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2004                         g_free (face_name);
2005                         g_free (markup);
2006                 }
2007
2008         }
2009
2010         g_free (buffer_format);
2011
2012 }
2013
2014 #ifdef MODEST_HILDON_VERSION_0
2015 void
2016 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2017 {
2018         
2019         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2020         ModestMsgEditWindowPrivate *priv;
2021         GtkWidget *dialog = NULL;
2022         gint response;
2023         GdkColor *new_color = NULL;
2024
2025         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2026         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2027         
2028         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2029         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2030         g_free (buffer_format);
2031
2032         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2033                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2034                 if (new_color != NULL) {
2035                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2036                                                       (gpointer) new_color);
2037                 }
2038         }
2039         gtk_widget_destroy (dialog);
2040 }
2041
2042
2043 void
2044 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2045 {
2046         
2047         ModestMsgEditWindowPrivate *priv;
2048         GtkWidget *dialog = NULL;
2049         gint response;
2050         GdkColor *old_color = NULL;
2051         const GdkColor *new_color = NULL;
2052         
2053         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2054         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2055         
2056         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2057         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2058
2059         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2060                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2061                 if (new_color != NULL)
2062                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2063         }
2064         gtk_widget_destroy (dialog);
2065
2066 }
2067
2068 #else 
2069 void
2070 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2071 {
2072         
2073         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2074         ModestMsgEditWindowPrivate *priv;
2075         GtkWidget *dialog = NULL;
2076
2077         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2078         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2079                 
2080         dialog = hildon_color_chooser_new ();
2081         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2082         g_free (buffer_format);
2083
2084         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2085                 GdkColor col;
2086                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2087                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2088                                               (gpointer) &col);
2089         }
2090         gtk_widget_destroy (dialog);
2091 }
2092
2093
2094 void
2095 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2096 {
2097         
2098         ModestMsgEditWindowPrivate *priv;
2099         GtkWidget *dialog = NULL;
2100         GdkColor *old_color = NULL;
2101         
2102         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2103         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2104         
2105         dialog = hildon_color_chooser_new ();
2106         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2107
2108         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2109                 GdkColor col;
2110                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2111                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2112         }
2113         gtk_widget_destroy (dialog);
2114 }
2115
2116 #endif /*!MODEST_HILDON_VERSION_0*/
2117
2118
2119
2120 static TnyStream*
2121 create_stream_for_uri (const gchar* uri)
2122 {
2123         if (!uri)
2124                 return NULL;
2125                 
2126         TnyStream *result = NULL;
2127
2128         GnomeVFSHandle *handle = NULL;
2129         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2130         if (test == GNOME_VFS_OK) {
2131                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2132                 /* Streams over OBEX (Bluetooth) are not seekable but
2133                  * we expect them to be (we might need to read them
2134                  * several times). So if this is a Bluetooth URI just
2135                  * read the whole file into memory (this is not a fast
2136                  * protocol so we can assume that these files are not
2137                  * going to be very big) */
2138                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2139                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2140                         TnyStream *memstream = tny_camel_mem_stream_new ();
2141                         tny_stream_write_to_stream (vfssstream, memstream);
2142                         g_object_unref (vfssstream);
2143                         result = memstream;
2144                 } else {
2145                         result = vfssstream;
2146                 }
2147         }
2148         
2149         return result;
2150 }
2151
2152 void
2153 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2154 {
2155         
2156         ModestMsgEditWindowPrivate *priv;
2157         GtkWidget *dialog = NULL;
2158         gint response = 0;
2159         GSList *uris = NULL;
2160         GSList *uri_node = NULL;
2161
2162         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2163
2164         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2165         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2166         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2167
2168         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2169
2170         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2171                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2172
2173         response = gtk_dialog_run (GTK_DIALOG (dialog));
2174         switch (response) {
2175         case GTK_RESPONSE_OK:
2176                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2177                 break;
2178         default:
2179                 break;
2180         }
2181         gtk_widget_destroy (dialog);
2182
2183         g_object_ref (window);
2184         /* The operation could take some time so allow the dialog to be closed */
2185         while (gtk_events_pending ())
2186                 gtk_main_iteration ();
2187
2188         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2189                 const gchar *uri;
2190                 GnomeVFSHandle *handle = NULL;
2191                 GnomeVFSResult result;
2192                 GtkTextIter position;
2193                 GtkTextMark *insert_mark;
2194
2195                 uri = (const gchar *) uri_node->data;
2196                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2197                 if (result == GNOME_VFS_OK) {
2198                         GdkPixbuf *pixbuf;
2199                         GnomeVFSFileInfo *info;
2200                         gchar *filename, *basename, *escaped_filename;
2201                         TnyMimePart *mime_part;
2202                         gchar *content_id;
2203                         const gchar *mime_type = NULL;
2204                         GnomeVFSURI *vfs_uri;
2205                         guint64 stream_size;
2206
2207                         gnome_vfs_close (handle);
2208                         vfs_uri = gnome_vfs_uri_new (uri);
2209
2210                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2211                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2212                         g_free (escaped_filename);
2213                         gnome_vfs_uri_unref (vfs_uri);
2214                         info = gnome_vfs_file_info_new ();
2215
2216                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2217                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2218                             == GNOME_VFS_OK)
2219                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2220
2221                         mime_part = tny_platform_factory_new_mime_part
2222                                 (modest_runtime_get_platform_factory ());
2223
2224                         TnyStream *stream = create_stream_for_uri (uri);
2225
2226                         if (stream == NULL) {
2227
2228                                 modest_platform_information_banner (NULL, NULL, 
2229                                                                     _FM("sfil_ib_opening_not_allowed"));
2230                                 g_free (filename);
2231                                 g_object_unref (mime_part);
2232                                 gnome_vfs_file_info_unref (info);
2233                                 continue;
2234                         }
2235
2236                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2237
2238                         content_id = g_strdup_printf ("%d", priv->next_cid);
2239                         tny_mime_part_set_content_id (mime_part, content_id);
2240                         g_free (content_id);
2241                         priv->next_cid++;
2242
2243                         basename = g_path_get_basename (filename);
2244                         tny_mime_part_set_filename (mime_part, basename);
2245                         g_free (basename);
2246
2247                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2248
2249                         if (pixbuf != NULL) {
2250                                 priv->images_size += stream_size;
2251                                 priv->images_count ++;
2252                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2253                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2254                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, 
2255                                                              tny_mime_part_get_content_id (mime_part), pixbuf);
2256                                 g_object_unref (pixbuf);
2257
2258                                 tny_list_prepend (priv->images, (GObject *) mime_part);
2259                                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2260                         } else {
2261                                 modest_platform_information_banner (NULL, NULL,
2262                                                                     _("mail_ib_file_operation_failed"));
2263                         }
2264
2265                         g_free (filename);
2266                         g_object_unref (mime_part);
2267                         gnome_vfs_file_info_unref (info);
2268
2269                 }
2270         }
2271         g_object_unref (window);
2272 }
2273
2274 static void
2275 on_attach_file_response (GtkDialog *dialog,
2276                          gint       arg1,
2277                          gpointer   user_data)
2278 {
2279         GSList *uris = NULL;
2280         GSList *uri_node;
2281         GnomeVFSFileSize total_size, allowed_size;
2282         ModestMsgEditWindow *window;
2283         ModestMsgEditWindowPrivate *priv;
2284         gint att_num;
2285         guint64 att_size;
2286
2287         switch (arg1) {
2288         case GTK_RESPONSE_OK:
2289                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2290                 break;
2291         default:
2292                 break;
2293         }
2294
2295         window = MODEST_MSG_EDIT_WINDOW (user_data);
2296         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2297
2298         /* allowed size is the maximum size - what's already there */
2299         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2300                                            &att_num, &att_size);
2301         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2302
2303         total_size = 0;
2304         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2305
2306                 const gchar *uri = (const gchar *) uri_node->data;
2307
2308                 total_size += 
2309                         modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2310
2311                 if (total_size > allowed_size) {
2312                         g_warning ("%s: total size: %u", 
2313                                    __FUNCTION__, (unsigned int)total_size);
2314                         break;
2315                 }
2316                 allowed_size -= total_size;
2317         }
2318         g_slist_foreach (uris, (GFunc) g_free, NULL);
2319         g_slist_free (uris);
2320
2321         gtk_widget_destroy (GTK_WIDGET (dialog));
2322 }
2323
2324 void
2325 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2326 {
2327         GtkWidget *dialog = NULL;
2328         ModestMsgEditWindowPrivate *priv;
2329
2330         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2331
2332         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2333
2334         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2335                 return;
2336
2337         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), 
2338                                                  GTK_FILE_CHOOSER_ACTION_OPEN);
2339         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2340         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2341         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2342                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2343
2344         /* Connect to response & show */
2345         g_signal_connect (dialog, "response", 
2346                           G_CALLBACK (on_attach_file_response), window);
2347         gtk_widget_show (dialog);
2348 }
2349
2350
2351 GnomeVFSFileSize
2352 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2353                                         const gchar *uri, 
2354                                         GnomeVFSFileSize allowed_size)
2355
2356 {
2357         GnomeVFSHandle *handle = NULL;
2358         ModestMsgEditWindowPrivate *priv;
2359         GnomeVFSResult result;
2360         GnomeVFSFileSize size = 0;
2361         g_return_val_if_fail (window, 0);
2362         g_return_val_if_fail (uri, 0);
2363
2364         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2365
2366         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2367         if (result == GNOME_VFS_OK) {
2368                 TnyMimePart *mime_part;
2369                 TnyStream *stream;
2370                 const gchar *mime_type = NULL;
2371                 gchar *basename;
2372                 gchar *escaped_filename;
2373                 gchar *filename;
2374                 gchar *content_id;
2375                 GnomeVFSFileInfo *info;
2376                 GnomeVFSURI *vfs_uri;
2377
2378                 gnome_vfs_close (handle);
2379                 vfs_uri = gnome_vfs_uri_new (uri);
2380                 
2381
2382                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2383                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2384                 g_free (escaped_filename);
2385                 gnome_vfs_uri_unref (vfs_uri);
2386
2387                 info = gnome_vfs_file_info_new ();
2388                 
2389                 if (gnome_vfs_get_file_info (uri, 
2390                                              info, 
2391                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2392                     == GNOME_VFS_OK)
2393                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2394                 mime_part = tny_platform_factory_new_mime_part
2395                         (modest_runtime_get_platform_factory ());
2396                 
2397                 /* try to get the attachment's size; this may fail for weird
2398                  * file systems, like obex, upnp... */
2399                 if (allowed_size != 0 &&
2400                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2401                         size = info->size;
2402                         if (size > allowed_size) {
2403                                 modest_platform_information_banner (NULL, NULL, 
2404                                                                     _FM("sfil_ib_opening_not_allowed"));
2405                                 g_free (filename);
2406                                 return 0;
2407                         }
2408                 } else
2409                         g_warning ("%s: could not get attachment size", __FUNCTION__);
2410                 
2411                 stream = create_stream_for_uri (uri);
2412                 
2413                 if (stream == NULL) {
2414
2415                         modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2416
2417                         g_object_unref (mime_part);
2418                         g_free (filename);
2419                         gnome_vfs_file_info_unref (info);
2420                         return 0;
2421                 }
2422
2423                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2424                 g_object_unref (stream);
2425                 
2426                 content_id = g_strdup_printf ("%d", priv->next_cid);
2427                 tny_mime_part_set_content_id (mime_part, content_id);
2428                 g_free (content_id);
2429                 priv->next_cid++;
2430                 
2431                 basename = g_path_get_basename (filename);
2432                 tny_mime_part_set_filename (mime_part, basename);
2433                 g_free (basename);
2434                 
2435                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2436                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2437                                                         mime_part,
2438                                                         info->size == 0, info->size);
2439                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2440                 gtk_widget_show_all (priv->attachments_caption);
2441                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2442                 g_free (filename);
2443                 g_object_unref (mime_part);
2444                 gnome_vfs_file_info_unref (info);
2445         }
2446
2447         return size;
2448 }
2449
2450 void
2451 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2452                                            TnyList *att_list)
2453 {
2454         ModestMsgEditWindowPrivate *priv;
2455         TnyIterator *iter;
2456
2457         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2458         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2459
2460         if (att_list == NULL) {
2461                 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2462                 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2463                         g_object_unref (att_list);
2464                         return;
2465                 }
2466                 
2467         } else {
2468                 g_object_ref (att_list);
2469         }
2470
2471         if (tny_list_get_length (att_list) == 0) {
2472                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2473         } else {
2474                 gboolean dialog_response;
2475                 gchar *message = NULL;
2476                 gchar *filename = NULL;
2477
2478                 if (tny_list_get_length (att_list) == 1) {
2479                         TnyMimePart *part;
2480                         iter = tny_list_create_iterator (att_list);
2481                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2482                         g_object_unref (iter);
2483                         if (TNY_IS_MSG (part)) {
2484                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2485                                 if (header) {
2486                                         filename = tny_header_dup_subject (header);
2487                                         g_object_unref (header);
2488                                 }
2489                                 if (filename == NULL) {
2490                                         filename = g_strdup (_("mail_va_no_subject"));
2491                                 }
2492                         } else {
2493                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2494                         }
2495                         g_object_unref (part);
2496                 } else {
2497                         filename = g_strdup ("");
2498                 }
2499                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", 
2500                                                     "emev_nc_delete_attachments",
2501                                                     tny_list_get_length (att_list)), filename);
2502                 g_free (filename);
2503
2504                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), 
2505                                                                            message);
2506                 g_free (message);
2507
2508                 if (dialog_response != GTK_RESPONSE_OK) {
2509                         g_object_unref (att_list);
2510                         return;
2511                 }
2512
2513                 for (iter = tny_list_create_iterator (att_list);
2514                      !tny_iterator_is_done (iter);
2515                      tny_iterator_next (iter)) {
2516                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2517                         const gchar *att_id;
2518                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2519
2520                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2521                                                                    mime_part);
2522                         if (tny_list_get_length (priv->attachments) == 0)
2523                                 gtk_widget_hide (priv->attachments_caption);
2524                         att_id = tny_mime_part_get_content_id (mime_part);
2525                         if (att_id != NULL)
2526                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2527                                                                  att_id);
2528                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2529                         g_object_unref (mime_part);
2530                 }
2531                 g_object_unref (iter);
2532         }
2533
2534         g_object_unref (att_list);
2535
2536         /* if the last attachment has been removed, focus the Subject: field */
2537         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2538                 gtk_widget_grab_focus (priv->subject_field);
2539 }
2540
2541 static void
2542 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2543                                             gpointer userdata)
2544 {
2545         ModestMsgEditWindowPrivate *priv;
2546         GdkColor *new_color;
2547         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2548         
2549 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2550         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2551 #else 
2552         GdkColor col;
2553         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2554         new_color = &col;
2555 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2556
2557         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2558         
2559         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2560
2561 }
2562
2563 static void
2564 font_size_clicked (GtkToolButton *button,
2565                    ModestMsgEditWindow *window)
2566 {
2567         ModestMsgEditWindowPrivate *priv;
2568         GtkWidget *selector, *dialog;
2569         
2570         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2571
2572         selector = hildon_touch_selector_new ();
2573         hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2574         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2575
2576         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2577         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2578         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2579
2580         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2581                 gint new_index;
2582                 gchar *size_text;
2583                 gchar *markup;
2584                 WPTextBufferFormat format;
2585
2586                 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2587
2588                 memset (&format, 0, sizeof (format));
2589                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2590
2591                 format.cs.font_size = TRUE;
2592                 format.cs.text_position = TRUE;
2593                 format.cs.font = TRUE;
2594                 format.font_size = new_index;
2595 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2596
2597                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2598                                                    GINT_TO_POINTER (new_index)))
2599                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2600                 
2601                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2602                 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2603                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", 
2604                                       size_text, "</span>", NULL);
2605                 g_free (size_text);
2606                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2607                 g_free (markup);
2608
2609         }
2610         gtk_widget_destroy (dialog);
2611
2612         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2613
2614 }
2615
2616 static void
2617 font_face_clicked (GtkToolButton *button,
2618                    ModestMsgEditWindow *window)
2619 {
2620         ModestMsgEditWindowPrivate *priv;
2621         GtkWidget *selector, *dialog;
2622         GtkCellRenderer *renderer;
2623         
2624         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2625
2626         selector = hildon_touch_selector_new ();
2627         renderer = gtk_cell_renderer_text_new ();
2628         hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model, 
2629                                              renderer, "family", 0, "text", 0, NULL);
2630         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2631
2632         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2633         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2634         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2635
2636         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2637                 gint new_font_index;
2638                 GtkTreePath *path;
2639                 GtkTreeIter iter;
2640
2641                 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2642                 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2643                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2644                         gchar *face_name;
2645                         gchar *markup;
2646
2647                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2648
2649                         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2650                                                            GINT_TO_POINTER(new_font_index)))
2651                                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2652
2653                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2654                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2655
2656                         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2657                         g_free (face_name);
2658                         g_free (markup);
2659                 }
2660                 gtk_tree_path_free (path);
2661
2662         }
2663         gtk_widget_destroy (dialog);
2664
2665         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2666
2667 }
2668
2669 void
2670 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2671                                 gboolean show)
2672 {
2673         ModestMsgEditWindowPrivate *priv = NULL;
2674         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2675
2676         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2677         if (!priv->update_caption_visibility)
2678                 return;
2679
2680         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2681         if (show)
2682                 gtk_widget_show (priv->cc_caption);
2683         else
2684                 gtk_widget_hide (priv->cc_caption);
2685
2686         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2687 }
2688
2689 void
2690 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2691                                  gboolean show)
2692 {
2693         ModestMsgEditWindowPrivate *priv = NULL;
2694         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2695
2696         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2697         if (!priv->update_caption_visibility)
2698                 return;
2699
2700         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2701         if (show)
2702                 gtk_widget_show (priv->bcc_caption);
2703         else
2704                 gtk_widget_hide (priv->bcc_caption);
2705
2706         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2707 }
2708
2709 static void
2710 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2711                                          ModestRecptEditor *editor)
2712 {
2713         ModestMsgEditWindowPrivate *priv;
2714
2715         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2716         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2717         
2718         /* we check for low-mem; in that case, show a warning, and don't allow
2719          * for the addressbook
2720          */
2721         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2722                 return;
2723
2724         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2725
2726         if (editor == NULL) {
2727                 GtkWidget *view_focus;
2728                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2729
2730                 /* This code should be kept in sync with ModestRecptEditor. The
2731                    textview inside the recpt editor is the one that really gets the
2732                    focus. As it's inside a scrolled window, and this one inside the
2733                    hbox recpt editor inherits from, we'll need to go up in the 
2734                    hierarchy to know if the text view is part of the recpt editor
2735                    or if it's a different text entry */
2736
2737                 if (gtk_widget_get_parent (view_focus)) {
2738                         GtkWidget *first_parent;
2739
2740                         first_parent = gtk_widget_get_parent (view_focus);
2741                         if (gtk_widget_get_parent (first_parent) && 
2742                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2743                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2744                         }
2745                 }
2746
2747                 if (editor == NULL)
2748                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2749
2750         }
2751
2752         modest_address_book_select_addresses (editor);
2753
2754 }
2755
2756 void
2757 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2758 {
2759         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2760
2761         modest_msg_edit_window_open_addressbook (window, NULL);
2762 }
2763
2764 static void
2765 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2766                                      gboolean show_toolbar)
2767 {
2768         ModestWindowPrivate *parent_priv;
2769
2770         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2771         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2772
2773         /* We can not just use the code of
2774            modest_msg_edit_window_setup_toolbar because it has a
2775            mixture of both initialization and creation code. */
2776         if (show_toolbar)
2777                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2778         else
2779                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2780 }
2781
2782 void
2783 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2784                                            TnyHeaderFlags priority_flags)
2785 {
2786         ModestMsgEditWindowPrivate *priv;
2787         ModestWindowPrivate *parent_priv;
2788
2789         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2790
2791         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2792         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2793
2794         if (priv->priority_flags != priority_flags) {
2795                 GtkAction *priority_action = NULL;
2796
2797                 priv->priority_flags = priority_flags;
2798
2799                 switch (priority_flags) {
2800                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2801                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2802                                                       MODEST_HEADER_ICON_HIGH, 
2803                                                       HILDON_ICON_SIZE_SMALL);
2804                         gtk_widget_show (priv->priority_icon);
2805                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2806                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2807                         break;
2808                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2809                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2810                                                       MODEST_HEADER_ICON_LOW,
2811                                                       HILDON_ICON_SIZE_SMALL);
2812                         gtk_widget_show (priv->priority_icon);
2813                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2814                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2815                         break;
2816                 default:
2817                         gtk_widget_hide (priv->priority_icon);
2818                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2819                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2820                         break;
2821                 }
2822                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2823                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2824         }
2825         gtk_widget_queue_resize (priv->subject_box);
2826 }
2827
2828 void
2829 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2830                                         gint file_format)
2831 {
2832         ModestMsgEditWindowPrivate *priv;
2833         ModestWindowPrivate *parent_priv;
2834         gint current_format;
2835
2836         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2837
2838         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2839         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2840
2841         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2842                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2843
2844         if (current_format != file_format) {
2845                 switch (file_format) {
2846                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2847                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2848                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2849                         break;
2850                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2851                 {
2852                         GtkWidget *dialog;
2853                         gint response;
2854                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2855                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2856                         gtk_widget_destroy (dialog);
2857                         if (response == GTK_RESPONSE_OK) {
2858                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2859                         } else {
2860                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2861                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2862                         }
2863                 }
2864                         break;
2865                 }
2866                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2867                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2868                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2869         }
2870 }
2871
2872 void
2873 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2874 {
2875         GtkWidget *dialog;
2876         ModestMsgEditWindowPrivate *priv;
2877         WPTextBufferFormat oldfmt, fmt;
2878         gint old_position = 0;
2879         gint response = 0;
2880         gint position = 0;
2881         gint font_size;
2882         GdkColor *color = NULL;
2883         gboolean bold, bold_set, italic, italic_set;
2884         gboolean underline, underline_set;
2885         gboolean strikethrough, strikethrough_set;
2886         gboolean position_set;
2887         gboolean font_size_set, font_set, color_set;
2888         gchar *font_name;
2889
2890         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2891         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2892         
2893         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2894         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2895                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
2896
2897         /* First we get the currently selected font information */
2898         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2899
2900         switch (oldfmt.text_position) {
2901         case TEXT_POSITION_NORMAL:
2902                 old_position = 0;
2903                 break;
2904         case TEXT_POSITION_SUPERSCRIPT:
2905                 old_position = 1;
2906                 break;
2907         default:
2908                 old_position = -1;
2909                 break;
2910         }
2911
2912         g_object_set (G_OBJECT (dialog),
2913                       "bold", oldfmt.bold != FALSE,
2914                       "bold-set", !oldfmt.cs.bold,
2915                       "underline", oldfmt.underline != FALSE,
2916                       "underline-set", !oldfmt.cs.underline,
2917                       "italic", oldfmt.italic != FALSE,
2918                       "italic-set", !oldfmt.cs.italic,
2919                       "strikethrough", oldfmt.strikethrough != FALSE,
2920                       "strikethrough-set", !oldfmt.cs.strikethrough,
2921                       "color", &oldfmt.color,
2922                       "color-set", !oldfmt.cs.color,
2923                       "size", wp_font_size[oldfmt.font_size],
2924                       "size-set", !oldfmt.cs.font_size,
2925                       "position", old_position,
2926                       "position-set", !oldfmt.cs.text_position,
2927                       "family", wp_get_font_name (oldfmt.font),
2928                       "family-set", !oldfmt.cs.font,
2929                       NULL);
2930
2931         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2932                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2933         gtk_widget_show_all (dialog);
2934         priv->font_dialog = dialog;
2935         response = gtk_dialog_run (GTK_DIALOG (dialog));
2936         priv->font_dialog = NULL;
2937         if (response == GTK_RESPONSE_OK) {
2938
2939                 g_object_get( dialog,
2940                               "bold", &bold,
2941                               "bold-set", &bold_set,
2942                               "underline", &underline,
2943                               "underline-set", &underline_set,
2944                               "italic", &italic,
2945                               "italic-set", &italic_set,
2946                               "strikethrough", &strikethrough,
2947                               "strikethrough-set", &strikethrough_set,
2948                               "color", &color,
2949                               "color-set", &color_set,
2950                               "size", &font_size,
2951                               "size-set", &font_size_set,
2952                               "family", &font_name,
2953                               "family-set", &font_set,
2954                               "position", &position,
2955                               "position-set", &position_set,
2956                               NULL );
2957                 
2958         }       
2959
2960         if (response == GTK_RESPONSE_OK) {
2961                 memset(&fmt, 0, sizeof(fmt));
2962                 if (bold_set) {
2963                         fmt.bold = bold;
2964                         fmt.cs.bold = TRUE;
2965                 }
2966                 if (italic_set) {
2967                         fmt.italic = italic;
2968                         fmt.cs.italic = TRUE;
2969                 }
2970                 if (underline_set) {
2971                         fmt.underline = underline;
2972                         fmt.cs.underline = TRUE;
2973                 }
2974                 if (strikethrough_set) {
2975                         fmt.strikethrough = strikethrough;
2976                         fmt.cs.strikethrough = TRUE;
2977                 }
2978                 if (position_set) {
2979                         fmt.text_position =
2980                                 ( position == 0 )
2981                                 ? TEXT_POSITION_NORMAL
2982                                 : ( ( position == 1 )
2983                                     ? TEXT_POSITION_SUPERSCRIPT
2984                                     : TEXT_POSITION_SUBSCRIPT );
2985                         fmt.cs.text_position = TRUE;
2986                         fmt.font_size = oldfmt.font_size;
2987                 }
2988                 if (color_set) {
2989                         fmt.color = *color;
2990                         fmt.cs.color = TRUE;
2991                 }
2992                 if (font_set) {
2993                         fmt.font = wp_get_font_index(font_name,
2994                                                      DEFAULT_FONT);
2995                         fmt.cs.font = TRUE;
2996                 }
2997                 g_free(font_name);
2998                 if (font_size_set) {
2999                         fmt.cs.font_size = TRUE;
3000                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3001                 }
3002                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3003                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3004         }
3005         gtk_widget_destroy (dialog);
3006         
3007         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3008 }
3009
3010 void
3011 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3012 {
3013         ModestMsgEditWindowPrivate *priv;
3014
3015         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3016         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3017         
3018         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3019
3020         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3021         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3022 }
3023
3024 void
3025 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3026 {
3027         ModestMsgEditWindowPrivate *priv;
3028
3029         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3030         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3031         
3032         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3033
3034         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3035         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3036
3037 }
3038
3039 static void  
3040 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3041 {
3042         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3043
3044         priv->can_undo = can_undo;
3045 }
3046
3047 static void  
3048 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3049 {
3050         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3051
3052         priv->can_redo = can_redo;
3053 }
3054
3055 gboolean            
3056 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3057 {
3058         ModestMsgEditWindowPrivate *priv;
3059         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3060         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3061
3062         return priv->can_undo;
3063 }
3064
3065 gboolean            
3066 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3067 {
3068         ModestMsgEditWindowPrivate *priv;
3069         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3070         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3071
3072         return priv->can_redo;
3073 }
3074
3075
3076 static void
3077 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3078 {
3079         GtkTextIter iter;
3080         GtkTextIter match_start, match_end;
3081
3082         if (image_id == NULL)
3083                 return;
3084
3085         gtk_text_buffer_get_start_iter (buffer, &iter);
3086
3087         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3088                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3089                 GSList *node;
3090                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3091                         GtkTextTag *tag = (GtkTextTag *) node->data;
3092                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3093                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3094                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3095                                         gint offset;
3096                                         offset = gtk_text_iter_get_offset (&match_start);
3097                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3098                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3099                                 }
3100                         }
3101                 }
3102                 gtk_text_iter_forward_char (&iter);
3103         }
3104 }
3105
3106 gboolean
3107 message_is_empty (ModestMsgEditWindow *window)
3108 {
3109         ModestMsgEditWindowPrivate *priv = NULL;
3110
3111         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3112         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3113
3114         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3115          * so we can ignore markup.
3116          */
3117         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3118         gint count = 0;
3119         if (buf)
3120                 count = gtk_text_buffer_get_char_count (buf);
3121
3122         return count == 0;
3123 }
3124
3125 static gboolean
3126 msg_body_focus (GtkWidget *focus,
3127                 GdkEventFocus *event,
3128                 gpointer userdata)
3129 {
3130         
3131         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3132         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3133         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3134         return FALSE;
3135 }
3136
3137 static void
3138 recpt_field_changed (GtkTextBuffer *buffer,
3139                   ModestMsgEditWindow *editor)
3140 {
3141         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3142         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3143 }
3144
3145 static void
3146 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3147 {
3148         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3149         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3150 }
3151
3152 void
3153 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3154                                      gboolean modified)
3155 {
3156         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3157         GtkTextBuffer *buffer;
3158
3159         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3160         gtk_text_buffer_set_modified (buffer, modified);
3161         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3162         gtk_text_buffer_set_modified (buffer, modified);
3163         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3164         gtk_text_buffer_set_modified (buffer, modified);
3165         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3166 }
3167
3168 gboolean
3169 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3170 {
3171         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3172         const char *account_name;
3173         GtkTextBuffer *buffer;
3174
3175         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3176         if (gtk_text_buffer_get_modified (buffer))
3177                 return TRUE;
3178         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3179         if (gtk_text_buffer_get_modified (buffer))
3180                 return TRUE;
3181         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3182         if (gtk_text_buffer_get_modified (buffer))
3183                 return TRUE;
3184         if (gtk_text_buffer_get_modified (priv->text_buffer))
3185                 return TRUE;
3186         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3187         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3188                 return TRUE;
3189         }
3190
3191         return FALSE;
3192 }
3193
3194
3195
3196
3197 gboolean
3198 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3199 {
3200         ModestMsgEditWindowPrivate *priv = NULL;
3201         
3202         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3203         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3204
3205         /* check if there's no recipient added */
3206         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3207             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3208             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3209                 /* no recipient contents, then select contacts */
3210                 modest_msg_edit_window_open_addressbook (window, NULL);
3211                 return FALSE;
3212         }
3213
3214         g_object_ref (window);
3215         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3216                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3217                 g_object_unref (window);
3218                 return FALSE;
3219         }
3220         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3221                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3222                 g_object_unref (window);
3223                 return FALSE;
3224         }
3225         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3226                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3227                 g_object_unref (window);
3228                 return FALSE;
3229         }
3230
3231         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3232             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3233                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3234         g_object_unref (window);
3235
3236         return TRUE;
3237
3238 }
3239
3240 static void
3241 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3242                                                ModestMsgEditWindow *window)
3243 {
3244         modest_msg_edit_window_offer_attach_file (window);
3245 }
3246
3247 const gchar *
3248 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3249 {
3250         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3251
3252         return priv->clipboard_text;
3253 }
3254
3255 static void
3256 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3257                                                GdkEvent *event,
3258                                                ModestMsgEditWindow *window)
3259 {
3260         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3261         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3262         gchar *text = NULL;
3263
3264         /* It could happen that the window was already closed */
3265         if (!GTK_WIDGET_VISIBLE (window))
3266                 return;
3267
3268         g_object_ref (window);
3269         text = gtk_clipboard_wait_for_text (selection_clipboard);
3270
3271         if (priv->clipboard_text != NULL) {
3272                 g_free (priv->clipboard_text);
3273         }
3274         priv->clipboard_text = text;
3275
3276         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3277
3278         g_object_unref (window);
3279 }
3280
3281 static gboolean clipboard_owner_change_idle (gpointer userdata)
3282 {
3283         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3284         ModestMsgEditWindowPrivate *priv;
3285
3286         gdk_threads_enter ();
3287         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3288         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3289
3290         priv->clipboard_owner_idle = 0;
3291         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3292         gdk_threads_leave ();
3293
3294         return FALSE;
3295 }
3296
3297 static void
3298 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3299 {
3300         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3301         if (priv->clipboard_owner_idle == 0) {
3302                 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3303                                                               clipboard_owner_change_idle, 
3304                                                               g_object_ref (window),
3305                                                               g_object_unref);
3306         }
3307 }
3308
3309 static void 
3310 subject_field_move_cursor (GtkEntry *entry,
3311                            GtkMovementStep step,
3312                            gint a1,
3313                            gboolean a2,
3314                            gpointer window)
3315 {
3316         /* It could happen that the window was already closed */
3317         if (!GTK_WIDGET_VISIBLE (window))
3318                 return;
3319
3320         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3321 }
3322
3323 static void 
3324 update_window_title (ModestMsgEditWindow *window)
3325 {
3326         ModestMsgEditWindowPrivate *priv = NULL;
3327         const gchar *subject;
3328
3329         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3330         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3331         if (subject == NULL || subject[0] == '\0')
3332                 subject = _("mail_va_new_email");
3333
3334         gtk_window_set_title (GTK_WINDOW (window), subject);
3335
3336 }
3337
3338 static void  
3339 subject_field_changed (GtkEditable *editable, 
3340                        ModestMsgEditWindow *window)
3341 {
3342         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3343         update_window_title (window);
3344         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3345         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3346         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3347 }
3348
3349 static void  
3350 subject_field_insert_text (GtkEditable *editable, 
3351                            gchar *new_text,
3352                            gint new_text_length,
3353                            gint *position,
3354                            ModestMsgEditWindow *window)
3355 {
3356         GString *result = g_string_new ("");
3357         gchar *current;
3358         gint result_len = 0;
3359         const gchar *entry_text = NULL;
3360         gint old_length;
3361
3362         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3363         old_length = g_utf8_strlen (entry_text, -1);
3364
3365         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3366                 gunichar c = g_utf8_get_char_validated (current, 8);
3367                 /* Invalid unichar, stop */
3368                 if (c == -1)
3369                         break;
3370                 /* a bullet */
3371                 if (c == 0x2022)
3372                         continue;
3373                 result = g_string_append_unichar (result, c);
3374                 result_len++;
3375         }
3376
3377         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3378                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3379                 if (result_len > 0)
3380                 {
3381                         /* Prevent endless recursion */
3382                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3383                         g_signal_emit_by_name (editable, "insert-text", 
3384                                                (gpointer) result->str, (gpointer) result->len,
3385                                                (gpointer) position, (gpointer) window);
3386                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3387                 }
3388         }
3389
3390         if (result_len + old_length > 1000) {
3391                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3392                                                 _CS("ckdg_ib_maximum_characters_reached"));
3393         }
3394         g_string_free (result, TRUE);
3395 }
3396
3397 void
3398 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3399                                             gboolean show)
3400 {
3401         ModestMsgEditWindowPrivate *priv = NULL;
3402
3403         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3404         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3405
3406         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3407
3408         if (show) {
3409                 gtk_widget_show_all (priv->find_toolbar);
3410                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3411         } else {
3412                 gtk_widget_hide_all (priv->find_toolbar);
3413                 gtk_widget_grab_focus (priv->msg_body);
3414         }
3415 }
3416
3417 static gboolean 
3418 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3419                                           const gchar *str,
3420                                           GtkTextIter *match_start,
3421                                           GtkTextIter *match_end)
3422 {
3423         GtkTextIter end_iter;
3424         gchar *str_casefold;
3425         gint str_chars_n;
3426         gchar *range_text;
3427         gchar *range_casefold;
3428         gint offset;
3429         gint range_chars_n;
3430         gboolean result = FALSE;
3431
3432         if (str == NULL)
3433                 return TRUE;
3434         
3435         /* get end iter */
3436         end_iter = *iter;
3437         gtk_text_iter_forward_to_end (&end_iter);
3438
3439         str_casefold = g_utf8_casefold (str, -1);
3440         str_chars_n = strlen (str);
3441
3442         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3443         range_casefold = g_utf8_casefold (range_text, -1);
3444         range_chars_n = strlen (range_casefold);
3445
3446         if (range_chars_n < str_chars_n) {
3447                 g_free (str_casefold);
3448                 g_free (range_text);
3449                 g_free (range_casefold);
3450                 return FALSE;
3451         }
3452
3453         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3454                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3455                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3456                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3457                         result = TRUE;
3458                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3459                                                       match_start, match_end, NULL);
3460                         g_free (found_text);
3461                 }
3462                 g_free (range_subtext);
3463                 if (result)
3464                         break;
3465         }
3466         g_free (str_casefold);
3467         g_free (range_text);
3468         g_free (range_casefold);
3469
3470         return result;
3471 }
3472
3473
3474 static void 
3475 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3476                                             ModestMsgEditWindow *window)
3477 {
3478         gchar *current_search = NULL;
3479         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3480         gboolean result;
3481         GtkTextIter selection_start, selection_end;
3482         GtkTextIter match_start, match_end;
3483         gboolean continue_search = FALSE;
3484
3485         if (message_is_empty (window)) {
3486                 g_free (priv->last_search);
3487                 priv->last_search = NULL;
3488                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3489                 return;
3490         }
3491
3492         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3493         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3494                 g_free (current_search);
3495                 g_free (priv->last_search);
3496                 priv->last_search = NULL;
3497                 /* Information banner about empty search */
3498                 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3499                 return;
3500         }
3501
3502         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3503                 continue_search = TRUE;
3504         } else {
3505                 g_free (priv->last_search);
3506                 priv->last_search = g_strdup (current_search);
3507         }
3508
3509         if (continue_search) {
3510                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3511                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3512                                                                    &match_start, &match_end);
3513                 if (!result)
3514                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3515         } else {
3516                 GtkTextIter buffer_start;
3517                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3518                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3519                                                                    &match_start, &match_end);
3520                 if (!result)
3521                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3522         }
3523
3524         /* Mark as selected the string found in search */
3525         if (result) {
3526                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3527                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3528                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3529         } else {
3530                 g_free (priv->last_search);
3531                 priv->last_search = NULL;
3532         }
3533         g_free (current_search);
3534 }
3535
3536 gboolean 
3537 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3538 {
3539         ModestMsgEditWindowPrivate *priv;
3540
3541         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3542         return priv->sent;
3543 }
3544
3545 void 
3546 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3547                                  gboolean sent)
3548 {
3549         ModestMsgEditWindowPrivate *priv;
3550
3551         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3552         priv->sent = sent;
3553 }
3554
3555 static void
3556 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3557                                           ModestMsgEditWindow *window)
3558 {
3559         modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3560 }
3561
3562 void
3563 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3564                                   TnyMsg *draft)
3565 {
3566         ModestMsgEditWindowPrivate *priv;
3567         TnyHeader *header = NULL;
3568
3569         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3570         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3571
3572         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3573         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3574
3575         if (priv->draft_msg != NULL) {
3576                 g_object_unref (priv->draft_msg);
3577         }
3578
3579         if (draft != NULL) {
3580                 g_object_ref (draft);
3581                 header = tny_msg_get_header (draft);
3582                 if (priv->msg_uid) {
3583                         g_free (priv->msg_uid);
3584                         priv->msg_uid = NULL;
3585                 }
3586                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3587                 if (GTK_WIDGET_REALIZED (window)) {
3588                         if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3589                                 gtk_widget_destroy (GTK_WIDGET (window));
3590                                 return;
3591                         }
3592                 }
3593         }
3594
3595         priv->draft_msg = draft;
3596 }
3597
3598 static void  
3599 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3600                        GtkTextIter *start, GtkTextIter *end,
3601                        gpointer userdata)
3602 {
3603         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3604         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3605         gchar *tag_name;
3606
3607         if (tag == NULL) return;
3608         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3609         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3610                 replace_with_images (window, priv->images);
3611         }
3612 }
3613
3614 void                    
3615 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3616                                  TnyMimePart *part)
3617 {
3618         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3619
3620         g_return_if_fail (TNY_IS_MIME_PART (part));
3621         tny_list_prepend (priv->attachments, (GObject *) part);
3622         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3623         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3624         gtk_widget_show_all (priv->attachments_caption);
3625         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3626 }
3627
3628 const gchar*    
3629 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3630 {
3631         ModestMsgEditWindowPrivate *priv;
3632
3633         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3634         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3635
3636         return priv->msg_uid;
3637 }
3638
3639 GtkWidget *
3640 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3641                                          ModestMsgEditWindowWidgetType widget_type)
3642 {
3643         ModestMsgEditWindowPrivate *priv;
3644
3645         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3646         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3647
3648         switch (widget_type) {
3649         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3650                 return priv->msg_body;
3651                 break;
3652         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3653                 return priv->to_field;
3654                 break;
3655         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3656                 return priv->cc_field;
3657                 break;
3658         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3659                 return priv->bcc_field;
3660                 break;
3661         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3662                 return priv->subject_field;
3663                 break;
3664         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3665                 return priv->attachments_view;
3666                 break;
3667         default:
3668                 return NULL;
3669         }
3670 }
3671
3672 static void 
3673 remove_tags (WPTextBuffer *buffer)
3674 {
3675         GtkTextIter start, end;
3676
3677         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3678         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3679
3680         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3681 }
3682
3683 static void
3684 on_account_removed (TnyAccountStore *account_store, 
3685                     TnyAccount *account,
3686                     gpointer user_data)
3687 {
3688         /* Do nothing if it's a store account, because we use the
3689            transport to send the messages */
3690         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3691                 const gchar *parent_acc = NULL;
3692                 const gchar *our_acc = NULL;
3693
3694                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3695                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3696                 /* Close this window if I'm showing a message of the removed account */
3697                 if (strcmp (parent_acc, our_acc) == 0)
3698                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3699         }
3700 }
3701
3702 static void
3703 from_field_changed (HildonPickerButton *button,
3704                     ModestMsgEditWindow *self)
3705 {
3706         ModestMsgEditWindowPrivate *priv;
3707         gboolean has_old_signature, has_new_signature;
3708         GtkTextIter iter;
3709         GtkTextIter match_start, match_end;
3710         ModestAccountMgr *mgr;
3711         gchar *signature;
3712         gchar *full_signature;
3713
3714         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3715
3716         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3717         mgr = modest_runtime_get_account_mgr ();
3718         signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3719         if (has_old_signature) {
3720                 full_signature = g_strconcat ("\n--\n", signature, NULL);
3721                 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3722                         gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3723                         iter = match_start;
3724                 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3725                                                          &match_start, &match_end, NULL)) {
3726                         iter = match_start;
3727                 }
3728                 g_free (full_signature);
3729         }
3730         g_free (signature);
3731
3732         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3733         signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3734         if (has_new_signature) {
3735                 full_signature = g_strconcat ("\n--\n", signature, NULL);
3736                 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3737                 g_free (full_signature);
3738         }
3739         g_free (signature);
3740 }
3741
3742 typedef struct _MessageSettingsHelper {
3743         ModestMsgEditWindow *window;
3744         GSList *priority_group;
3745         GSList *format_group;
3746         GtkToggleButton *current_priority;
3747         GtkToggleButton *current_format;
3748 } MessageSettingsHelper;
3749
3750 static void
3751 on_priority_toggle (GtkToggleButton *button, 
3752                     MessageSettingsHelper *helper)
3753 {
3754         GSList *node;
3755         ModestMsgEditWindowPrivate *priv;
3756
3757         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3758         if (gtk_toggle_button_get_active (button)) {
3759
3760                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3761                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3762                         if ((node_button != button) &&
3763                             gtk_toggle_button_get_active (node_button)) {
3764                                 gtk_toggle_button_set_active (node_button, FALSE);
3765                         }
3766                 }
3767                 helper->current_priority = button;
3768         } else {
3769                 gboolean found = FALSE;
3770                 /* If no one is active, activate it again */
3771                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3772                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3773                         if (gtk_toggle_button_get_active (node_button)) {
3774                                 found = TRUE;
3775                                 break;
3776                         }
3777                 }
3778                 if (!found) {
3779                         gtk_toggle_button_set_active (button, TRUE);
3780                 }
3781         }
3782 }
3783
3784 static void
3785 on_format_toggle (GtkToggleButton *button,
3786                   MessageSettingsHelper *helper)
3787 {
3788         GSList *node;
3789         ModestMsgEditWindowPrivate *priv;
3790
3791         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3792         if (gtk_toggle_button_get_active (button)) {
3793
3794                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3795                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3796                         if ((node_button != button) &&
3797                             gtk_toggle_button_get_active (node_button)) {
3798                                 gtk_toggle_button_set_active (node_button, FALSE);
3799                         }
3800                 }
3801                 helper->current_format = button;
3802         } else {
3803                 gboolean found = FALSE;
3804                 /* If no one is active, activate it again */
3805                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3806                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3807                         if (gtk_toggle_button_get_active (node_button)) {
3808                                 found = TRUE;
3809                                 break;
3810                         }
3811                 }
3812                 if (!found) {
3813                         gtk_toggle_button_set_active (button, TRUE);
3814                 }
3815         }
3816
3817 }
3818
3819 static void
3820 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3821 {
3822         GtkWidget *dialog;
3823         GtkWidget *align;
3824         GtkWidget *vbox;
3825         GtkWidget *priority_hbox;
3826         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3827         GtkWidget *captioned;
3828         GtkSizeGroup *title_sizegroup, *value_sizegroup;
3829         GtkWidget *format_hbox;
3830         GtkWidget *html_toggle, *text_toggle;
3831         ModestMsgEditWindowPrivate *priv;
3832         MessageSettingsHelper helper = {0,};
3833
3834         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3835         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3836         helper.window = window;
3837         helper.priority_group = NULL;
3838         helper.format_group = NULL;
3839
3840         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3841         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3842
3843         dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3844                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3845                                               _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3846         vbox = gtk_vbox_new (FALSE, 0);
3847         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3848         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3849         gtk_container_add (GTK_CONTAINER (align), vbox);
3850         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3851         gtk_widget_show (align);
3852         gtk_widget_show (vbox);
3853
3854         /* Priority toggles */
3855         priority_hbox = gtk_hbox_new (TRUE, 0);
3856         high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3857         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3858         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3859         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3860         medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3861         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3862         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3863         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3864         low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3865         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3866         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3867         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3868         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3869         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3870         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3871         gtk_widget_show_all (priority_hbox);
3872         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3873                                                          _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3874         gtk_widget_show (captioned);
3875         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3876
3877         /* format toggles */
3878         format_hbox = gtk_hbox_new (TRUE, 0);
3879         html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3880         gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3881         helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3882         g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3883         g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3884         text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3885         gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3886         helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3887         g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3888         g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3889         gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3890         gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3891         gtk_widget_show_all (format_hbox);
3892         gtk_widget_show (format_hbox);
3893         gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3894
3895
3896         g_object_unref (title_sizegroup);
3897         g_object_unref (value_sizegroup);
3898
3899         /* Set current values */
3900         switch (priv->priority_flags) {
3901         case TNY_HEADER_FLAG_HIGH_PRIORITY:
3902                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3903                 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3904                 break;
3905         case TNY_HEADER_FLAG_LOW_PRIORITY:
3906                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3907                 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3908                 break;
3909         default:
3910                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3911                 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3912                 break;
3913         }
3914
3915         switch (modest_msg_edit_window_get_format (window)) {
3916         case MODEST_MSG_EDIT_FORMAT_TEXT:
3917                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3918                 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3919                 break;
3920         case MODEST_MSG_EDIT_FORMAT_HTML:
3921         default:
3922                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3923                 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3924                 break;
3925         }
3926
3927         /* Signal connects */
3928         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3929         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3930         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3931         g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3932         g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3933
3934         /* Save settings if the user clicked on done */
3935         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3936                 TnyHeaderFlags flags;
3937                 ModestMsgEditFormat old_format, new_format;
3938
3939                 /* Set priority flags */
3940                 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3941                 if (priv->priority_flags !=  flags)
3942                         modest_msg_edit_window_set_priority_flags (window, flags);
3943
3944                 /* Set edit format */
3945                 old_format = modest_msg_edit_window_get_format (window);
3946                 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3947                 if (old_format != new_format) {
3948                         gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3949                         modest_msg_edit_window_set_file_format (window, file_format);
3950                 }
3951         }
3952
3953         gtk_widget_destroy (dialog);
3954         g_slist_free (helper.priority_group);
3955 }
3956
3957 static void
3958 on_message_settings (GtkAction *action,
3959                      ModestMsgEditWindow *window)
3960 {
3961         modest_msg_edit_window_show_msg_settings_dialog (window);
3962 }
3963
3964 static void
3965 on_cc_button_toggled (HildonCheckButton *button,
3966                       ModestMsgEditWindow *window)
3967 {
3968         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3969
3970         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3971                                         hildon_check_button_get_active (button));
3972 }
3973
3974 static void
3975 on_bcc_button_toggled (HildonCheckButton *button,
3976                       ModestMsgEditWindow *window)
3977 {
3978         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3979
3980         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3981                                         hildon_check_button_get_active (button));
3982 }
3983
3984 static void 
3985 setup_menu (ModestMsgEditWindow *self)
3986 {
3987         ModestMsgEditWindowPrivate *priv = NULL;
3988
3989         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3990
3991         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3992
3993         /* Settings menu buttons */
3994         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3995                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3996                                            NULL);
3997         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3998                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3999                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4000
4001         priv->cc_button = hildon_check_button_new (0);
4002         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4003         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4004                                         FALSE);
4005         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4006                                                   NULL);
4007         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4008                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4009         priv->bcc_button = hildon_check_button_new (0);
4010         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4011         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4012                                         FALSE);
4013         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4014                                                   NULL);
4015         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4016                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4017
4018         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4019                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4020                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4021         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4022                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4023                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4024         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4025                                            APP_MENU_CALLBACK (on_message_settings),
4026                                            NULL);
4027         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4028                                            APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4029                                            NULL);
4030 }
4031