Statistics
| Revision:

root / src / prefs_template.c @ 1029

History | View | Annotate | Download (15.3 kB)

1
/*
2
 * Sylpheed templates subsystem 
3
 * Copyright (C) 2001 Alexander Barinov
4
 * Copyright (C) 2001-2005 Hiroyuki Yamamoto
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
 */
20
21
#include "defs.h"
22
23
#include <glib.h>
24
#include <glib/gi18n.h>
25
#include <gtk/gtk.h>
26
#include <gdk/gdkkeysyms.h>
27
#include <string.h>
28
#include <dirent.h>
29
#include <sys/stat.h>
30
31
#include "template.h"
32
#include "main.h"
33
#include "inc.h"
34
#include "utils.h"
35
#include "gtkutils.h"
36
#include "alertpanel.h"
37
#include "manage_window.h"
38
#include "prefs_common.h"
39
#include "prefs_common_dialog.h"
40
#include "compose.h"
41
#include "mainwindow.h"
42
#include "addr_compl.h"
43
#include "quote_fmt.h"
44
45
static struct Templates {
46
        GtkWidget *window;
47
        GtkWidget *clist_tmpls;
48
        GtkWidget *entry_name;
49
        GtkWidget *entry_to;
50
        GtkWidget *entry_cc;
51
        GtkWidget *entry_subject;
52
        GtkWidget *text_value;
53
        GtkWidget *confirm_area;
54
        GtkWidget *ok_btn;
55
        GtkWidget *cancel_btn;
56
} templates;
57
58
/* widget creating functions */
59
static void prefs_template_window_create        (void);
60
static void prefs_template_window_setup                (void);
61
static void prefs_template_clear                (void);
62
63
static GSList *prefs_template_get_list                (void);
64
65
/* callbacks */
66
static gint prefs_template_deleted_cb                (GtkWidget        *widget,
67
                                                 GdkEventAny        *event,
68
                                                 gpointer         data);
69
static gboolean prefs_template_key_pressed_cb        (GtkWidget        *widget,
70
                                                 GdkEventKey        *event,
71
                                                 gpointer         data);
72
static void prefs_template_cancel_cb                (void);
73
static void prefs_template_ok_cb                (void);
74
static void prefs_template_select_cb                (GtkCList        *clist,
75
                                                 gint                 row,
76
                                                 gint                 column,
77
                                                 GdkEvent        *event);
78
static void prefs_template_register_cb                (void);
79
static void prefs_template_substitute_cb        (void);
80
static void prefs_template_delete_cb                (void);
81
82
/* Called from mainwindow.c */
83
void prefs_template_open(void)
84
{
85
        inc_lock();
86
87
        if (!templates.window)
88
                prefs_template_window_create();
89
90
        prefs_template_window_setup();
91
        gtk_widget_show(templates.window);
92
}
93
94
#define ADD_ENTRY(entry, str, row) \
95
{ \
96
        label1 = gtk_label_new(str); \
97
        gtk_widget_show(label1); \
98
        gtk_table_attach(GTK_TABLE(table), label1, 0, 1, row, (row + 1), \
99
                         GTK_FILL, 0, 0, 0); \
100
        gtk_misc_set_alignment(GTK_MISC(label1), 1, 0.5); \
101
 \
102
        entry = gtk_entry_new(); \
103
        gtk_widget_show(entry); \
104
        gtk_table_attach(GTK_TABLE(table), entry, 1, 2, row, (row + 1), \
105
                         GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); \
106
}
107
108
static void prefs_template_window_create(void)
109
{
110
        /* window structure ;) */
111
        GtkWidget *window;
112
        GtkWidget   *vpaned;
113
        GtkWidget     *vbox1;
114
        GtkWidget       *hbox1;
115
        GtkWidget         *label1;
116
        GtkWidget         *entry_name;
117
        GtkWidget       *table;
118
        GtkWidget         *entry_to;
119
        GtkWidget         *entry_cc;
120
        GtkWidget         *entry_subject;
121
        GtkWidget       *scroll2;
122
        GtkWidget         *text_value;
123
        GtkWidget     *vbox2;
124
        GtkWidget       *hbox2;
125
        GtkWidget         *arrow1;
126
        GtkWidget         *hbox3;
127
        GtkWidget           *reg_btn;
128
        GtkWidget           *subst_btn;
129
        GtkWidget           *del_btn;
130
        GtkWidget         *desc_btn;
131
        GtkWidget       *scroll1;
132
        GtkWidget         *clist_tmpls;
133
        GtkWidget       *confirm_area;
134
        GtkWidget         *ok_btn;
135
        GtkWidget         *cancel_btn;
136
137
        gchar *title[1];
138
139
        /* main window */
140
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
141
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
142
        gtk_window_set_modal(GTK_WINDOW(window), TRUE);
143
        gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, FALSE);
