2007-10-17 [wwp] 3.0.2cvs79
[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         "|attach{<span style=\"oblique\">sub_expr</span>}\n(|a{<span style=\"oblique\">sub_expr</span>})",              N_("attach file:\n<span style=\"oblique\">sub_expr</span> is evaluated as the path of the file to attach"), /* attach file */
93         "",                                     NULL,
94         N_("<span weight=\"bold\">definition of terms:</span>"),        NULL,
95         "<span style=\"oblique\">expr</span>\n",                        N_("text that can contain any of the symbols or\ncommands above"),
96         "<span style=\"oblique\">sub_expr</span>\n",            N_("text that can contain any of the symbols (no\ncommands) above"),
97         "<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"),
98         NULL,NULL
99 };
100
101 static DescriptionWindow quote_desc_win = { 
102         NULL,
103         NULL,
104         2,
105         N_("Description of symbols"),
106         N_("The following symbols and commands can be used:"),
107         quote_desc_strings
108 };
109
110
111 void quote_fmt_quote_description(GtkWidget *widget, GtkWidget *pref_window)
112 {
113         quote_desc_win.parent = pref_window;
114         description_window_create(&quote_desc_win);
115 }
116
117 void quotefmt_create_new_msg_fmt_widgets(GtkWindow *parent_window,
118                                                 GtkWidget *parent_box,
119                                                 GtkWidget **checkbtn_compose_with_format,
120                                                 GtkWidget **edit_subject_format,
121                                                 GtkWidget **edit_body_format,
122                                                 gboolean add_info_button)
123 {
124         GtkWidget *checkbtn_use_format = NULL;
125         GtkWidget *vbox_format;
126         GtkWidget *hbox_format;
127         GtkWidget *label_subject;
128         GtkWidget *entry_subject;
129         GtkWidget *scrolledwin_format;
130         GtkWidget *text_format;
131
132         if (add_info_button)
133                 g_return_if_fail(parent_window != NULL);
134         g_return_if_fail(parent_box != NULL);
135         if (checkbtn_compose_with_format)
136                 g_return_if_fail(checkbtn_compose_with_format != NULL);
137
138         g_return_if_fail(edit_subject_format != NULL);
139         g_return_if_fail(edit_body_format != NULL);
140
141         if (checkbtn_compose_with_format)
142                 PACK_CHECK_BUTTON (parent_box, checkbtn_use_format, 
143                                    _("Use template when composing new messages"));
144
145         vbox_format = gtk_vbox_new (FALSE, 4);
146         gtk_widget_show(vbox_format);
147         gtk_container_add(GTK_CONTAINER (parent_box), vbox_format);
148         gtk_container_set_border_width (GTK_CONTAINER (vbox_format), 8);
149
150         hbox_format = gtk_hbox_new (FALSE, 8);
151         gtk_widget_show (hbox_format);
152         gtk_box_pack_start (GTK_BOX (vbox_format), hbox_format, FALSE, FALSE, 0);
153
154         label_subject = gtk_label_new (_("Subject"));
155         gtk_widget_show (label_subject);
156         gtk_box_pack_start (GTK_BOX (hbox_format), label_subject, FALSE, FALSE, 0);
157
158         entry_subject = gtk_entry_new ();
159         gtk_widget_show (entry_subject);
160         gtk_box_pack_start (GTK_BOX (hbox_format), entry_subject, TRUE, TRUE, 0);
161         gtk_widget_set_size_request (entry_subject, 100, -1);
162
163         scrolledwin_format = gtk_scrolled_window_new (NULL, NULL);
164         gtk_widget_show (scrolledwin_format);
165         gtk_box_pack_start (GTK_BOX (vbox_format), scrolledwin_format,
166                             TRUE, TRUE, 0);
167         gtk_scrolled_window_set_policy
168                 (GTK_SCROLLED_WINDOW (scrolledwin_format),
169                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
170         gtk_scrolled_window_set_shadow_type
171                 (GTK_SCROLLED_WINDOW (scrolledwin_format), GTK_SHADOW_IN);
172
173         text_format = gtk_text_view_new ();
174         if (prefs_common.textfont) {
175                 PangoFontDescription *font_desc;
176
177                 font_desc = pango_font_description_from_string
178                                                 (prefs_common.textfont);
179                 if (font_desc) {
180                         gtk_widget_modify_font(text_format, font_desc);
181                         pango_font_description_free(font_desc);
182                 }
183         }
184         gtk_widget_show(text_format);
185         gtk_container_add(GTK_CONTAINER(scrolledwin_format), text_format);
186         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_format), TRUE);
187         gtk_widget_set_size_request(text_format, -1, 100);
188
189         if (checkbtn_compose_with_format) {
190                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, label_subject);
191                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, entry_subject);
192                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, text_format);
193         }
194
195         if (add_info_button)
196                 quotefmt_add_info_button(parent_window, vbox_format);
197
198         if (checkbtn_compose_with_format)
199                 *checkbtn_compose_with_format = checkbtn_use_format;
200         *edit_subject_format = entry_subject;
201         *edit_body_format = text_format;
202 }
203
204 void quotefmt_create_reply_fmt_widgets(GtkWindow *parent_window,
205                                                 GtkWidget *parent_box,
206                                                 GtkWidget **checkbtn_reply_with_format,
207                                                 GtkWidget **edit_reply_quotemark,
208                                                 GtkWidget **edit_reply_format,
209                                                 gboolean add_info_button)
210 {
211         GtkWidget *checkbtn_use_format = NULL;
212         GtkWidget *vbox_quote;
213         GtkWidget *hbox1;
214         GtkWidget *hbox2;
215         GtkWidget *label_quotemark;
216         GtkWidget *entry_quotemark;
217         GtkWidget *scrolledwin_quotefmt;
218         GtkWidget *text_quotefmt;
219
220         if (add_info_button)
221                 g_return_if_fail(parent_window != NULL);
222         g_return_if_fail(parent_box != NULL);
223         if (checkbtn_reply_with_format)
224                 g_return_if_fail(checkbtn_reply_with_format != NULL);
225
226         g_return_if_fail(edit_reply_quotemark != NULL);
227         g_return_if_fail(edit_reply_format != NULL);
228
229         if (checkbtn_reply_with_format)
230                 PACK_CHECK_BUTTON (parent_box, checkbtn_use_format,
231                                    _("Use template when replying to messages"));
232
233         vbox_quote = gtk_vbox_new (FALSE, 4);
234         gtk_widget_show(vbox_quote);
235         gtk_container_add(GTK_CONTAINER (parent_box), vbox_quote);
236         gtk_container_set_border_width (GTK_CONTAINER (vbox_quote), 8);
237
238         hbox1 = gtk_hbox_new (FALSE, 32);
239         gtk_widget_show (hbox1);
240         gtk_box_pack_start (GTK_BOX (vbox_quote), hbox1, FALSE, FALSE, 0);
241
242         hbox2 = gtk_hbox_new (FALSE, 8);
243         gtk_widget_show (hbox2);
244         gtk_box_pack_start (GTK_BOX (hbox1), hbox2, FALSE, FALSE, 0);
245
246         label_quotemark = gtk_label_new (_("Quotation mark"));
247         gtk_widget_show (label_quotemark);
248         gtk_box_pack_start (GTK_BOX (hbox2), label_quotemark, FALSE, FALSE, 0);
249
250         entry_quotemark = gtk_entry_new ();
251         gtk_widget_show (entry_quotemark);
252         gtk_box_pack_start (GTK_BOX (hbox2), entry_quotemark, FALSE, FALSE, 0);
253         gtk_widget_set_size_request (entry_quotemark, 64, -1);
254
255         scrolledwin_quotefmt = gtk_scrolled_window_new (NULL, NULL);
256         gtk_widget_show (scrolledwin_quotefmt);
257         gtk_box_pack_start (GTK_BOX (vbox_quote), scrolledwin_quotefmt,
258                             TRUE, TRUE, 0);
259         gtk_scrolled_window_set_policy
260                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt),
261                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
262         gtk_scrolled_window_set_shadow_type
263                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt), GTK_SHADOW_IN);
264
265         text_quotefmt = gtk_text_view_new ();
266         if (prefs_common.textfont) {
267                 PangoFontDescription *font_desc;
268
269                 font_desc = pango_font_description_from_string
270                                                 (prefs_common.textfont);
271                 if (font_desc) {
272                         gtk_widget_modify_font(text_quotefmt, font_desc);
273                         pango_font_description_free(font_desc);
274                 }
275         }
276         gtk_widget_show(text_quotefmt);
277         gtk_container_add(GTK_CONTAINER(scrolledwin_quotefmt), text_quotefmt);
278         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_quotefmt), TRUE);
279         gtk_widget_set_size_request(text_quotefmt, -1, 100);
280
281         if (checkbtn_reply_with_format) {
282                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, label_quotemark);
283                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, entry_quotemark);
284                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, text_quotefmt);
285         }
286
287         if (add_info_button)
288                 quotefmt_add_info_button(parent_window, vbox_quote);
289
290         if (checkbtn_reply_with_format)
291                 *checkbtn_reply_with_format = checkbtn_use_format;
292         *edit_reply_quotemark = entry_quotemark;
293         *edit_reply_format = text_quotefmt;
294 }
295
296 void quotefmt_create_forward_fmt_widgets(GtkWindow *parent_window,
297                                                 GtkWidget *parent_box,
298                                                 GtkWidget **checkbtn_forward_with_format,
299                                                 GtkWidget **edit_fw_quotemark,
300                                                 GtkWidget **edit_fw_format,
301                                                 gboolean add_info_button)
302 {
303         GtkWidget *checkbtn_use_format = NULL;
304         GtkWidget *vbox_quote;
305         GtkWidget *hbox1;
306         GtkWidget *hbox2;
307         GtkWidget *label_quotemark;
308         GtkWidget *entry_fw_quotemark;
309         GtkWidget *scrolledwin_quotefmt;
310         GtkWidget *text_fw_quotefmt;
311
312         if (add_info_button)
313                 g_return_if_fail(parent_window != NULL);
314         g_return_if_fail(parent_box != NULL);
315         if (checkbtn_forward_with_format) {
316                 g_return_if_fail(checkbtn_forward_with_format != 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,
323                                    _("Use template when forwarding messages"));
324
325         vbox_quote = gtk_vbox_new (FALSE, 4);
326         gtk_widget_show(vbox_quote);
327         gtk_container_add(GTK_CONTAINER (parent_box), vbox_quote);
328         gtk_container_set_border_width (GTK_CONTAINER (vbox_quote), 8);
329
330         hbox1 = gtk_hbox_new (FALSE, 32);
331         gtk_widget_show (hbox1);
332         gtk_box_pack_start (GTK_BOX (vbox_quote), hbox1, FALSE, FALSE, 0);
333
334         hbox2 = gtk_hbox_new (FALSE, 8);
335         gtk_widget_show (hbox2);
336         gtk_box_pack_start (GTK_BOX (hbox1), hbox2, FALSE, FALSE, 0);
337
338         label_quotemark = gtk_label_new (_("Quotation mark"));
339         gtk_widget_show (label_quotemark);
340         gtk_box_pack_start (GTK_BOX (hbox2), label_quotemark, FALSE, FALSE, 0);
341
342         entry_fw_quotemark = gtk_entry_new ();
343         gtk_widget_show (entry_fw_quotemark);
344         gtk_box_pack_start (GTK_BOX (hbox2), entry_fw_quotemark,
345                             FALSE, FALSE, 0);
346         gtk_widget_set_size_request (entry_fw_quotemark, 64, -1);
347
348         scrolledwin_quotefmt = gtk_scrolled_window_new (NULL, NULL);
349         gtk_widget_show (scrolledwin_quotefmt);
350         gtk_box_pack_start (GTK_BOX (vbox_quote), scrolledwin_quotefmt,
351                             TRUE, TRUE, 0);
352         gtk_scrolled_window_set_policy
353                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt),
354                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
355         gtk_scrolled_window_set_shadow_type
356                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt), GTK_SHADOW_IN);
357
358         text_fw_quotefmt = gtk_text_view_new ();
359         if (prefs_common.textfont) {
360                 PangoFontDescription *font_desc;
361
362                 font_desc = pango_font_description_from_string
363                                                 (prefs_common.textfont);
364                 if (font_desc) {
365                         gtk_widget_modify_font(text_fw_quotefmt, font_desc);
366                         pango_font_description_free(font_desc);
367                 }
368         }
369         gtk_widget_show(text_fw_quotefmt);
370         gtk_container_add(GTK_CONTAINER(scrolledwin_quotefmt),
371                           text_fw_quotefmt);
372         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_fw_quotefmt), TRUE);
373         gtk_widget_set_size_request (text_fw_quotefmt, -1, 100);
374
375         if (checkbtn_forward_with_format) {
376                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, label_quotemark);
377                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, entry_fw_quotemark);
378                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, text_fw_quotefmt);
379         }
380
381         if (add_info_button)
382                 quotefmt_add_info_button(parent_window, vbox_quote);
383
384         if (checkbtn_forward_with_format)
385                 *checkbtn_forward_with_format = checkbtn_use_format;
386         *edit_fw_quotemark = entry_fw_quotemark;
387         *edit_fw_format = text_fw_quotefmt;
388 }
389
390 void quotefmt_add_info_button(GtkWindow *parent_window, GtkWidget *parent_box)
391 {
392         GtkWidget *hbox_formatdesc;
393         GtkWidget *btn_formatdesc;
394
395         hbox_formatdesc = gtk_hbox_new (FALSE, 32);
396         gtk_widget_show (hbox_formatdesc);
397         gtk_box_pack_start (GTK_BOX (parent_box), hbox_formatdesc, FALSE, FALSE,
398                                 VBOX_BORDER);
399
400 #if GTK_CHECK_VERSION(2, 8, 0)
401         btn_formatdesc = gtk_button_new_from_stock(GTK_STOCK_INFO);
402 #else
403         btn_formatdesc =
404                 gtk_button_new_with_label (_("Description of symbols..."));
405 #endif
406         gtk_widget_show (btn_formatdesc);
407         gtk_box_pack_start (GTK_BOX (hbox_formatdesc), btn_formatdesc, FALSE, FALSE, 0);
408         g_signal_connect(G_OBJECT(btn_formatdesc), "clicked",
409                          G_CALLBACK(quote_fmt_quote_description), GTK_WIDGET(parent_window));
410 }
411
412
413 void quotefmt_check_new_msg_formats(gboolean use_format,
414                                                                         gchar *subject_fmt,
415                                                                         gchar *body_fmt)
416 {
417         if (use_format) {
418                 gint line;
419
420                 if (!prefs_template_string_is_valid(subject_fmt, NULL))
421                         alertpanel_error(_("New message subject format error."));
422
423                 if (!prefs_template_string_is_valid(body_fmt, &line)) {
424                         alertpanel_error(_("New message body format error at line %d."), line);
425                 }
426         }
427 }
428
429 void quotefmt_check_reply_formats(gboolean use_format,
430                                                                         gchar *quotation_mark,
431                                                                         gchar *body_fmt)
432 {
433         if (use_format) {
434                 gint line;
435
436                 if (!prefs_template_string_is_valid(quotation_mark, NULL))
437                         alertpanel_error(_("Message reply quotation mark format error."));
438
439                 if (!prefs_template_string_is_valid(body_fmt, &line)) {
440                         alertpanel_error(_("Message reply format error at line %d."), line);
441                 }
442         }
443 }
444
445 void quotefmt_check_forward_formats(gboolean use_format,
446                                                                         gchar *quotation_mark,
447                                                                         gchar *body_fmt)
448 {
449         if (use_format) {
450                 gint line;
451
452                 if (!prefs_template_string_is_valid(quotation_mark, NULL))
453                         alertpanel_error(_("Message forward quotation mark format error."));
454
455                 if (!prefs_template_string_is_valid(body_fmt, &line)) {
456                         alertpanel_error(_("Message forward format error at line %d."), line);
457                 }
458         }
459 }