* message viewer window now also show message body
[modest] / src / gtk-glade / modest-ui-message-editor.c
1 #include <gtk/gtk.h>
2 #include <glade/glade.h>
3 #include <glib/gi18n.h>
4 #include <string.h>
5
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif /*HAVE_CONFIG_H*/
9
10 /* TODO: put in auto* */
11 #include <tny-text-buffer-stream.h>
12 #include <tny-msg-folder.h>
13
14 #include "../modest-ui.h"
15 #include "../modest-window-mgr.h"
16 #include "../modest-account-mgr.h"
17 #include "../modest-account-mgr.h"
18 #include "../modest-identity-mgr.h"
19
20 #include "../modest-tny-account-store.h"
21 #include "../modest-tny-folder-tree-view.h"
22 #include "../modest-tny-header-tree-view.h"
23 #include "../modest-tny-msg-view.h"
24 #include "../modest-tny-transport-actions.h"
25 #include "../modest-tny-store-actions.h"
26
27 #include "../modest-text-utils.h"
28 #include "../modest-tny-msg-actions.h"
29
30 #include "../modest-editor-window.h"
31
32 #include "modest-ui-glade.h"
33 #include "modest-ui-wizard.h"
34
35 #include "modest-ui-message-editor.h"
36
37
38 static void on_attach_button_clicked (GtkWidget *widget, ModestEditorWindow *modest_editwin);
39
40 static void on_send_button_clicked (GtkWidget *widget, ModestEditorWindow *modest_editwin);
41
42
43 typedef struct {
44         ModestUI *modest_ui;
45         ModestEditorWindow *edit_win;
46         GladeXML *glade_xml;
47         GList *attachments;
48 } EditWinData;
49
50
51 static gboolean close_edit_confirm_dialog(ModestEditorWindow *edit_win)
52 {
53         GtkWidget *mdialog;
54         gint res;
55
56         mdialog = gtk_message_dialog_new(GTK_WINDOW(edit_win),
57                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
58                         GTK_MESSAGE_QUESTION,
59                         GTK_BUTTONS_YES_NO,
60                         _("Message was modified.\nDiscard Changes?"));
61         gtk_widget_show_all (mdialog);
62
63         res=gtk_dialog_run(GTK_DIALOG(mdialog));
64         gtk_widget_destroy (mdialog);
65         if (res == GTK_RESPONSE_YES)
66                 return TRUE;
67         else
68                 return FALSE;
69 }
70
71 static void
72 close_edit_window (GtkWidget *win, GdkEvent *event, gpointer data)
73 {
74         ModestEditorWindow *edit_win;
75         ModestUIPrivate *priv;
76         EditWinData *win_data;
77
78         edit_win = (ModestEditorWindow *)data;
79         win_data = modest_editor_window_get_data(edit_win);
80         priv = MODEST_UI_GET_PRIVATE(win_data->modest_ui);
81
82         // g_message("window was %s modified", modest_editor_window_get_modified(edit_win) ? "" : "not");
83
84         if (modest_editor_window_get_modified(edit_win)) {
85                 if (close_edit_confirm_dialog(edit_win)) {
86                         gtk_widget_hide (GTK_WIDGET(edit_win));
87                         modest_window_mgr_unregister(priv->modest_window_mgr, G_OBJECT(edit_win));
88                         gtk_widget_destroy(GTK_WIDGET(edit_win));
89                         g_message("closing window");
90                 } else {
91                         g_message("not closing window");
92                 }
93         } else {
94                 gtk_widget_hide (GTK_WIDGET(edit_win));
95                 modest_window_mgr_unregister(priv->modest_window_mgr, G_OBJECT(edit_win));
96                 gtk_widget_destroy(GTK_WIDGET(edit_win));
97                 g_message("closing window");
98         }
99 }
100
101
102 GtkContainer
103 *modest_ui_new_editor_window (ModestUI *modest_ui, gpointer *user_data)
104 {
105         GtkWidget       *top_container;
106         GladeXML                *glade_xml;
107         EditWinData             *win_data;
108
109         glade_xml = glade_xml_new(MODEST_GLADE, "new_mail_top_container", NULL);
110         if (!glade_xml)
111                 return NULL;
112
113         win_data = g_malloc(sizeof(EditWinData));
114         win_data->modest_ui = modest_ui;
115         win_data->glade_xml = glade_xml;
116         win_data->attachments = NULL;
117
118         *user_data = win_data;
119
120         top_container = glade_xml_get_widget(glade_xml, "new_mail_top_container");
121         if (!top_container) {
122                 g_object_unref(G_OBJECT(glade_xml));
123                 return NULL;
124         }
125         
126         return GTK_CONTAINER(top_container);
127 }
128
129
130 gboolean
131 modest_ui_editor_window_set_to_header(const gchar *to, gpointer window_data)
132 {
133         GladeXML *glade_xml;
134         GtkWidget *w;
135         EditWinData *win_data;
136
137         win_data = (EditWinData *)window_data;
138         glade_xml = win_data->glade_xml;
139         w = glade_xml_get_widget(glade_xml, "to_entry");
140         gtk_entry_set_text(GTK_ENTRY(w), to);
141
142         return TRUE;
143 }
144
145
146 gboolean
147 modest_ui_editor_window_set_cc_header(const gchar *cc, gpointer window_data)
148 {
149         GladeXML *glade_xml;
150         // GtkWidget *w;
151         EditWinData *win_data;
152
153         win_data = (EditWinData *)window_data;
154         glade_xml = win_data->glade_xml;
155 /*
156         w = glade_xml_get_widget(glade_xml, "cc_entry");
157         gtk_entry_set_text(GTK_ENTRY(w), cc);
158 */
159         return TRUE;
160 }
161
162
163 gboolean
164 modest_ui_editor_window_set_bcc_header(const gchar *bcc, gpointer window_data)
165 {
166         GladeXML *glade_xml;
167         // GtkWidget *w;
168         EditWinData *win_data;
169
170         win_data = (EditWinData *)window_data;
171         glade_xml = win_data->glade_xml;
172 /*
173         w = glade_xml_get_widget(glade_xml, "bcc_entry");
174         gtk_entry_set_text(GTK_ENTRY(w), bcc);
175 */
176         return TRUE;
177 }
178
179
180 gboolean
181 modest_ui_editor_window_set_subject_header(const gchar *subject, gpointer window_data)
182 {
183         GladeXML *glade_xml;
184         GtkWidget *w;
185         EditWinData *win_data;
186
187         win_data = (EditWinData *)window_data;
188         glade_xml = win_data->glade_xml;
189
190         w = glade_xml_get_widget(glade_xml, "subject_entry");
191         gtk_entry_set_text(GTK_ENTRY(w), subject);
192
193         return TRUE;
194 }
195
196
197 gboolean
198 modest_ui_editor_window_set_body(const gchar *body, gpointer window_data)
199 {
200         GladeXML *glade_xml;
201         GtkWidget *body_view;
202         GtkTextBuffer *buf;
203         EditWinData *win_data;
204
205         win_data = (EditWinData *)window_data;
206         glade_xml = win_data->glade_xml;
207
208         body_view = glade_xml_get_widget(glade_xml, "body_view");
209         buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(body_view));
210
211         gtk_text_buffer_set_text(GTK_TEXT_BUFFER(buf), body, -1);
212
213         return TRUE;
214 }
215
216
217 gboolean
218 modest_ui_editor_window_update_attachments(gpointer window_data)
219 {
220         GladeXML *glade_xml;
221         
222         glade_xml = ((EditWinData *) window_data)->glade_xml;
223
224         //body_view = glade_xml_get_widget(glade_xml, "body_view");
225         
226         return TRUE;
227 }
228
229
230 static
231 void on_editor_entry_changed(GtkEditable *editable,
232                                             gpointer     user_data)
233 {
234         GtkWidget *edit_win;
235         EditWinData *windata;
236
237         edit_win = (GtkWidget *)user_data;
238         windata = (EditWinData *)modest_editor_window_get_data(MODEST_EDITOR_WINDOW(edit_win));
239
240         modest_editor_window_set_modified(MODEST_EDITOR_WINDOW(edit_win), TRUE);
241 }
242
243
244 static
245 void on_editor_buffer_changed (GtkTextBuffer *textbuffer,
246                                             gpointer       user_data)
247 {
248         GtkWidget *edit_win;
249         
250         edit_win = (GtkWidget *)user_data;
251         modest_editor_window_set_modified(MODEST_EDITOR_WINDOW(edit_win), TRUE);
252 }
253
254
255 static void
256 new_editor_with_presets (ModestUI *modest_ui, const gchar *to_header,
257                                                         const gchar *cc_header, const gchar *bcc_header,
258                                                         const gchar *subject_header, const gchar *body)
259 {
260         GtkWidget *edit_win;
261         GladeXML *glade_xml;
262         GtkWidget *btn, *w;
263         GtkTextBuffer *buf;
264         EditWinData *windata;
265         ModestUIPrivate *priv;
266         gint height, width;
267
268         g_return_if_fail (modest_ui);
269
270         edit_win = modest_editor_window_new(modest_ui);
271         windata = (EditWinData *)modest_editor_window_get_data(MODEST_EDITOR_WINDOW(edit_win));
272         g_return_if_fail(windata);
273
274         glade_xml = windata->glade_xml;
275         btn = glade_xml_get_widget (glade_xml, "toolb_send");
276         g_signal_connect (btn, "clicked", G_CALLBACK(on_send_button_clicked),
277                           edit_win);
278         btn = glade_xml_get_widget (glade_xml, "toolb_attach");
279         g_signal_connect (btn, "clicked", G_CALLBACK(on_attach_button_clicked),
280                           edit_win);
281
282         w = glade_xml_get_widget (glade_xml, "to_entry");
283         g_signal_connect(w, "changed", G_CALLBACK(on_editor_entry_changed), edit_win);
284         w = glade_xml_get_widget (glade_xml, "subject_entry");
285         g_signal_connect(w, "changed", G_CALLBACK(on_editor_entry_changed), edit_win);
286         w = glade_xml_get_widget (glade_xml, "body_view");
287         buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w));
288         g_signal_connect(buf, "changed", G_CALLBACK(on_editor_buffer_changed), edit_win);
289
290         g_signal_connect (edit_win, "destroy-event", G_CALLBACK(close_edit_window),
291                           edit_win);
292         g_signal_connect (edit_win, "delete-event", G_CALLBACK(close_edit_window),
293                           edit_win);
294
295         priv = MODEST_UI_GET_PRIVATE(modest_ui);
296         height = modest_conf_get_int (priv->modest_conf,
297                                           MODEST_CONF_EDIT_WINDOW_HEIGHT, NULL);
298         width  = modest_conf_get_int (priv->modest_conf,
299                                           MODEST_CONF_EDIT_WINDOW_WIDTH, NULL);
300
301         // g_message("new editor win@%dx%d", width, height);
302
303         gtk_widget_set_usize (GTK_WIDGET(edit_win), width, height);
304         if (strlen(subject_header) > 0)
305                 gtk_window_set_title (GTK_WINDOW(edit_win), subject_header);
306         else
307                 gtk_window_set_title (GTK_WINDOW(edit_win), _("Untitled"));
308
309         modest_window_mgr_register(priv->modest_window_mgr, G_OBJECT(edit_win), MODEST_EDIT_WINDOW, 0);
310
311         modest_editor_window_set_to_header(MODEST_EDITOR_WINDOW(edit_win), to_header);
312         modest_editor_window_set_cc_header(MODEST_EDITOR_WINDOW(edit_win), cc_header);
313         modest_editor_window_set_bcc_header(MODEST_EDITOR_WINDOW(edit_win), bcc_header);
314         modest_editor_window_set_subject_header(MODEST_EDITOR_WINDOW(edit_win), subject_header);
315         modest_editor_window_set_body(MODEST_EDITOR_WINDOW(edit_win), body);
316
317         modest_editor_window_set_modified(MODEST_EDITOR_WINDOW(edit_win), FALSE);
318
319         gtk_widget_show(edit_win);
320 }
321
322
323 void
324 on_new_mail_clicked (GtkWidget *widget, gpointer user_data)
325 {
326         ModestUI *modest_ui = (ModestUI *) modest_ui;
327
328         new_editor_with_presets(modest_ui, "", "", "", "", "");
329 }
330
331
332 void
333 quoted_send_msg (ModestUI *modest_ui, quoted_send_type qstype)
334 {
335         GtkTreeSelection *sel;
336         GtkWidget *paned;
337         GtkTreeModel *model;
338         GtkTreeIter iter;
339         GtkScrolledWindow *scroll;
340
341         TnyMsgHeaderIface *header;
342
343         ModestTnyHeaderTreeView *header_view;
344         ModestTnyMsgView *msg_view;
345         ModestUIPrivate *priv;
346
347         const TnyMsgIface *msg;
348         const TnyMsgFolderIface *folder;
349         GString *re_sub;
350         const gchar *subject, *from;
351         gchar *unquoted, *quoted;
352         time_t sent_date;
353         gint line_limit = 76;
354
355         g_return_if_fail (modest_ui);
356
357         priv = MODEST_UI_GET_PRIVATE(modest_ui);
358
359         paned = glade_xml_get_widget (priv->glade_xml,"mail_paned");
360         g_return_if_fail (paned);
361
362         scroll = GTK_SCROLLED_WINDOW(gtk_paned_get_child1 (GTK_PANED(paned)));
363         g_return_if_fail (scroll);
364
365         msg_view = MODEST_TNY_MSG_VIEW(gtk_paned_get_child2 (GTK_PANED(paned)));
366         g_return_if_fail (msg_view);
367
368         header_view = MODEST_TNY_HEADER_TREE_VIEW(gtk_bin_get_child (GTK_BIN(scroll)));
369         g_return_if_fail (header_view);
370
371         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(header_view));
372         g_return_if_fail (sel);
373
374         if (!gtk_tree_selection_get_selected (sel, &model, &iter)) {
375                 g_warning("nothing to reply to");
376                 return;
377         }
378
379         gtk_tree_model_get (model, &iter,
380                             TNY_MSG_HEADER_LIST_MODEL_INSTANCE_COLUMN,
381                             &header, -1);
382
383         if (!header) {
384                 g_warning("no header");
385                 return;
386         }
387
388         folder = tny_msg_header_iface_get_folder (TNY_MSG_HEADER_IFACE(header));
389         if (!folder) {
390                 g_warning ("cannot find folder");
391                 return;
392         }
393
394         msg = tny_msg_folder_iface_get_message (TNY_MSG_FOLDER_IFACE(folder), header);
395         if (!msg) {
396                 g_warning ("cannot find msg");
397                 return;
398         }
399
400         subject = tny_msg_header_iface_get_subject(header);
401         re_sub = g_string_new(subject);
402         /* FIXME: honor replyto, cc */
403         from = tny_msg_header_iface_get_from(header);
404         sent_date = tny_msg_header_iface_get_date_sent(header);
405
406         unquoted = modest_tny_msg_view_get_selected_text(msg_view);
407         quoted = modest_tny_msg_actions_quote(msg, from, sent_date, line_limit, unquoted);
408
409         switch (qstype) {
410                 case QUOTED_SEND_REPLY:
411                         g_string_prepend(re_sub, _("Re: "));
412                         new_editor_with_presets(modest_ui, from, /* cc */ "", /* bcc */ "", re_sub->str, quoted);
413                         break;
414                 case QUOTED_SEND_FORWARD:
415                         g_string_prepend(re_sub, _("Fwd: "));
416                         new_editor_with_presets(modest_ui, /* from */ "", /* cc */ "", /* bcc */ "", re_sub->str, quoted);
417                         break;
418                 default:
419                         break;
420         }
421         g_free(quoted);
422         g_free(unquoted);
423         g_string_free(re_sub, TRUE);
424 }
425
426
427 static void
428 on_attach_button_clicked (GtkWidget *widget, ModestEditorWindow *modest_editwin)
429 {
430         /* open file selector */
431         GtkWidget *dialog;
432         gchar *mime_type;
433         gchar *filename = NULL;
434         
435         dialog = gtk_file_chooser_dialog_new ("Open File",
436                                                                                   GTK_WINDOW(modest_editwin),
437                                                                                   GTK_FILE_CHOOSER_ACTION_OPEN,
438                                                                                   GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
439                                                                                   GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
440                                                                                   NULL);
441
442         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
443         {
444
445                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
446                 printf ("file:%s\n", filename);
447         }
448         gtk_widget_destroy (dialog);
449       
450         /* check file */
451         if (!filename)
452                 return;
453         
454         g_return_if_fail(g_str_has_suffix(filename, ".jpg")); /* for now... */
455         
456         /* get mime type */
457         mime_type = "image/jpeg";
458         
459         /* attach file */
460         
461         modest_editor_window_attach_file(modest_editwin, filename);
462         
463         g_free (filename);
464 }
465
466
467 static void
468 on_send_button_clicked (GtkWidget *widget, ModestEditorWindow *modest_editwin)
469 {
470         ModestTnyTransportActions *actions;
471         ModestUI *modest_ui;
472         ModestUIPrivate *priv;
473         GtkWidget *to_entry, *subject_entry, *body_view;
474         const gchar *to, *subject, *email_from;
475         gchar *body;
476         GtkTextIter start, end;
477         GtkTextBuffer *buf;
478         TnyAccountStoreIface *account_store;
479         const GList *transport_accounts;
480         TnyTransportAccountIface *transport_account;
481         ModestIdentityMgr *id_mgr;
482         EditWinData *win_data;
483         GList * attachments;
484
485
486         win_data = modest_editor_window_get_data(modest_editwin);
487         modest_ui = win_data->modest_ui;
488
489         g_return_if_fail (modest_ui);
490
491         actions = MODEST_TNY_TRANSPORT_ACTIONS
492                 (modest_tny_transport_actions_new ());
493
494         priv = MODEST_UI_GET_PRIVATE(modest_ui);
495
496         account_store = priv->account_store;
497         transport_accounts =
498                 tny_account_store_iface_get_transport_accounts (account_store);
499         if (!transport_accounts) {
500                 g_message ("cannot send message: no transport account defined");
501                 return;
502         } else /* take the first one! */
503                 transport_account =
504                         TNY_TRANSPORT_ACCOUNT_IFACE(transport_accounts->data);
505
506         to_entry      = glade_xml_get_widget (win_data->glade_xml, "to_entry");
507         subject_entry = glade_xml_get_widget (win_data->glade_xml, "subject_entry");
508         body_view     = glade_xml_get_widget (win_data->glade_xml, "body_view");
509
510         to      = gtk_entry_get_text (GTK_ENTRY(to_entry));
511         subject = gtk_entry_get_text (GTK_ENTRY(subject_entry));
512
513         buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(body_view));
514         gtk_text_buffer_get_bounds (buf, &start, &end);
515         body    = gtk_text_buffer_get_text (buf, &start, &end, FALSE);
516
517         id_mgr = priv->modest_id_mgr;
518         email_from = modest_identity_mgr_get_identity_string(id_mgr,
519                                                              MODEST_IDENTITY_DEFAULT_IDENTITY,
520                                                              MODEST_IDENTITY_EMAIL, NULL);
521         attachments = modest_editor_window_get_attachments(modest_editwin);
522         /* while (attachments) {
523                 printf("att: %s\n", (gchar *) attachments->data);
524                 attachments = attachments->next;
525         } */
526         if (!email_from)
527                 email_from = "";
528         
529         g_message("sending \"%s\" %s ==> %s", subject, email_from, to);
530
531         modest_tny_transport_actions_send_message (actions,
532                                                    transport_account,
533                                                    email_from,
534                                                    to, "", "", subject,
535                                                    body,
536                                                    attachments);
537
538         g_free (body);
539         g_object_unref (G_OBJECT(actions));
540
541         gtk_widget_hide (GTK_WIDGET(modest_editwin));
542         modest_window_mgr_unregister(priv->modest_window_mgr, G_OBJECT(modest_editwin));
543         if (GTK_IS_WIDGET(modest_editwin)) {
544                 gtk_widget_destroy(GTK_WIDGET(modest_editwin));
545         } else
546                 g_warning("editor window has vanished!");
547 }