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