2007-05-30 [wwp] 2.9.2cvs19
[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 2 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, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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         "%dict (%T)",                           N_("current dictionary"), /* current dictionary */
66         "%cursor (%X)",                         N_("cursor position"), /* X marks the cursor spot */
67         "%account_fullname (%af)",      N_("account property: your name"), /* full name in compose account */
68         "%account_email (%ae)",         N_("account property: your email address"), /* mail address in compose account */
69         "%account_name (%an)",          N_("account property: account name"), /* compose account name itself */
70         "%account_org (%ao)",           N_("account property: organization"), /* organization in compose account */
71         "%account_dict (%aT)",          N_("account property: default dictionary"), /* main dict (if enabled) in account */
72         "%addrbook_cc (%ABc)",          N_("address book <span style=\"oblique\">completion</span>: Cc"), /* completion of 'Cc' from address book */
73         "%addrbook_from (%ABf)",        N_("address book <span style=\"oblique\">completion</span>: From"), /* completion of 'From' from address book */
74         "%addrbook_to (%ABt)",          N_("address book <span style=\"oblique\">completion</span>: To"), /* completion of 'To' from address book */
75         "\\%",                          N_("literal %"),
76         "\\\\",                         N_("literal backslash"),
77         "\\?",                          N_("literal question mark"),
78         "\\!",                          N_("literal exclamation mark"),
79         "\\|",                          N_("literal pipe"),
80         "\\{",                          N_("literal opening curly brace"),
81         "\\}",                          N_("literal closing curly brace"),
82         "\\t",                          N_("tab"),
83         "\\n",                          N_("new line"),
84         "",                                     NULL,
85         N_("<span weight=\"bold\">commands:</span>"),           NULL,
86         "?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)"),
87         "!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)"),
88         "|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 */
89         "|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 */
90         "|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 */
91         "",                                     NULL,
92         N_("<span weight=\"bold\">definition of terms:</span>"),        NULL,
93         "<span style=\"oblique\">expr</span>\n",                        N_("text that can contain any of the symbols or\ncommands above"),
94         "<span style=\"oblique\">sub_expr</span>\n",            N_("text that can contain any of the symbols (no\ncommands) above"),
95         "<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"),
96         NULL,NULL
97 };
98
99 static DescriptionWindow quote_desc_win = { 
100         NULL,
101         NULL,
102         2,
103         N_("Description of symbols"),
104         N_("The following symbols and commands can be used:"),
105         quote_desc_strings
106 };
107
108
109 void quote_fmt_quote_description(GtkWidget *widget, GtkWidget *pref_window)
110 {
111         quote_desc_win.parent = pref_window;
112         description_window_create(&quote_desc_win);
113 }
114
115 void quotefmt_create_new_msg_fmt_widgets(GtkWindow *parent_window,
116                                                 GtkWidget *parent_box,
117                                                 GtkWidget **checkbtn_compose_with_format,
118                                                 gchar *checkbtn_compose_text,
119                                                 GtkWidget **edit_subject_format,
120                                                 GtkWidget **edit_body_format,
121                                                 gboolean add_info_button)
122 {
123         GtkWidget *checkbtn_use_format = NULL;
124         GtkWidget *frame_format;
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                 g_return_if_fail(checkbtn_compose_text != NULL);
138         }
139         g_return_if_fail(edit_subject_format != NULL);
140         g_return_if_fail(edit_body_format != NULL);
141
142         if (checkbtn_compose_with_format)
143                 PACK_CHECK_BUTTON (parent_box, checkbtn_use_format, 
144                                    _("Use format when composing new messages"));
145
146         vbox_format = gtkut_get_options_frame(parent_box, &frame_format, checkbtn_compose_text);
147
148         if (checkbtn_compose_with_format)
149                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, frame_format);
150
151         hbox_format = gtk_hbox_new (FALSE, 8);
152         gtk_widget_show (hbox_format);
153         gtk_box_pack_start (GTK_BOX (vbox_format), hbox_format, FALSE, FALSE, 0);
154
155         label_subject = gtk_label_new (_("Subject"));
156         gtk_widget_show (label_subject);
157         gtk_box_pack_start (GTK_BOX (hbox_format), label_subject, FALSE, FALSE, 0);
158
159         entry_subject = gtk_entry_new ();
160         gtk_widget_show (entry_subject);
161         gtk_box_pack_start (GTK_BOX (hbox_format), entry_subject, TRUE, TRUE, 0);
162         gtk_widget_set_size_request (entry_subject, 100, -1);
163
164         scrolledwin_format = gtk_scrolled_window_new (NULL, NULL);
165         gtk_widget_show (scrolledwin_format);
166         gtk_box_pack_start (GTK_BOX (vbox_format), scrolledwin_format,
167                             TRUE, TRUE, 0);
168         gtk_scrolled_window_set_policy
169                 (GTK_SCROLLED_WINDOW (scrolledwin_format),
170                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
171         gtk_scrolled_window_set_shadow_type
172                 (GTK_SCROLLED_WINDOW (scrolledwin_format), GTK_SHADOW_IN);
173
174         text_format = gtk_text_view_new ();
175         if (prefs_common.textfont) {
176                 PangoFontDescription *font_desc;
177
178                 font_desc = pango_font_description_from_string
179                                                 (prefs_common.textfont);
180                 if (font_desc) {
181                         gtk_widget_modify_font(text_format, font_desc);
182                         pango_font_description_free(font_desc);
183                 }
184         }
185         gtk_widget_show(text_format);
186         gtk_container_add(GTK_CONTAINER(scrolledwin_format), text_format);
187         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_format), TRUE);
188         gtk_widget_set_size_request(text_format, -1, 100);
189
190         if (add_info_button)
191                 quotefmt_add_info_button(parent_window, vbox_format);
192
193         if (checkbtn_compose_with_format)
194                 *checkbtn_compose_with_format = checkbtn_use_format;
195         *edit_subject_format = entry_subject;
196         *edit_body_format = text_format;
197 }
198
199 void quotefmt_create_reply_fmt_widgets(GtkWindow *parent_window,
200                                                 GtkWidget *parent_box,
201                                                 GtkWidget **checkbtn_reply_with_format,
202                                                 gchar *checkbtn_reply_text,
203                                                 GtkWidget **edit_reply_quotemark,
204                                                 GtkWidget **edit_reply_format,
205                                                 gboolean add_info_button)
206 {
207         GtkWidget *checkbtn_use_format = NULL;
208         GtkWidget *frame_quote;
209         GtkWidget *vbox_quote;
210         GtkWidget *hbox1;
211         GtkWidget *hbox2;
212         GtkWidget *label_quotemark;
213         GtkWidget *entry_quotemark;
214         GtkWidget *scrolledwin_quotefmt;
215         GtkWidget *text_quotefmt;
216
217         if (add_info_button)
218                 g_return_if_fail(parent_window != NULL);
219         g_return_if_fail(parent_box != NULL);
220         if (checkbtn_reply_with_format) {
221                 g_return_if_fail(checkbtn_reply_with_format != NULL);
222                 g_return_if_fail(checkbtn_reply_text != NULL);
223         }
224         g_return_if_fail(edit_reply_quotemark != NULL);
225         g_return_if_fail(edit_reply_format != NULL);
226
227         if (checkbtn_reply_with_format)
228                 PACK_CHECK_BUTTON (parent_box, checkbtn_use_format, checkbtn_reply_text);
229
230         PACK_FRAME (parent_box, frame_quote, _("Reply format"));
231
232         if (checkbtn_reply_with_format)
233                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, frame_quote);
234
235         vbox_quote = gtk_vbox_new (FALSE, VSPACING_NARROW);
236         gtk_widget_show (vbox_quote);
237         gtk_container_add (GTK_CONTAINER (frame_quote), vbox_quote);
238         gtk_container_set_border_width (GTK_CONTAINER (vbox_quote), 8);
239
240         hbox1 = gtk_hbox_new (FALSE, 32);
241         gtk_widget_show (hbox1);
242         gtk_box_pack_start (GTK_BOX (vbox_quote), hbox1, FALSE, FALSE, 0);
243
244         hbox2 = gtk_hbox_new (FALSE, 8);
245         gtk_widget_show (hbox2);
246         gtk_box_pack_start (GTK_BOX (hbox1), hbox2, FALSE, FALSE, 0);
247
248         label_quotemark = gtk_label_new (_("Quotation mark"));
249         gtk_widget_show (label_quotemark);
250         gtk_box_pack_start (GTK_BOX (hbox2), label_quotemark, FALSE, FALSE, 0);
251
252         entry_quotemark = gtk_entry_new ();
253         gtk_widget_show (entry_quotemark);
254         gtk_box_pack_start (GTK_BOX (hbox2), entry_quotemark, FALSE, FALSE, 0);
255         gtk_widget_set_size_request (entry_quotemark, 64, -1);
256
257         scrolledwin_quotefmt = gtk_scrolled_window_new (NULL, NULL);
258         gtk_widget_show (scrolledwin_quotefmt);
259         gtk_box_pack_start (GTK_BOX (vbox_quote), scrolledwin_quotefmt,
260                             TRUE, TRUE, 0);
261         gtk_scrolled_window_set_policy
262                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt),
263                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
264         gtk_scrolled_window_set_shadow_type
265                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt), GTK_SHADOW_IN);
266
267         text_quotefmt = gtk_text_view_new ();
268         if (prefs_common.textfont) {
269                 PangoFontDescription *font_desc;
270
271                 font_desc = pango_font_description_from_string
272                                                 (prefs_common.textfont);
273                 if (font_desc) {
274                         gtk_widget_modify_font(text_quotefmt, font_desc);
275                         pango_font_description_free(font_desc);
276                 }
277         }
278         gtk_widget_show(text_quotefmt);
279         gtk_container_add(GTK_CONTAINER(scrolledwin_quotefmt), text_quotefmt);
280         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_quotefmt), TRUE);
281         gtk_widget_set_size_request(text_quotefmt, -1, 100);
282
283         if (add_info_button)
284                 quotefmt_add_info_button(parent_window, vbox_quote);
285
286         if (checkbtn_reply_with_format)
287                 *checkbtn_reply_with_format = checkbtn_use_format;
288         *edit_reply_quotemark = entry_quotemark;
289         *edit_reply_format = text_quotefmt;
290 }
291
292 void quotefmt_create_forward_fmt_widgets(GtkWindow *parent_window,
293                                                 GtkWidget *parent_box,
294                                                 GtkWidget **checkbtn_forward_with_format,
295                                                 gchar *checkbtn_forward_text,
296                                                 GtkWidget **edit_fw_quotemark,
297                                                 GtkWidget **edit_fw_format,
298                                                 gboolean add_info_button)
299 {
300         GtkWidget *checkbtn_use_format = NULL;
301         GtkWidget *frame_quote;
302         GtkWidget *vbox_quote;
303         GtkWidget *hbox1;
304         GtkWidget *hbox2;
305         GtkWidget *label_quotemark;
306         GtkWidget *entry_fw_quotemark;
307         GtkWidget *scrolledwin_quotefmt;
308         GtkWidget *text_fw_quotefmt;
309
310         if (add_info_button)
311                 g_return_if_fail(parent_window != NULL);
312         g_return_if_fail(parent_box != NULL);
313         if (checkbtn_forward_with_format) {
314                 g_return_if_fail(checkbtn_forward_with_format != NULL);
315                 g_return_if_fail(checkbtn_forward_text != 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, checkbtn_forward_text);
322
323         PACK_FRAME (parent_box, frame_quote, _("Forward format"));
324
325         if (checkbtn_forward_with_format)
326                 SET_TOGGLE_SENSITIVITY(checkbtn_use_format, frame_quote);
327
328         vbox_quote = gtk_vbox_new (FALSE, VSPACING_NARROW);
329         gtk_widget_show (vbox_quote);
330         gtk_container_add (GTK_CONTAINER (frame_quote), vbox_quote);
331         gtk_container_set_border_width (GTK_CONTAINER (vbox_quote), 8);
332
333         hbox1 = gtk_hbox_new (FALSE, 32);
334         gtk_widget_show (hbox1);
335         gtk_box_pack_start (GTK_BOX (vbox_quote), hbox1, FALSE, FALSE, 0);
336
337         hbox2 = gtk_hbox_new (FALSE, 8);
338         gtk_widget_show (hbox2);
339         gtk_box_pack_start (GTK_BOX (hbox1), hbox2, FALSE, FALSE, 0);
340
341         label_quotemark = gtk_label_new (_("Quotation mark"));
342         gtk_widget_show (label_quotemark);
343         gtk_box_pack_start (GTK_BOX (hbox2), label_quotemark, FALSE, FALSE, 0);
344
345         entry_fw_quotemark = gtk_entry_new ();
346         gtk_widget_show (entry_fw_quotemark);
347         gtk_box_pack_start (GTK_BOX (hbox2), entry_fw_quotemark,
348                             FALSE, FALSE, 0);
349         gtk_widget_set_size_request (entry_fw_quotemark, 64, -1);
350
351         scrolledwin_quotefmt = gtk_scrolled_window_new (NULL, NULL);
352         gtk_widget_show (scrolledwin_quotefmt);
353         gtk_box_pack_start (GTK_BOX (vbox_quote), scrolledwin_quotefmt,
354                             TRUE, TRUE, 0);
355         gtk_scrolled_window_set_policy
356                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt),
357                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
358         gtk_scrolled_window_set_shadow_type
359                 (GTK_SCROLLED_WINDOW (scrolledwin_quotefmt), GTK_SHADOW_IN);
360
361         text_fw_quotefmt = gtk_text_view_new ();
362         if (prefs_common.textfont) {
363                 PangoFontDescription *font_desc;
364
365                 font_desc = pango_font_description_from_string
366                                                 (prefs_common.textfont);
367                 if (font_desc) {
368                         gtk_widget_modify_font(text_fw_quotefmt, font_desc);
369                         pango_font_description_free(font_desc);
370                 }
371         }
372         gtk_widget_show(text_fw_quotefmt);
373         gtk_container_add(GTK_CONTAINER(scrolledwin_quotefmt),
374                           text_fw_quotefmt);
375         gtk_text_view_set_editable (GTK_TEXT_VIEW (text_fw_quotefmt), TRUE);
376         gtk_widget_set_size_request (text_fw_quotefmt, -1, 100);
377
378         if (add_info_button)
379                 quotefmt_add_info_button(parent_window, vbox_quote);
380
381         if (checkbtn_forward_with_format)
382                 *checkbtn_forward_with_format = checkbtn_use_format;
383         *edit_fw_quotemark = entry_fw_quotemark;
384         *edit_fw_format = text_fw_quotefmt;
385 }
386
387 void quotefmt_add_info_button(GtkWindow *parent_window, GtkWidget *parent_box)
388 {
389         GtkWidget *hbox_formatdesc;
390         GtkWidget *btn_formatdesc;
391
392         hbox_formatdesc = gtk_hbox_new (FALSE, 32);
393         gtk_widget_show (hbox_formatdesc);
394         gtk_box_pack_start (GTK_BOX (parent_box), hbox_formatdesc, FALSE, FALSE, 0);
395
396 #if GTK_CHECK_VERSION(2, 8, 0)
397         btn_formatdesc = gtk_button_new_from_stock(GTK_STOCK_INFO);
398 #else
399         btn_formatdesc =
400                 gtk_button_new_with_label (_("Description of symbols..."));
401 #endif
402         gtk_widget_show (btn_formatdesc);
403         gtk_box_pack_start (GTK_BOX (hbox_formatdesc), btn_formatdesc, FALSE, FALSE, 0);
404         g_signal_connect(G_OBJECT(btn_formatdesc), "clicked",
405                          G_CALLBACK(quote_fmt_quote_description), GTK_WIDGET(parent_window));
406 }
407
408
409 void quotefmt_check_new_msg_formats(gboolean use_format,
410                                                                         gchar *subject_fmt,
411                                                                         gchar *body_fmt)
412 {
413         gint line;
414
415         if (use_format &&
416                         !prefs_template_string_is_valid(subject_fmt, NULL))
417                 alertpanel_error(_("New message subject format error."));
418         if (use_format &&
419                         !prefs_template_string_is_valid(body_fmt, &line)) {
420                 gchar *msg = g_strdup_printf(_("New message body format error at line %d."), line);
421                 alertpanel_error(msg);
422                 g_free(msg);
423         }
424 }
425
426 void quotefmt_check_reply_formats(gboolean use_format,
427                                                                         gchar *body_fmt)
428 {
429         gint line;
430
431         if (use_format &&
432                         !prefs_template_string_is_valid(body_fmt, &line)) {
433                 gchar *msg = g_strdup_printf(_("Message reply format error at line %d."), line);
434                 alertpanel_error(msg);
435                 g_free(msg);
436         }
437 }
438
439 void quotefmt_check_forward_formats(gboolean use_format,
440                                                                         gchar *body_fmt)
441 {
442         gint line;
443
444         if (use_format &&
445                         !prefs_template_string_is_valid(body_fmt, &line)) {
446                 gchar *msg = g_strdup_printf(_("Message forward format error at line %d."), line);
447                 alertpanel_error(msg);
448                 g_free(msg);
449         }
450 }