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