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