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