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