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