144
        gtk_window_set_default_size(GTK_WINDOW(window), 400, -1);
145
146
        /* vpaned to separate template settings from templates list */
147
        vpaned = gtk_vpaned_new();
148
        gtk_widget_show(vpaned);
149
        gtk_container_add(GTK_CONTAINER(window), vpaned);
150
151
        /* vbox to handle template name and content */
152
        vbox1 = gtk_vbox_new(FALSE, 6);
153
        gtk_widget_show(vbox1);
154
        gtk_container_set_border_width(GTK_CONTAINER(vbox1), 8);
155
        gtk_paned_pack1(GTK_PANED(vpaned), vbox1, FALSE, FALSE);
156
157
        hbox1 = gtk_hbox_new(FALSE, 8);
158
        gtk_widget_show(hbox1);
159
        gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
160
161
        label1 = gtk_label_new(_("Template name"));
162
        gtk_widget_show(label1);
163
        gtk_box_pack_start(GTK_BOX(hbox1), label1, FALSE, FALSE, 0);
164
165
        entry_name = gtk_entry_new();
166
        gtk_widget_show(entry_name);
167
        gtk_box_pack_start(GTK_BOX(hbox1), entry_name, TRUE, TRUE, 0);
168
169
        /* table for headers */
170
        table = gtk_table_new(3, 2, FALSE);
171
        gtk_widget_show(table);
172
        gtk_box_pack_start(GTK_BOX(vbox1), table, FALSE, FALSE, 0);
173
        gtk_table_set_row_spacings(GTK_TABLE(table), 4);
174
        gtk_table_set_col_spacings(GTK_TABLE(table), 4);
175
176
        ADD_ENTRY(entry_to, _("To:"), 0);
177
        address_completion_register_entry(GTK_ENTRY(entry_to));
178
        ADD_ENTRY(entry_cc, _("Cc:"), 1);
179
        address_completion_register_entry(GTK_ENTRY(entry_cc));
180
        ADD_ENTRY(entry_subject, _("Subject:"), 2);
181
182
#undef ADD_ENTRY
183
184
        /* template content */
185
        scroll2 = gtk_scrolled_window_new(NULL, NULL);
186
        gtk_widget_show(scroll2);
187
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll2),
188
                                       GTK_POLICY_AUTOMATIC,
189
                                       GTK_POLICY_AUTOMATIC);
190
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll2),
191
                                            GTK_SHADOW_IN);
192
        gtk_box_pack_start(GTK_BOX(vbox1), scroll2, TRUE, TRUE, 0);
193
194
        text_value = gtk_text_view_new();
195
        gtk_widget_show(text_value);
196
        gtk_widget_set_size_request(text_value, -1, 120);
197
        gtk_container_add(GTK_CONTAINER(scroll2), text_value);
198
        gtk_text_view_set_editable(GTK_TEXT_VIEW(text_value), TRUE);
199
        gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_value), GTK_WRAP_WORD);
200
201
        /* vbox for buttons and templates list */
202
        vbox2 = gtk_vbox_new(FALSE, 6);
203
        gtk_widget_show(vbox2);
204
        gtk_container_set_border_width(GTK_CONTAINER(vbox2), 8);
205
        gtk_paned_pack2(GTK_PANED(vpaned), vbox2, TRUE, FALSE);
206
207
        /* register | substitute | delete */
208
        hbox2 = gtk_hbox_new(FALSE, 4);
209
        gtk_widget_show(hbox2);
210
        gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0);
211
212
        arrow1 = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
213
        gtk_widget_show(arrow1);
214
        gtk_box_pack_start(GTK_BOX(hbox2), arrow1, FALSE, FALSE, 0);
215
        gtk_widget_set_size_request(arrow1, -1, 16);
216
217
        hbox3 = gtk_hbox_new(TRUE, 4);
218
        gtk_widget_show(hbox3);
219
        gtk_box_pack_start(GTK_BOX(hbox2), hbox3, FALSE, FALSE, 0);
220
221
        reg_btn = gtk_button_new_with_label(_("Register"));
