1c42131f37122f44bdfaff29521510364f14b2fa
[claws.git] / src / quote_fmt.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <glib.h>
25 #include <glib/gi18n.h>
26 #include <gtk/gtk.h>
27 #include <gdk/gdkkeysyms.h>
28
29 #include "manage_window.h"
30 #include "description_window.h"
31 #include "gtkutils.h"
32
33 #include "prefs_gtk.h"
34 #include "prefs_common.h"
35 #include "quote_fmt.h"
36 #include "alertpanel.h"
37 #include "prefs_template.h"
38
39
40 /*
41  * Strings describing quote format strings
42  * 
43  * When adding new lines, remember to put 2 strings for each line
44  */
45 static gchar *quote_desc_strings[] = {
46         N_("<span weight=\"bold\">symbols:</span>"),                            NULL,
47         "%date_fmt{<span style=\"oblique\">fmt</span>} (%D{<span style=\"oblique\">fmt</span>})",       N_("customized date format (see 'man strftime')"), /* date expression */
48         "%date (%d)",                           N_("Date"), /* date */
49         "%from (%f)",                           N_("From"), /* from */
50         "%email (%A)",                          N_("email address of sender"), /* email address */
51         "%fullname (%N)",                       N_("full name of sender"), /* full name */
52         "%firstname (%F)",                      N_("first name of sender"), /* first name */
53         "%lastname (%L)",                       N_("last name of sender"), /* last name */
54         "%initials (%I)",                       N_("initials of sender"), /* initial of sender */
55         "%subject (%s)",                        N_("Subject"), /* subject */ 
56         "%to (%t)",                                     N_("To"), /* to */ 
57         "%cc (%c)",                                     N_("Cc"), /* cc */ 
58         "%newsgroups (%n)",                     N_("Newsgroups"), /* newsgroups */ 
59         "%references (%r)",                     N_("References"), /* references */ 
60         "%messageid (%i)",                      N_("Message-ID"), /* message-id */ 
61         "%msg (%M)",                            N_("message body"), /* message */
62         "%quoted_msg (%Q)",                     N_("quoted message body"), /* quoted message */
63         "%msg_no_sig (%m)",                     N_("message body without signature"), /* message with no signature */
64         "%quoted_msg_no_sig (%q)",      N_("quoted message body without signature"), /* quoted message with no signature */
65         "%tags",                                N_("message tags"), /* message tags */
66         "%dict (%T)",                           N_("current dictionary"), /* current dictionary */
67         "%cursor (%X)",                         N_("cursor position"), /* X marks the cursor spot */
68         "%account_fullname (%af)",      N_("account property: your name"), /* full name in compose account */
69         "%account_email (%am)",         N_("account property: your email address"), /* mail address in compose account */
70         "%account_name (%an)",          N_("account property: account name"), /* compose account name itself */
71         "%account_org (%ao)",           N_("account property: organization"), /* organization in compose account */
72         "%account_dict (%aT)",          N_("account property: default dictionary"), /* main dict (if enabled) in account */
73         "%addrbook_cc (%ABc)",          N_("address book <span style=\"oblique\">completion</span>: Cc"), /* completion of 'Cc' from address book */
74         "%addrbook_from (%ABf)",        N_("address book <span style=\"oblique\">completion</span>: From"), /* completion of 'From' from address book */
75         "%addrbook_to (%ABt)",          N_("address book <span style=\"oblique\">completion</span>: To"), /* completion of 'To' from address book */
76         "\\%",                          N_("literal %"),
77         "\\\\",                         N_("literal backslash"),
78         "\\?",                          N_("literal question mark"),
79         "\\!",                          N_("literal exclamation mark"),
80         "\\|",                          N_("literal pipe"),
81         "\\{",                          N_("literal opening curly brace"),
82         "\\}",                          N_("literal closing curly brace"),
83         "\\t",                          N_("tab"),
84         "\\n",                          N_("new line"),
85         "",                                     NULL,
86         N_("<span weight=\"bold\">commands:</span>"),           NULL,
87         "?x{<span style=\"oblique\">expr</span>}\n\n",          N_("insert <span style=\"oblique\">expr</span> if x is set, where x is one of\nthe [dfNFLIstcnriT, ad, af, ao, aT, ABc, ABf, ABt]\nsymbols (or their long equivalent)"),
88         "!x{<span style=\"oblique\">expr</span>}\n\n",          N_("insert <span style=\"oblique\">expr</span> if x is not set, where x is one of\nthe [dfNFLIstcnriT, ad, af, ao, aT, ABc, ABf, ABt]\nsymbols (or their long equivalent)"),
89         "|file{<span style=\"oblique\">sub_expr</span>}\n(|f{<span style=\"oblique\">sub_expr</span>})",                N_("insert file:\n<span style=\"oblique\">sub_expr</span> is evaluated as the path of the file to insert"), /* insert file */
90         "|program{<span style=\"oblique\">sub_expr</span>}\n(|p{<span style=\"oblique\">sub_expr</span>})\n",   N_("insert program output:\n<span style=\"oblique\">sub_expr</span> is evaluated as a command-line to get\nthe output from"), /* insert program output */
91         "|input{<span style=\"oblique\">sub_expr</span>}\n(|i{<span style=\"oblique\">sub_expr</span>})\n",             N_("insert user input:\n<span style=\"oblique\">sub_expr</span> is a variable to be replaced by\nuser-entered text"), /* insert user input */
92         "",                                     NULL,
93         N_("<span weight=\"bold\">definition of terms:</span>"),        NULL,
94         "<span style=\"oblique\">expr</span>\n",                        N_("text that can contain any of the symbols or\ncommands above"),
95         "<span style=\"oblique\">sub_expr</span>\n",            N_("text that can contain any of the symbols (no\ncommands) above"),
96         "<span style=\"oblique\">completion</span>\n\n\n",      N_("completion from address book only works with the first\naddress of the header, it outputs the full name\nof the contact if that address matches exactly\none contact in the address book"),
97         NULL,NULL
98 };
99
100 static DescriptionWindow quote_desc_win = { 
101         NULL,
102         NULL,
103         2,
104         N_("Description of symbols"),
105         N_("The following symbols and commands can be used:"),
106         quote_desc_strings
107 };
108
109
110 void quote_fmt_quote_description(GtkWidget *widget, GtkWidget *pref_window)
111 {
112         quote_desc_win.parent = pref_window;
113         description_window_create(&quote_desc_win);
114 }
115
116 void quotefmt_create_new_msg_fmt_widgets(GtkWindow *parent_window,
117                                                 GtkWidget *parent_box,
118                                                 GtkWidget **checkbtn_compose_with_format,
119                                                 GtkWidget **edit_subject_format,
120                                                 GtkWidget **edit_body_format,
121                                                 gboolean add_info_button)
122 {
123         GtkWidget *checkbtn_use_format = NULL;
124         GtkWidget *vbox_format;
125         GtkWidget *hbox_format;
126         GtkWidget *label_subject;
127         GtkWidget *entry_subject;
128         GtkWidget *scrolledwin_format;
129         GtkWidget *text_format;
130
131         if (add_info_button)
132                 g_return_if_fail(parent_window != NULL);
133         g_return_if_fail(parent_box != NULL);
134         if (checkbtn_compose_with_format)
135                 g_return_if_fail(checkbtn_compose_with_format != NULL);
136
137         g_return_if_fail(edit_subject_format != NULL);
138         g_return_if_fail(edit_body_format != NULL);
139
140         if (checkbtn_compose_with_format)
141                 PACK_CHECK_BUTTON (parent_box, checkbtn_use_format, 
142                                    _("Use template when composing new messages"));
143
144         vbox_format = gtk_vbox_new (FALSE, 4);
145         gtk_widget_show(vbox_format);
146         gtk_container_add(GTK_CONTAINER (parent_box), vbox_format);
147         gtk_container_set_border_width (GTK_CONTAINER (vbox_format), 8);
148
149         hbox_format = gtk_hbox_new (FALSE, 8);
150         gtk_widget_show (hbox_format);
151         gtk_box_pack_start (GTK_BOX (vbox_format), hbox_format, FALSE, FALSE, 0);
152
153         label_subject = gtk_label_new (_("Subject"));
154         gtk_widget_show (label_subject);
155         gtk_box_pack_start (GTK_BOX (hbox_format), label_subject, FALSE, FALSE, 0);
156
157         entry_subject = gtk_entry_new ();
158         gtk_widget_show (entry_subject);
159         gtk_box_pack_start (GTK_BOX (hbox_format), entry_subject, TRUE, TRUE, 0);
160         gtk_widget_set_size_request (entry_subject, 100, -1);
161
162         scrolledwin_format = gtk_scrolled_window_new (NULL, NULL);
163         gtk_widget_show (scrolledwin_format);
164         gtk_box_pack_start (GTK_BOX (vbox_format), scrolledwin_format,
165                             TRUE, TRUE, 0);
166         gtk_scrolled_window_set_policy
167                 (GTK_SCROLLED_WINDOW (scrolledwin_format),
168                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
169         gtk_scrolled_window_set_shadow_type
170                 (GTK_SCROLLED_WINDOW (scrolledwin_format), GTK_SHADOW_IN);
171
172         text_format = gtk_text_view_new ();
173         if (prefs_common.textfont) {
174                 PangoFontDescription *font_desc;
175
176                 font_desc = pango_font_description_from_string
177                                                 (prefs_common.textfont);
178                 if (font_desc) {
179                         gtk_widget_modify_font(text_format, font_desc);
180                         pango_font_description_free(font_desc);
181                 }
182         }
183         gtk_widget_show(text_format);
184         gtk_container_add(GTK_CONTAINER(scrolledwin_format), text_format);
185         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_format), TRUE);
186         gtk_widget_set_size_request(text_format, -1, 100);
187
188         if (checkbtn_compose_with_format) {
189                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, label_subject);
190                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, entry_subject);
191                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, text_format);
192         }
193
194         if (add_info_button)
195                 quotefmt_add_info_button(parent_window, vbox_format);
196
197         if (checkbtn_compose_with_format)
198                 *checkbtn_compose_with_format = checkbtn_use_format;
199         *edit_subject_format = entry_subject;
200         *edit_body_format = text_format;
201 }
202
203 void quotefmt_create_reply_fmt_widgets(GtkWindow *parent_window,
204                                                 GtkWidget *parent_box,
205                                                 GtkWidget **checkbtn_reply_with_format,
206                                                 GtkWidget **edit_reply_quotemark,
207                                                 GtkWidget **edit_reply_format,
208                                                 gboolean add_info_button)
209 {
210         GtkWidget *checkbtn_use_format = NULL;
211         GtkWidget *vbox_quote;
212         GtkWidget *hbox1;
213         GtkWidget *hbox2;
214         GtkWidget *label_quotemark;
215         GtkWidget *entry_quotemark;
216         GtkWidget *scrolledwin_quotefmt;
217         GtkWidget *text_quotefmt;
218
219         if (add_info_button)
220                 g_return_if_fail(parent_window != NULL);
221         g_return_if_fail(parent_box != NULL);
222         if (checkbtn_reply_with_format)
223                 g_return_if_fail(checkbtn_reply_with_format != NULL);
224
225         g_return_if_fail(edit_reply_quotemark != NULL);
226         g_return_if_fail(edit_reply_format != NULL);
227
228         if (checkbtn_reply_with_format)
229                 PACK_CHECK_BUTTON (parent_box, checkbtn_use_format,
230                                    _("Use template when replying to messages"));
231
232         vbox_quote = gtk_vbox_new (FALSE, 4);
233         gtk_widget_show(vbox_quote);
234         gtk_container_add(GTK_CONTAINER (parent_box), vbox_quote);
235         gtk_container_set_border_width (GTK_CONTAINER (vbox_quote), 8);
236
237         hbox1 = gtk_hbox_new (FALSE, 32);
238         gtk_widget_show (hbox1);
239         gtk_box_pack_start (GTK_BOX (vbox_quote), hbox1, FALSE, FALSE, 0);
240
241         hbox2 = gtk_hbox_new (FALSE, 8);
242         gtk_widget_show (hbox2);
243         gtk_box_pack_start (GTK_BOX (hbox1), hbox2, FALSE, FALSE, 0);
244
245         label_quotemark = gtk_label_new (_("Quotation mark"));
246         gtk_widget_show (label_quotemark);
247         gtk_box_pack_start (GTK_BOX (hbox2), label_quotemark, FALSE, FALSE, 0);
248
249         entry_quotemark = gtk_entry_new ();
250         gtk_widget_show (entry_quotemark);
251         gtk_box_pack_start (GTK_BOX (hbox2), entry_quotemark, FALSE, FALSE, 0);
252         gtk_widget_set_size_request (entry_quotemark, 64, -1);
253
254         scrolledwin_quotefmt = gtk_scrolled_window_new (NULL, NULL);
255         gtk_widget_show (scrolledwin_quotefmt);
256         gtk_box_pack_start (GTK_BOX (vbox_quote), scrolledwin_quotefmt,
257                             TRUE, TRUE, 0);
258         gtk_scrolled_window_set_policy
259                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt),
260                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
261         gtk_scrolled_window_set_shadow_type
262                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt), GTK_SHADOW_IN);
263
264         text_quotefmt = gtk_text_view_new ();
265         if (prefs_common.textfont) {
266                 PangoFontDescription *font_desc;
267
268                 font_desc = pango_font_description_from_string
269                                                 (prefs_common.textfont);
270                 if (font_desc) {
271                         gtk_widget_modify_font(text_quotefmt, font_desc);
272                         pango_font_description_free(font_desc);
273                 }
274         }
275         gtk_widget_show(text_quotefmt);
276         gtk_container_add(GTK_CONTAINER(scrolledwin_quotefmt), text_quotefmt);
277         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_quotefmt), TRUE);
278         gtk_widget_set_size_request(text_quotefmt, -1, 100);
279
280         if (checkbtn_reply_with_format) {
281                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, label_quotemark);
282                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, entry_quotemark);
283                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, text_quotefmt);
284         }
285
286         if (add_info_button)
287                 quotefmt_add_info_button(parent_window, vbox_quote);
288
289         if (checkbtn_reply_with_format)
290                 *checkbtn_reply_with_format = checkbtn_use_format;
291         *edit_reply_quotemark = entry_quotemark;
292         *edit_reply_format = text_quotefmt;
293 }
294
295 void quotefmt_create_forward_fmt_widgets(GtkWindow *parent_window,
296                                                 GtkWidget *parent_box,
297                                                 GtkWidget **checkbtn_forward_with_format,
298                                                 GtkWidget **edit_fw_quotemark,
299                                                 GtkWidget **edit_fw_format,
300                                                 gboolean add_info_button)
301 {
302         GtkWidget *checkbtn_use_format = NULL;
303         GtkWidget *vbox_quote;
304         GtkWidget *hbox1;
305         GtkWidget *hbox2;
306         GtkWidget *label_quotemark;
307         GtkWidget *entry_fw_quotemark;
308         GtkWidget *scrolledwin_quotefmt;
309         GtkWidget *text_fw_quotefmt;
310
311         if (add_info_button)
312                 g_return_if_fail(parent_window != NULL);
313         g_return_if_fail(parent_box != NULL);
314         if (checkbtn_forward_with_format) {
315                 g_return_if_fail(checkbtn_forward_with_format != NULL);
316         }
317         g_return_if_fail(edit_fw_quotemark != NULL);
318         g_return_if_fail(edit_fw_format != NULL);
319
320         if (checkbtn_forward_with_format)
321                 PACK_CHECK_BUTTON (parent_box, checkbtn_use_format,
322                                    _("Use template when forwarding messages"));
323
324         vbox_quote = gtk_vbox_new (FALSE, 4);
325         gtk_widget_show(vbox_quote);
326         gtk_container_add(GTK_CONTAINER (parent_box), vbox_quote);
327         gtk_container_set_border_width (GTK_CONTAINER (vbox_quote), 8);
328
329         hbox1 = gtk_hbox_new (FALSE, 32);
330         gtk_widget_show (hbox1);
331         gtk_box_pack_start (GTK_BOX (vbox_quote), hbox1, FALSE, FALSE, 0);
332
333         hbox2 = gtk_hbox_new (FALSE, 8);
334         gtk_widget_show (hbox2);
335         gtk_box_pack_start (GTK_BOX (hbox1), hbox2, FALSE, FALSE, 0);
336
337         label_quotemark = gtk_label_new (_("Quotation mark"));
338         gtk_widget_show (label_quotemark);
339         gtk_box_pack_start (GTK_BOX (hbox2), label_quotemark, FALSE, FALSE, 0);
340
341         entry_fw_quotemark = gtk_entry_new ();
342         gtk_widget_show (entry_fw_quotemark);
343         gtk_box_pack_start (GTK_BOX (hbox2), entry_fw_quotemark,
344                             FALSE, FALSE, 0);
345         gtk_widget_set_size_request (entry_fw_quotemark, 64, -1);
346
347         scrolledwin_quotefmt = gtk_scrolled_window_new (NULL, NULL);
348         gtk_widget_show (scrolledwin_quotefmt);
349         gtk_box_pack_start (GTK_BOX (vbox_quote), scrolledwin_quotefmt,
350                             TRUE, TRUE, 0);
351         gtk_scrolled_window_set_policy
352                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt),
353                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
354         gtk_scrolled_window_set_shadow_type
355                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt), GTK_SHADOW_IN);
356
357         text_fw_quotefmt = gtk_text_view_new ();
358         if (prefs_common.textfont) {
359                 PangoFontDescription *font_desc;
360
361                 font_desc = pango_font_description_from_string
362                                                 (prefs_common.textfont);
363                 if (font_desc) {
364                         gtk_widget_modify_font(text_fw_quotefmt, font_desc);
365                         pango_font_description_free(font_desc);
366                 }
367         }
368         gtk_widget_show(text_fw_quotefmt);
369         gtk_container_add(GTK_CONTAINER(scrolledwin_quotefmt),
370                           text_fw_quotefmt);
371         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_fw_quotefmt), TRUE);
372         gtk_widget_set_size_request (text_fw_quotefmt, -1, 100);
373
374         if (checkbtn_forward_with_format) {
375                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, label_quotemark);
376                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, entry_fw_quotemark);
377                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, text_fw_quotefmt);
378         }
379
380         if (add_info_button)
381                 quotefmt_add_info_button(parent_window, vbox_quote);
382
383         if (checkbtn_forward_with_format)
384                 *checkbtn_forward_with_format = checkbtn_use_format;
385         *edit_fw_quotemark = entry_fw_quotemark;
386         *edit_fw_format = text_fw_quotefmt;
387 }
388
389 void quotefmt_add_info_button(GtkWindow *parent_window, GtkWidget *parent_box)
390 {
391         GtkWidget *hbox_formatdesc;
392         GtkWidget *btn_formatdesc;
393
394         hbox_formatdesc = gtk_hbox_new (FALSE, 32);
395         gtk_widget_show (hbox_formatdesc);
396         gtk_box_pack_start (GTK_BOX (parent_box), hbox_formatdesc, FALSE, FALSE,
397                                 VBOX_BORDER);
398
399 #if GTK_CHECK_VERSION(2, 8, 0)
400         btn_formatdesc = gtk_button_new_from_stock(GTK_STOCK_INFO);
401 #else
402         btn_formatdesc =
403                 gtk_button_new_with_label (_("Description of symbols..."));
404 #endif
405         gtk_widget_show (btn_formatdesc);
406         gtk_box_pack_start (GTK_BOX (hbox_formatdesc), btn_formatdesc, FALSE, FALSE, 0);
407         g_signal_connect(G_OBJECT(btn_formatdesc), "clicked",
408                          G_CALLBACK(quote_fmt_quote_description), GTK_WIDGET(parent_window));
409 }
410
411
412 void quotefmt_check_new_msg_formats(gboolean use_format,
413                                                                         gchar *subject_fmt,
414                                                                         gchar *body_fmt)
415 {
416         if (use_format) {
417                 gint line;
418
419                 if (!prefs_template_string_is_valid(subject_fmt, NULL))
420                         alertpanel_error(_("New message subject format error."));
421
422                 if (!prefs_template_string_is_valid(body_fmt, &line)) {
423                         alertpanel_error(_("New message body format error at line %d."), line);
424                 }
425         }
426 }
427
428 void quotefmt_check_reply_formats(gboolean use_format,
429                                                                         gchar *quotation_mark,
430                                                                         gchar *body_fmt)
431 {
432         if (use_format) {
433                 gint line;
434
435                 if (!prefs_template_string_is_valid(quotation_mark, NULL))
436                         alertpanel_error(_("Message reply quotation mark format error."));
437
438                 if (!prefs_template_string_is_valid(body_fmt, &line)) {
439                         alertpanel_error(_("Message reply format error at line %d."), line);
440                 }
441         }
442 }
443
444 void quotefmt_check_forward_formats(gboolean use_format,
445                                                                         gchar *quotation_mark,
446                                                                         gchar *body_fmt)
447 {
448         if (use_format) {
449                 gint line;
450
451                 if (!prefs_template_string_is_valid(quotation_mark, NULL))
452                         alertpanel_error(_("Message forward quotation mark format error."));
453
454                 if (!prefs_template_string_is_valid(body_fmt, &line)) {
455                         alertpanel_error(_("Message forward format error at line %d."), line);
456                 }
457         }
458 }