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