222
        gtk_widget_show(reg_btn);
223
        gtk_box_pack_start(GTK_BOX(hbox3), reg_btn, FALSE, TRUE, 0);
224
        g_signal_connect(G_OBJECT (reg_btn), "clicked",
225
                         G_CALLBACK (prefs_template_register_cb), NULL);
226
227
        subst_btn = gtk_button_new_with_label(_(" Substitute "));
228
        gtk_widget_show(subst_btn);
229
        gtk_box_pack_start(GTK_BOX(hbox3), subst_btn, FALSE, TRUE, 0);
230
        g_signal_connect(G_OBJECT(subst_btn), "clicked",
231
                         G_CALLBACK(prefs_template_substitute_cb), NULL);
232
233
        del_btn = gtk_button_new_with_label(_("Delete"));
234
        gtk_widget_show(del_btn);
235
        gtk_box_pack_start(GTK_BOX(hbox3), del_btn, FALSE, TRUE, 0);
236
        g_signal_connect(G_OBJECT(del_btn), "clicked",
237
                         G_CALLBACK(prefs_template_delete_cb), NULL);
238
239
        desc_btn = gtk_button_new_with_label(_(" Symbols "));
240
        gtk_widget_show(desc_btn);
241
        gtk_box_pack_end(GTK_BOX(hbox2), desc_btn, FALSE, FALSE, 0);
242
        g_signal_connect(G_OBJECT(desc_btn), "clicked",
243
                         G_CALLBACK(prefs_quote_description), NULL);
244
245
        /* templates list */
246
        scroll1 = gtk_scrolled_window_new(NULL, NULL);
247
        gtk_widget_show(scroll1);
248
        gtk_box_pack_start(GTK_BOX(vbox2), scroll1, TRUE, TRUE, 0);
249
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll1),
250
                                       GTK_POLICY_AUTOMATIC,
251
                                       GTK_POLICY_AUTOMATIC);
252
253
        title[0] = _("Registered templates");
254
        clist_tmpls = gtk_clist_new_with_titles(1, title);
255
        gtk_widget_show(clist_tmpls);
256
        gtk_widget_set_size_request(scroll1, -1, 140);
257
        gtk_container_add(GTK_CONTAINER(scroll1), clist_tmpls);
258
        gtk_clist_set_column_width(GTK_CLIST(clist_tmpls), 0, 80);
259
        gtk_clist_set_selection_mode(GTK_CLIST(clist_tmpls),
260
                                     GTK_SELECTION_BROWSE);
261
        GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist_tmpls)->column[0].button,
262
                               GTK_CAN_FOCUS);
263
        g_signal_connect(G_OBJECT (clist_tmpls), "select_row",
264
                         G_CALLBACK (prefs_template_select_cb), NULL);
265
266
        /* ok | cancel */
267
        gtkut_stock_button_set_create(&confirm_area, &ok_btn, GTK_STOCK_OK,
268
                                      &cancel_btn, GTK_STOCK_CANCEL,
269
                                      NULL, NULL);
270
        gtk_widget_show(confirm_area);
271
        gtk_box_pack_end(GTK_BOX(vbox2), confirm_area, FALSE, FALSE, 0);
272
        gtk_widget_grab_default(ok_btn);
273
274
        gtk_window_set_title(GTK_WINDOW(window), _("Templates"));
275
276
        g_signal_connect(G_OBJECT(window), "delete_event",
277
                         G_CALLBACK(prefs_template_deleted_cb), NULL);
278
        g_signal_connect(G_OBJECT(window), "key_press_event",
279
                         G_CALLBACK(prefs_template_key_pressed_cb), NULL);
280
        MANAGE_WINDOW_SIGNALS_CONNECT(window);
281
        g_signal_connect(G_OBJECT(ok_btn), "clicked",
282
                         G_CALLBACK(prefs_template_ok_cb), NULL);
283
        g_signal_connect(G_OBJECT(cancel_btn), "clicked",
284
                         G_CALLBACK(prefs_template_cancel_cb), NULL);
285
286
        address_completion_start(window);
287
288
        templates.window = window;
289
        templates.clist_tmpls = clist_tmpls;
290
        templates.entry_name = entry_name;
291
        templates.entry_to = entry_to;
292
        templates.entry_cc = entry_cc;
293
        templates.entry_subject = entry_subject;
294
        templates.text_value = text_value;
295
        templates.confirm_area = confirm_area;
296
        templates.ok_btn = ok_btn;
