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