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