70edd55c097d231b1fac98b9de1bd990e1504349
[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                                                 gchar *checkbtn_compose_text,
120                                                 GtkWidget **edit_subject_format,
121                                                 GtkWidget **edit_body_format,
122                                                 gboolean add_info_button)
123 {
124         GtkWidget *checkbtn_use_format = NULL;
125         GtkWidget *frame_format;
126         GtkWidget *vbox_format;
127         GtkWidget *hbox_format;
128         GtkWidget *label_subject;
129         GtkWidget *entry_subject;
130         GtkWidget *scrolledwin_format;
131         GtkWidget *text_format;
132
133         if (add_info_button)
134                 g_return_if_fail(parent_window != NULL);
135         g_return_if_fail(parent_box != NULL);
136         if (checkbtn_compose_with_format) {
137                 g_return_if_fail(checkbtn_compose_with_format != NULL);
138                 g_return_if_fail(checkbtn_compose_text != NULL);
139         }
140         g_return_if_fail(edit_subject_format != NULL);
141         g_return_if_fail(edit_body_format != NULL);
142
143         if (checkbtn_compose_with_format)
144                 PACK_CHECK_BUTTON (parent_box, checkbtn_use_format, 
145                                    _("Use format when composing new messages"));
146
147         vbox_format = gtkut_get_options_frame(parent_box, &frame_format, checkbtn_compose_text);
148
149         if (checkbtn_compose_with_format)
150                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, frame_format);
151
152         hbox_format = gtk_hbox_new (FALSE, 8);
153         gtk_widget_show (hbox_format);
154         gtk_box_pack_start (GTK_BOX (vbox_format), hbox_format, FALSE, FALSE, 0);
155
156         label_subject = gtk_label_new (_("Subject"));
157         gtk_widget_show (label_subject);
158         gtk_box_pack_start (GTK_BOX (hbox_format), label_subject, FALSE, FALSE, 0);
159
160         entry_subject = gtk_entry_new ();
161         gtk_widget_show (entry_subject);
162         gtk_box_pack_start (GTK_BOX (hbox_format), entry_subject, TRUE, TRUE, 0);
163         gtk_widget_set_size_request (entry_subject, 100, -1);
164
165         scrolledwin_format = gtk_scrolled_window_new (NULL, NULL);
166         gtk_widget_show (scrolledwin_format);
167         gtk_box_pack_start (GTK_BOX (vbox_format), scrolledwin_format,
168                             TRUE, TRUE, 0);
169         gtk_scrolled_window_set_policy
170                 (GTK_SCROLLED_WINDOW (scrolledwin_format),
171                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
172         gtk_scrolled_window_set_shadow_type
173                 (GTK_SCROLLED_WINDOW (scrolledwin_format), GTK_SHADOW_IN);
174
175         text_format = gtk_text_view_new ();
176         if (prefs_common.textfont) {
177                 PangoFontDescription *font_desc;
178
179                 font_desc = pango_font_description_from_string
180                                                 (prefs_common.textfont);
181                 if (font_desc) {
182                         gtk_widget_modify_font(text_format, font_desc);
183                         pango_font_description_free(font_desc);
184                 }
185         }
186         gtk_widget_show(text_format);
187         gtk_container_add(GTK_CONTAINER(scrolledwin_format), text_format);
188         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_format), TRUE);
189         gtk_widget_set_size_request(text_format, -1, 100);
190
191         if (add_info_button)
192                 quotefmt_add_info_button(parent_window, vbox_format);
193
194         if (checkbtn_compose_with_format)
195                 *checkbtn_compose_with_format = checkbtn_use_format;
196         *edit_subject_format = entry_subject;
197         *edit_body_format = text_format;
198 }
199
200 void quotefmt_create_reply_fmt_widgets(GtkWindow *parent_window,
201                                                 GtkWidget *parent_box,
202                                                 GtkWidget **checkbtn_reply_with_format,
203                                                 gchar *checkbtn_reply_text,
204                                                 GtkWidget **edit_reply_quotemark,
205                                                 GtkWidget **edit_reply_format,
206                                                 gboolean add_info_button)
207 {
208         GtkWidget *checkbtn_use_format = NULL;
209         GtkWidget *frame_quote;
210         GtkWidget *vbox_quote;
211         GtkWidget *hbox1;
212         GtkWidget *hbox2;
213         GtkWidget *label_quotemark;
214         GtkWidget *entry_quotemark;
215         GtkWidget *scrolledwin_quotefmt;
216         GtkWidget *text_quotefmt;
217
218         if (add_info_button)
219                 g_return_if_fail(parent_window != NULL);
220         g_return_if_fail(parent_box != NULL);
221         if (checkbtn_reply_with_format) {
222                 g_return_if_fail(checkbtn_reply_with_format != NULL);
223                 g_return_if_fail(checkbtn_reply_text != 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, checkbtn_reply_text);
230
231         PACK_FRAME (parent_box, frame_quote, _("Reply format"));
232
233         if (checkbtn_reply_with_format)
234                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, frame_quote);
235
236         vbox_quote = gtk_vbox_new (FALSE, VSPACING_NARROW);
237         gtk_widget_show (vbox_quote);
238         gtk_container_add (GTK_CONTAINER (frame_quote), vbox_quote);
239         gtk_container_set_border_width (GTK_CONTAINER (vbox_quote), 8);
240
241         hbox1 = gtk_hbox_new (FALSE, 32);
242         gtk_widget_show (hbox1);
243         gtk_box_pack_start (GTK_BOX (vbox_quote), hbox1, FALSE, FALSE, 0);
244
245         hbox2 = gtk_hbox_new (FALSE, 8);
246         gtk_widget_show (hbox2);
247         gtk_box_pack_start (GTK_BOX (hbox1), hbox2, FALSE, FALSE, 0);
248
249         label_quotemark = gtk_label_new (_("Quotation mark"));
250         gtk_widget_show (label_quotemark);
251         gtk_box_pack_start (GTK_BOX (hbox2), label_quotemark, FALSE, FALSE, 0);
252
253         entry_quotemark = gtk_entry_new ();
254         gtk_widget_show (entry_quotemark);
255         gtk_box_pack_start (GTK_BOX (hbox2), entry_quotemark, FALSE, FALSE, 0);
256         gtk_widget_set_size_request (entry_quotemark, 64, -1);
257
258         scrolledwin_quotefmt = gtk_scrolled_window_new (NULL, NULL);
259         gtk_widget_show (scrolledwin_quotefmt);
260         gtk_box_pack_start (GTK_BOX (vbox_quote), scrolledwin_quotefmt,
261                             TRUE, TRUE, 0);
262         gtk_scrolled_window_set_policy
263                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt),
264                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
265         gtk_scrolled_window_set_shadow_type
266                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt), GTK_SHADOW_IN);
267
268         text_quotefmt = gtk_text_view_new ();
269         if (prefs_common.textfont) {
270                 PangoFontDescription *font_desc;
271
272                 font_desc = pango_font_description_from_string
273                                                 (prefs_common.textfont);
274                 if (font_desc) {
275                         gtk_widget_modify_font(text_quotefmt, font_desc);
276                         pango_font_description_free(font_desc);
277                 }
278         }
279         gtk_widget_show(text_quotefmt);
280         gtk_container_add(GTK_CONTAINER(scrolledwin_quotefmt), text_quotefmt);
281         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_quotefmt), TRUE);
282         gtk_widget_set_size_request(text_quotefmt, -1, 100);
283
284         if (add_info_button)
285                 quotefmt_add_info_button(parent_window, vbox_quote);
286
287         if (checkbtn_reply_with_format)
288                 *checkbtn_reply_with_format = checkbtn_use_format;
289         *edit_reply_quotemark = entry_quotemark;
290         *edit_reply_format = text_quotefmt;
291 }
292
293 void quotefmt_create_forward_fmt_widgets(GtkWindow *parent_window,
294                                                 GtkWidget *parent_box,
295                                                 GtkWidget **checkbtn_forward_with_format,
296                                                 gchar *checkbtn_forward_text,
297                                                 GtkWidget **edit_fw_quotemark,
298                                                 GtkWidget **edit_fw_format,
299                                                 gboolean add_info_button)
300 {
301         GtkWidget *checkbtn_use_format = NULL;
302         GtkWidget *frame_quote;
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                 g_return_if_fail(checkbtn_forward_text != NULL);
317         }
318         g_return_if_fail(edit_fw_quotemark != NULL);
319         g_return_if_fail(edit_fw_format != NULL);
320
321         if (checkbtn_forward_with_format)
322                 PACK_CHECK_BUTTON (parent_box, checkbtn_use_format, checkbtn_forward_text);
323
324         PACK_FRAME (parent_box, frame_quote, _("Forward format"));
325
326         if (checkbtn_forward_with_format)
327                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, frame_quote);
328
329         vbox_quote = gtk_vbox_new (FALSE, VSPACING_NARROW);
330         gtk_widget_show (vbox_quote);
331         gtk_container_add (GTK_CONTAINER (frame_quote), vbox_quote);
332         gtk_container_set_border_width (GTK_CONTAINER (vbox_quote), 8);
333
334         hbox1 = gtk_hbox_new (FALSE, 32);
335         gtk_widget_show (hbox1);
336         gtk_box_pack_start (GTK_BOX (vbox_quote), hbox1, FALSE, FALSE, 0);
337
338         hbox2 = gtk_hbox_new (FALSE, 8);
339         gtk_widget_show (hbox2);
340         gtk_box_pack_start (GTK_BOX (hbox1), hbox2, FALSE, FALSE, 0);
341
342         label_quotemark = gtk_label_new (_("Quotation mark"));
343         gtk_widget_show (label_quotemark);
344         gtk_box_pack_start (GTK_BOX (hbox2), label_quotemark, FALSE, FALSE, 0);
345
346         entry_fw_quotemark = gtk_entry_new ();
347         gtk_widget_show (entry_fw_quotemark);
348         gtk_box_pack_start (GTK_BOX (hbox2), entry_fw_quotemark,
349                             FALSE, FALSE, 0);
350         gtk_widget_set_size_request (entry_fw_quotemark, 64, -1);
351
352         scrolledwin_quotefmt = gtk_scrolled_window_new (NULL, NULL);
353         gtk_widget_show (scrolledwin_quotefmt);
354         gtk_box_pack_start (GTK_BOX (vbox_quote), scrolledwin_quotefmt,
355                             TRUE, TRUE, 0);
356         gtk_scrolled_window_set_policy
357                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt),
358                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
359         gtk_scrolled_window_set_shadow_type
360                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt), GTK_SHADOW_IN);
361
362         text_fw_quotefmt = gtk_text_view_new ();
363         if (prefs_common.textfont) {
364                 PangoFontDescription *font_desc;
365
366                 font_desc = pango_font_description_from_string
367                                                 (prefs_common.textfont);
368                 if (font_desc) {
369                         gtk_widget_modify_font(text_fw_quotefmt, font_desc);
370                         pango_font_description_free(font_desc);
371                 }
372         }
373         gtk_widget_show(text_fw_quotefmt);
374         gtk_container_add(GTK_CONTAINER(scrolledwin_quotefmt),
375                           text_fw_quotefmt);
376         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_fw_quotefmt), TRUE);
377         gtk_widget_set_size_request (text_fw_quotefmt, -1, 100);
378
379         if (add_info_button)
380                 quotefmt_add_info_button(parent_window, vbox_quote);
381
382         if (checkbtn_forward_with_format)
383                 *checkbtn_forward_with_format = checkbtn_use_format;
384         *edit_fw_quotemark = entry_fw_quotemark;
385         *edit_fw_format = text_fw_quotefmt;
386 }
387
388 void quotefmt_add_info_button(GtkWindow *parent_window, GtkWidget *parent_box)
389 {
390         GtkWidget *hbox_formatdesc;
391         GtkWidget *btn_formatdesc;
392
393         hbox_formatdesc = gtk_hbox_new (FALSE, 32);
394         gtk_widget_show (hbox_formatdesc);
395         gtk_box_pack_start (GTK_BOX (parent_box), hbox_formatdesc, FALSE, FALSE, 0);
396
397 #if GTK_CHECK_VERSION(2, 8, 0)
398         btn_formatdesc = gtk_button_new_from_stock(GTK_STOCK_INFO);
399 #else
400         btn_formatdesc =
401                 gtk_button_new_with_label (_("Description of symbols..."));
402 #endif
403         gtk_widget_show (btn_formatdesc);
404         gtk_box_pack_start (GTK_BOX (hbox_formatdesc), btn_formatdesc, FALSE, FALSE, 0);
405         g_signal_connect(G_OBJECT(btn_formatdesc), "clicked",
406                          G_CALLBACK(quote_fmt_quote_description), GTK_WIDGET(parent_window));
407 }
408
409
410 void quotefmt_check_new_msg_formats(gboolean use_format,
411                                                                         gchar *subject_fmt,
412                                                                         gchar *body_fmt)
413 {
414         if (use_format) {
415                 gint line;
416
417                 if (!prefs_template_string_is_valid(subject_fmt, NULL))
418                         alertpanel_error(_("New message subject format error."));
419
420                 if (!prefs_template_string_is_valid(body_fmt, &line)) {
421                         alertpanel_error(_("New message body format error at line %d."), line);
422                 }
423         }
424 }
425
426 void quotefmt_check_reply_formats(gboolean use_format,
427                                                                         gchar *quotation_mark,
428                                                                         gchar *body_fmt)
429 {
430         if (use_format) {
431                 gint line;
432
433                 if (!prefs_template_string_is_valid(quotation_mark, NULL))
434                         alertpanel_error(_("Message reply quotation mark format error."));
435
436                 if (!prefs_template_string_is_valid(body_fmt, &line)) {
437                         alertpanel_error(_("Message reply format error at line %d."), line);
438                 }
439         }
440 }
441
442 void quotefmt_check_forward_formats(gboolean use_format,
443                                                                         gchar *quotation_mark,
444                                                                         gchar *body_fmt)
445 {
446         if (use_format) {
447                 gint line;
448
449                 if (!prefs_template_string_is_valid(quotation_mark, NULL))
450                         alertpanel_error(_("Message forward quotation mark format error."));
451
452                 if (!prefs_template_string_is_valid(body_fmt, &line)) {
453                         alertpanel_error(_("Message forward format error at line %d."), line);
454                 }
455         }
456 }