297
        templates.cancel_btn = cancel_btn;
298
}
299
300
static void prefs_template_window_setup(void)
301
{
302
        GtkCList *clist = GTK_CLIST(templates.clist_tmpls);
303
        GSList *tmpl_list;
304
        GSList *cur;
305
        gchar *title[1];
306
        gint row;
307
        Template *tmpl;
308
309
        gtkut_box_set_reverse_order(GTK_BOX(templates.confirm_area),
310
                                    !prefs_common.comply_gnome_hig);
311
        manage_window_set_transient(GTK_WINDOW(templates.window));
312
        gtk_widget_grab_focus(templates.ok_btn);
313
314
        gtk_clist_freeze(clist);
315
        gtk_clist_clear(clist);
316
317
        title[0] = _("(New)");
318
        row = gtk_clist_append(clist, title);
319
        gtk_clist_set_row_data(clist, row, NULL);
320
321
        tmpl_list = template_read_config();
322
323
        for (cur = tmpl_list; cur != NULL; cur = cur->next) {
324
                tmpl = (Template *)cur->data;
325
                title[0] = tmpl->name;
326
                row = gtk_clist_append(clist, title);
327
                gtk_clist_set_row_data(clist, row, tmpl);
328
        }
329
330
        g_slist_free(tmpl_list);
331
332
        gtk_clist_thaw(clist);
333
}
334
335
static void prefs_template_clear(void)
336
{
337
        Template *tmpl;
338
        gint row = 1;
339
340
        while ((tmpl = gtk_clist_get_row_data
341
                (GTK_CLIST(templates.clist_tmpls), row)) != NULL) {
342
                template_free(tmpl);
343
                row++;
344
        }
345
346
        gtk_clist_clear(GTK_CLIST(templates.clist_tmpls));
347
}
348
349
static gint prefs_template_deleted_cb(GtkWidget *widget, GdkEventAny *event,
350
                                      gpointer data)
351
{
352
        prefs_template_cancel_cb();
353
        return TRUE;
354
}
355
356
static gboolean prefs_template_key_pressed_cb(GtkWidget *widget,
357
                                              GdkEventKey *event, gpointer data)
358
{
359
        if (event && event->keyval == GDK_Escape)
360
                prefs_template_cancel_cb();
361
        return FALSE;
362
}
363
364
static void prefs_template_ok_cb(void)
365
{
366
        GSList *tmpl_list;
367
368
        tmpl_list = prefs_template_get_list();
369
        template_set_config(tmpl_list);
370
        compose_reflect_prefs_all();
371
        gtk_clist_clear(GTK_CLIST(templates.clist_tmpls));
372
        gtk_widget_hide(templates.window);
373
        main_window_popup(main_window_get());
374
        inc_unlock();
375
}
376
377
static void prefs_template_cancel_cb(void)
378
{
379
        prefs_template_clear();
380
        gtk_widget_hide(templates.window);
381
        main_window_popup(main_window_get());
382
        inc_unlock();
383
}
384
385
static void prefs_template_select_cb(GtkCList *clist, gint row, gint column,
386
                                     GdkEvent *event)
387
{
388
        Template *tmpl;
389
        Template tmpl_def;
390
        GtkTextBuffer *buffer;
391
        GtkTextIter iter;
392
393
        tmpl_def.name = _("Template");
394
        tmpl_def.subject = "";
395
        tmpl_def.to = "";
396
        tmpl_def.cc = "";
397
        tmpl_def.value = "";
398
399
        if (!(tmpl = gtk_clist_get_row_data(clist, row)))
400
                tmpl = &tmpl_def;
401
402
        gtk_entry_set_text(GTK_ENTRY(templates.entry_name), tmpl->name);
403
        gtk_entry_set_text(GTK_ENTRY(templates.entry_to),
404
                           tmpl->to ? tmpl->to : "");
405
        gtk_entry_set_text(GTK_ENTRY(templates.entry_cc),
406
                           tmpl->cc ? tmpl->cc : "");
407
        gtk_entry_set_text(GTK_ENTRY(templates.entry_subject),
408
                           tmpl->subject ? tmpl->subject : "");
409
410
        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(templates.text_value));
411
        gtk_text_buffer_set_text(buffer, "", 0);
412
        gtk_text_buffer_get_start_iter(buffer, &iter);
413
        gtk_text_buffer_insert(buffer, &iter, tmpl->value, -1);
