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