414
}
415
416
static GSList *prefs_template_get_list(void)
417
{
418
        gint row = 1;
419
        GSList *tmpl_list = NULL;
420
        Template *tmpl;
421
422
        while ((tmpl = gtk_clist_get_row_data
423
                (GTK_CLIST(templates.clist_tmpls), row)) != NULL) {
424
                tmpl_list = g_slist_append(tmpl_list, tmpl);
425
                row++;
426
        }
427
428
        return tmpl_list;
429
}
430
431
static gint prefs_template_clist_set_row(gint row)
432
{
433
        GtkCList *clist = GTK_CLIST(templates.clist_tmpls);
434
        Template *tmpl;
435
        Template *tmp_tmpl;
436
        GtkTextBuffer *buffer;
437
        GtkTextIter start, end;
438
        gchar *name;
439
        gchar *to;
440
        gchar *cc;
441
        gchar *subject;
442
        gchar *value;
443
        gchar *title[1];
444
445
        g_return_val_if_fail(row != 0, -1);
446
447
        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(templates.text_value));
448
        gtk_text_buffer_get_start_iter(buffer, &start);
449
        gtk_text_buffer_get_iter_at_offset(buffer, &end, -1); // end_iter?
450
        value = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
451
452
        if (value && *value != '\0') {
453
                gchar *parsed_buf;
454
                MsgInfo dummyinfo;
455
456
                memset(&dummyinfo, 0, sizeof(MsgInfo));
457
                quote_fmt_init(&dummyinfo, NULL, NULL);
458
                quote_fmt_scan_string(value);
459
                quote_fmt_parse();
460
                parsed_buf = quote_fmt_get_buffer();
461
                if (!parsed_buf) {
462
                        alertpanel_error(_("Template format error."));
463
                        g_free(value);
464
                        return -1;
465
                }
466
        }
467
468
        name = gtk_editable_get_chars(GTK_EDITABLE(templates.entry_name),
469
                                      0, -1);
470
        subject = gtk_editable_get_chars(GTK_EDITABLE(templates.entry_subject),
471
                                         0, -1);
472
        to = gtk_editable_get_chars(GTK_EDITABLE(templates.entry_to), 0, -1);
473
        cc = gtk_editable_get_chars(GTK_EDITABLE(templates.entry_cc), 0, -1);
474
475
        if (subject && *subject == '\0') {
476
                g_free(subject);
477
                subject = NULL;
478
        }
479
        if (to && *to == '\0') {
480
                g_free(to);
481
                to = NULL;
482
        }
483
484
        tmpl = g_new(Template, 1);
485
        tmpl->name = name;
486
        tmpl->to = to;
487
        tmpl->cc = cc;
488
        tmpl->subject = subject;
489
        tmpl->value = value;
490
491
        title[0] = name;
492
493
        if (row < 0) {
494
                row = gtk_clist_append(clist, title);
495
        } else {
496
                gtk_clist_set_text(clist, row, 0, name);
497
                tmp_tmpl = gtk_clist_get_row_data(clist, row);
498
                if (tmp_tmpl)
499
                        template_free(tmp_tmpl);
500
        }
501
502
        gtk_clist_set_row_data(clist, row, tmpl);
503
        return row;
504
}
505
506
static void prefs_template_register_cb(void)
507
{
508
        prefs_template_clist_set_row(-1);
509
}
510
511
static void prefs_template_substitute_cb(void)
512
{
513
        GtkCList *clist = GTK_CLIST(templates.clist_tmpls);
514
        Template *tmpl;
515
        gint row;
516
517
        if (!clist->selection) return;
518
519
        row = GPOINTER_TO_INT(clist->selection->data);
520
        if (row == 0) return;
521
522
        tmpl = gtk_clist_get_row_data(clist, row);
523
        if (!tmpl) return;
524
525
        prefs_template_clist_set_row(row);
526
}
527
528
static void prefs_template_delete_cb(void)
529
{
530
        GtkCList *clist = GTK_CLIST(templates.clist_tmpls);
531
        Template *tmpl;
532
        gint row;
533
534
        if (!clist->selection) return;
535
        row = GPOINTER_TO_INT(clist->selection->data);
536
        if (row == 0) return;
537
538
        if (alertpanel(_("Delete template"),
539
                       _("Do you really want to delete this template?"),
540
                       GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT)
541
                return;
542
543
        tmpl = gtk_clist_get_row_data(clist, row);
544
        template_free(tmpl);
545
        gtk_clist_remove(clist, row);
546
}