~ubuntu-branches/ubuntu/oneiric/evolution/oneiric-proposed

« back to all changes in this revision

Viewing changes to .pc/evo_fbee43e_to_f4505a2.patch/plugins/save-calendar/csv-format.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2011-08-18 11:10:01 UTC
  • mfrom: (1.1.83 upstream)
  • Revision ID: james.westby@ubuntu.com-20110818111001-559uzyuqsoyj7xjg
Tags: 3.1.5-0ubuntu1
* New upstream release.
* debian/control: bump e-d-s Build-Depends to 3.1.5.
* debian/patches/03_lpi.patch: refreshed.
* debian/patches/11_remove_upstream_submit_bugreport.patch: refreshed.
* debian/patches/bogofilter_init_903b8e6.patch,
  debian/patches/evo_fbee43e_to_f4505a2.patch,
  debian/patches/spamassassin_init_4fc04af.patch: dropped, included upstream.
* debian/patches/spamd_sbin_path.patch: correct the path to spamd as
  /usr/sbin/spamd, which is the correct path in Ubuntu. (LP: #828693)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * This program is free software; you can redistribute it and/or
3
 
 * modify it under the terms of the GNU Lesser General Public
4
 
 * License as published by the Free Software Foundation; either
5
 
 * version 2 of the License, or (at your option) version 3.
6
 
 *
7
 
 * This program is distributed in the hope that it will be useful,
8
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10
 
 * Lesser General Public License for more details.
11
 
 *
12
 
 * You should have received a copy of the GNU Lesser General Public
13
 
 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14
 
 *
15
 
 *
16
 
 * Authors:
17
 
 *              Philip Van Hoof <pvanhoof@gnome.org>
18
 
 *
19
 
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20
 
 *
21
 
 */
22
 
 
23
 
#ifdef HAVE_CONFIG_H
24
 
#include <config.h>
25
 
#endif
26
 
 
27
 
#include <gtk/gtk.h>
28
 
#include <glib/gi18n.h>
29
 
#include <libedataserver/e-source.h>
30
 
#include <libecal/e-cal-time-util.h>
31
 
#include <libedataserver/e-data-server-util.h>
32
 
#include <libedataserverui/e-source-selector.h>
33
 
#include <libedataserverui/e-client-utils.h>
34
 
#include <libecal/e-cal-client.h>
35
 
#include <string.h>
36
 
 
37
 
#include "format-handler.h"
38
 
 
39
 
typedef struct _CsvConfig CsvConfig;
40
 
struct _CsvConfig {
41
 
        gchar *newline;
42
 
        gchar *quote;
43
 
        gchar *delimiter;
44
 
        gboolean header;
45
 
};
46
 
 
47
 
static gboolean string_needsquotes (const gchar *value, CsvConfig *config);
48
 
 
49
 
typedef struct _CsvPluginData CsvPluginData;
50
 
struct _CsvPluginData
51
 
{
52
 
        GtkWidget *delimiter_entry, *newline_entry, *quote_entry, *header_check;
53
 
};
54
 
 
55
 
static void
56
 
display_error_message (GtkWidget *parent, GError *error)
57
 
{
58
 
        GtkWidget *dialog;
59
 
 
60
 
        dialog = gtk_message_dialog_new (
61
 
                GTK_WINDOW (parent), 0,
62
 
                GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
63
 
                "%s", error->message);
64
 
        gtk_dialog_run (GTK_DIALOG (dialog));
65
 
        gtk_widget_destroy (dialog);
66
 
}
67
 
 
68
 
enum { /* CSV helper enum */
69
 
        ECALCOMPONENTTEXT,
70
 
        ECALCOMPONENTATTENDEE,
71
 
        CONSTCHAR
72
 
};
73
 
 
74
 
/* Some helpers for the csv stuff */
75
 
static GString *
76
 
add_list_to_csv (GString *line, GSList *list_in, CsvConfig *config, gint type)
77
 
{
78
 
 
79
 
        /*
80
 
         * This one will write 'ECalComponentText' and 'const char' GSLists. It will
81
 
         * put quotes around the complete written value if there's was only one value
82
 
         * but it required having quotes and if there was more than one value (in which
83
 
         * case delimiters are used to separate them, hence the need for the quotes).
84
 
         */
85
 
 
86
 
        if (list_in) {
87
 
                gboolean needquotes = FALSE;
88
 
                GSList *list = list_in;
89
 
                GString *tmp = NULL;
90
 
                gint cnt=0;
91
 
                while (list) {
92
 
                        const gchar *str = NULL;
93
 
                        if (cnt == 0)
94
 
                                tmp = g_string_new ("");
95
 
                        if (cnt > 0)
96
 
                                needquotes = TRUE;
97
 
                        switch (type) {
98
 
                        case ECALCOMPONENTATTENDEE:
99
 
                                str = ((ECalComponentAttendee*) list->data)->value;
100
 
                                break;
101
 
                        case ECALCOMPONENTTEXT:
102
 
                                str = ((ECalComponentText*) list->data)->value;
103
 
                                break;
104
 
                        case CONSTCHAR:
105
 
                        default:
106
 
                                str = list->data;
107
 
                                break;
108
 
                        }
109
 
                        if (!needquotes)
110
 
                                needquotes = string_needsquotes (str, config);
111
 
                        if (str)
112
 
                                tmp = g_string_append (tmp, (const gchar *) str);
113
 
                        list = g_slist_next (list); cnt++;
114
 
                        if (list)
115
 
                                tmp = g_string_append (tmp, config->delimiter);
116
 
                }
117
 
 
118
 
                if (needquotes)
119
 
                        line = g_string_append (line, config->quote);
120
 
                line = g_string_append_len (line, tmp->str, tmp->len);
121
 
                g_string_free (tmp, TRUE);
122
 
                if (needquotes)
123
 
                        line = g_string_append (line, config->quote);
124
 
        }
125
 
 
126
 
        line = g_string_append (line, config->delimiter);
127
 
        return line;
128
 
}
129
 
 
130
 
static GString *
131
 
add_nummeric_to_csv (GString *line, gint *nummeric, CsvConfig *config)
132
 
{
133
 
 
134
 
        /*
135
 
         * This one will write {-1}..{00}..{01}..{99}
136
 
         * it prepends a 0 if it's < 10 and > -1
137
 
         */
138
 
 
139
 
        if (nummeric)
140
 
                g_string_append_printf (
141
 
                        line, "%s%d",
142
 
                        (*nummeric < 10 && *nummeric > -1) ? "0" : "",
143
 
                        *nummeric);
144
 
 
145
 
        return g_string_append (line, config->delimiter);
146
 
}
147
 
 
148
 
static GString *
149
 
add_time_to_csv (GString *line, icaltimetype *time, CsvConfig *config)
150
 
{
151
 
 
152
 
        if (time) {
153
 
                gboolean needquotes = FALSE;
154
 
                struct tm mytm =  icaltimetype_to_tm (time);
155
 
                gchar *str = (gchar *) g_malloc (sizeof (gchar) * 200);
156
 
 
157
 
                /* Translators: the %F %T is the third argument for a
158
 
                 * strftime function.  It lets you define the formatting
159
 
                 * of the date in the csv-file. */
160
 
                e_utf8_strftime (str, 200, _("%F %T"), &mytm);
161
 
 
162
 
                needquotes = string_needsquotes (str, config);
163
 
 
164
 
                if (needquotes)
165
 
                        line = g_string_append (line, config->quote);
166
 
 
167
 
                line = g_string_append (line, str);
168
 
 
169
 
                if (needquotes)
170
 
                        line = g_string_append (line, config->quote);
171
 
 
172
 
                g_free (str);
173
 
 
174
 
        }
175
 
 
176
 
        line = g_string_append (line, config->delimiter);
177
 
 
178
 
        return line;
179
 
}
180
 
 
181
 
static gboolean
182
 
string_needsquotes (const gchar *value, CsvConfig *config)
183
 
{
184
 
 
185
 
        /* This is the actual need for quotes-checker */
186
 
 
187
 
        /*
188
 
         * These are the simple substring-checks
189
 
         *
190
 
         * Example: {Mom, can you please do that for me?}
191
 
         * Will be written as {"Mom, can you please do that for me?"}
192
 
         */
193
 
 
194
 
        gboolean needquotes = strstr (value, config->delimiter) ? TRUE:FALSE;
195
 
 
196
 
        if (!needquotes) {
197
 
                needquotes = strstr (value, config->newline) ? TRUE:FALSE;
198
 
                if (!needquotes)
199
 
                        needquotes = strstr (value, config->quote) ? TRUE:FALSE;
200
 
        }
201
 
 
202
 
        /*
203
 
         * If the special-char is char+onespace (so like {, } {" }, {\n }) and it occurs
204
 
         * the value that is going to be written
205
 
         *
206
 
         * In this case we don't trust the user . . . and are going to quote the string
207
 
         * just to play save -- Quoting is always allowed in the CSV format. If you can
208
 
         * avoid it, it's better to do so since a lot applications don't support CSV
209
 
         * correctly! --.
210
 
         *
211
 
         * Example: {Mom,can you please do that for me?}
212
 
         * This example will be written as {"Mom,can you please do that for me?"} because
213
 
         * there's a {,} behind {Mom} and the delimiter is {, } (so we searched only the
214
 
         * first character of {, } and didn't trust the user).
215
 
         */
216
 
 
217
 
        if (!needquotes) {
218
 
                gint len = strlen (config->delimiter);
219
 
                if ((len == 2) && (config->delimiter[1] == ' ')) {
220
 
                        needquotes = strchr (value, config->delimiter[0])?TRUE:FALSE;
221
 
                        if (!needquotes) {
222
 
                                len = strlen (config->newline);
223
 
                                if ((len == 2) && (config->newline[1] == ' ')) {
224
 
                                        needquotes = strchr (value, config->newline[0])?TRUE:FALSE;
225
 
                                        if (!needquotes) {
226
 
                                                len = strlen (config->quote);
227
 
                                                if ((len == 2) && (config->quote[1] == ' ')) {
228
 
                                                        needquotes = strchr
229
 
                                                                (value, config->quote[0])?TRUE:FALSE;
230
 
                                                }
231
 
                                        }
232
 
                                }
233
 
                        }
234
 
                }
235
 
        }
236
 
 
237
 
        return needquotes;
238
 
}
239
 
 
240
 
static GString *
241
 
add_string_to_csv (GString *line, const gchar *value, CsvConfig *config)
242
 
{
243
 
        /* Will add a string to the record and will check for the need for quotes */
244
 
 
245
 
        if ((value) && (strlen (value)>0)) {
246
 
                gboolean needquotes = string_needsquotes (value, config);
247
 
 
248
 
                if (needquotes)
249
 
                        line = g_string_append (line, config->quote);
250
 
                line = g_string_append (line, (const gchar *) value);
251
 
                if (needquotes)
252
 
                        line = g_string_append (line, config->quote);
253
 
        }
254
 
        line = g_string_append (line, config->delimiter);
255
 
        return line;
256
 
}
257
 
 
258
 
/* Convert what the user types to what he probably means */
259
 
static gchar *
260
 
userstring_to_systemstring (const gchar *userstring)
261
 
{
262
 
        const gchar *text = userstring;
263
 
        gint i=0, len = strlen (text);
264
 
        GString *str = g_string_new ("");
265
 
        gchar *retval = NULL;
266
 
 
267
 
        while (i < len) {
268
 
                if (text[i] == '\\') {
269
 
                        switch (text[i+1]) {
270
 
                        case 'n':
271
 
                                str = g_string_append_c (str, '\n');
272
 
                                i++;
273
 
                                break;
274
 
                        case '\\':
275
 
                                str = g_string_append_c (str, '\\');
276
 
                                i++;
277
 
                                break;
278
 
                        case 'r':
279
 
                                str = g_string_append_c (str, '\r');
280
 
                                i++;
281
 
                                break;
282
 
                        case 't':
283
 
                                str = g_string_append_c (str, '\t');
284
 
                                i++;
285
 
                                break;
286
 
                        }
287
 
                } else {
288
 
                        str = g_string_append_c (str, text[i]);
289
 
                }
290
 
 
291
 
                i++;
292
 
        }
293
 
 
294
 
        retval = str->str;
295
 
        g_string_free (str, FALSE);
296
 
 
297
 
        return retval;
298
 
}
299
 
 
300
 
static void
301
 
do_save_calendar_csv (FormatHandler *handler,
302
 
                      ESourceSelector *selector,
303
 
                      ECalClientSourceType type,
304
 
                      gchar *dest_uri)
305
 
{
306
 
 
307
 
        /*
308
 
         * According to some documentation about CSV, newlines 'are' allowed
309
 
         * in CSV-files. But you 'do' have to put the value between quotes.
310
 
         * The helper 'string_needsquotes' will check for that
311
 
         *
312
 
         * http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm
313
 
         * http://www.creativyst.com/cgi-bin/Prod/15/eg/csv2xml.pl
314
 
         */
315
 
 
316
 
        ESource *primary_source;
317
 
        ECalClient *source_client;
318
 
        GError *error = NULL;
319
 
        GSList *objects = NULL;
320
 
        GOutputStream *stream;
321
 
        GString *line = NULL;
322
 
        CsvConfig *config = NULL;
323
 
        CsvPluginData *d = handler->data;
324
 
        const gchar *tmp = NULL;
325
 
 
326
 
        if (!dest_uri)
327
 
                return;
328
 
 
329
 
        primary_source = e_source_selector_get_primary_selection (selector);
330
 
 
331
 
        /* open source client */
332
 
        source_client = e_cal_client_new (primary_source, type, &error);
333
 
        if (source_client)
334
 
                g_signal_connect (source_client, "authenticate", G_CALLBACK (e_client_utils_authenticate_handler), NULL);
335
 
 
336
 
        if (!source_client || !e_client_open_sync (E_CLIENT (source_client), TRUE, NULL, &error)) {
337
 
                display_error_message (
338
 
                        gtk_widget_get_toplevel (GTK_WIDGET (selector)),
339
 
                        error);
340
 
                if (source_client)
341
 
                        g_object_unref (source_client);
342
 
                g_error_free (error);
343
 
                return;
344
 
        }
345
 
 
346
 
        config = g_new (CsvConfig, 1);
347
 
 
348
 
        tmp = gtk_entry_get_text (GTK_ENTRY (d->delimiter_entry));
349
 
        config->delimiter = userstring_to_systemstring (tmp?tmp:", ");
350
 
        tmp = gtk_entry_get_text (GTK_ENTRY (d->newline_entry));
351
 
        config->newline = userstring_to_systemstring (tmp?tmp:"\\n");
352
 
        tmp = gtk_entry_get_text (GTK_ENTRY (d->quote_entry));
353
 
        config->quote = userstring_to_systemstring (tmp?tmp:"\"");
354
 
        config->header = gtk_toggle_button_get_active (
355
 
                GTK_TOGGLE_BUTTON (d->header_check));
356
 
 
357
 
        stream = open_for_writing (
358
 
                GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (selector))),
359
 
                dest_uri, &error);
360
 
 
361
 
        if (stream && e_cal_client_get_object_list_as_comps_sync (source_client, "#t", &objects, NULL, NULL)) {
362
 
                GSList *iter;
363
 
 
364
 
                if (config->header) {
365
 
 
366
 
                        gint i=0;
367
 
 
368
 
                        static const gchar *labels[] = {
369
 
                                 N_("UID"),
370
 
                                 N_("Summary"),
371
 
                                 N_("Description List"),
372
 
                                 N_("Categories List"),
373
 
                                 N_("Comment List"),
374
 
                                 N_("Completed"),
375
 
                                 N_("Created"),
376
 
                                 N_("Contact List"),
377
 
                                 N_("Start"),
378
 
                                 N_("End"),
379
 
                                 N_("Due"),
380
 
                                 N_("percent Done"),
381
 
                                 N_("Priority"),
382
 
                                 N_("URL"),
383
 
                                 N_("Attendees List"),
384
 
                                 N_("Location"),
385
 
                                 N_("Modified"),
386
 
                        };
387
 
 
388
 
                        line = g_string_new ("");
389
 
                        for (i=0;i<G_N_ELEMENTS (labels);i++) {
390
 
                                if (i>0)
391
 
                                        g_string_append (line, config->delimiter);
392
 
                                g_string_append (line, _(labels[i]));
393
 
                        }
394
 
 
395
 
                        g_string_append (line, config->newline);
396
 
 
397
 
                        g_output_stream_write_all (
398
 
                                stream, line->str, line->len,
399
 
                                NULL, NULL, NULL);
400
 
                        g_string_free (line, TRUE);
401
 
                }
402
 
 
403
 
                for (iter = objects; iter; iter = iter->next) {
404
 
                        ECalComponent *comp = objects->data;
405
 
                        gchar *delimiter_temp = NULL;
406
 
                        const gchar *temp_constchar;
407
 
                        GSList *temp_list;
408
 
                        ECalComponentDateTime temp_dt;
409
 
                        struct icaltimetype *temp_time;
410
 
                        gint *temp_int;
411
 
                        ECalComponentText temp_comptext;
412
 
 
413
 
                        line = g_string_new ("");
414
 
 
415
 
                        /* Getting the stuff */
416
 
                        e_cal_component_get_uid (comp, &temp_constchar);
417
 
                        line = add_string_to_csv (line, temp_constchar, config);
418
 
 
419
 
                        e_cal_component_get_summary (comp, &temp_comptext);
420
 
                        line = add_string_to_csv (
421
 
                                line, temp_comptext.value, config);
422
 
 
423
 
                        e_cal_component_get_description_list (comp, &temp_list);
424
 
                        line = add_list_to_csv (
425
 
                                line, temp_list, config, ECALCOMPONENTTEXT);
426
 
                        if (temp_list)
427
 
                                e_cal_component_free_text_list (temp_list);
428
 
 
429
 
                        e_cal_component_get_categories_list (comp, &temp_list);
430
 
                        line = add_list_to_csv (
431
 
                                line, temp_list, config, CONSTCHAR);
432
 
                        if (temp_list)
433
 
                                e_cal_component_free_categories_list (temp_list);
434
 
 
435
 
                        e_cal_component_get_comment_list (comp, &temp_list);
436
 
                        line = add_list_to_csv (
437
 
                                line, temp_list, config, ECALCOMPONENTTEXT);
438
 
                        if (temp_list)
439
 
                                e_cal_component_free_text_list (temp_list);
440
 
 
441
 
                        e_cal_component_get_completed (comp, &temp_time);
442
 
                        line = add_time_to_csv (line, temp_time, config);
443
 
                        if (temp_time)
444
 
                                e_cal_component_free_icaltimetype (temp_time);
445
 
 
446
 
                        e_cal_component_get_created (comp, &temp_time);
447
 
                        line = add_time_to_csv (line, temp_time, config);
448
 
                        if (temp_time)
449
 
                                e_cal_component_free_icaltimetype (temp_time);
450
 
 
451
 
                        e_cal_component_get_contact_list (comp, &temp_list);
452
 
                        line = add_list_to_csv (
453
 
                                line, temp_list, config, ECALCOMPONENTTEXT);
454
 
                        if (temp_list)
455
 
                                e_cal_component_free_text_list (temp_list);
456
 
 
457
 
                        e_cal_component_get_dtstart (comp, &temp_dt);
458
 
                        line = add_time_to_csv (
459
 
                                line, temp_dt.value ?
460
 
                                temp_dt.value : NULL, config);
461
 
                        e_cal_component_free_datetime (&temp_dt);
462
 
 
463
 
                        e_cal_component_get_dtend (comp, &temp_dt);
464
 
                        line = add_time_to_csv (
465
 
                                line, temp_dt.value ?
466
 
                                temp_dt.value : NULL, config);
467
 
                        e_cal_component_free_datetime (&temp_dt);
468
 
 
469
 
                        e_cal_component_get_due (comp, &temp_dt);
470
 
                        line = add_time_to_csv (
471
 
                                line, temp_dt.value ?
472
 
                                temp_dt.value : NULL, config);
473
 
                        e_cal_component_free_datetime (&temp_dt);
474
 
 
475
 
                        e_cal_component_get_percent (comp, &temp_int);
476
 
                        line = add_nummeric_to_csv (line, temp_int, config);
477
 
 
478
 
                        e_cal_component_get_priority (comp, &temp_int);
479
 
                        line = add_nummeric_to_csv (line, temp_int, config);
480
 
 
481
 
                        e_cal_component_get_url (comp, &temp_constchar);
482
 
                        line = add_string_to_csv (line, temp_constchar, config);
483
 
 
484
 
                        if (e_cal_component_has_attendees (comp)) {
485
 
                                e_cal_component_get_attendee_list (comp, &temp_list);
486
 
                                line = add_list_to_csv (
487
 
                                        line, temp_list, config,
488
 
                                        ECALCOMPONENTATTENDEE);
489
 
                                if (temp_list)
490
 
                                        e_cal_component_free_attendee_list (temp_list);
491
 
                        } else {
492
 
                                line = add_list_to_csv (
493
 
                                        line, NULL, config,
494
 
                                        ECALCOMPONENTATTENDEE);
495
 
                        }
496
 
 
497
 
                        e_cal_component_get_location (comp, &temp_constchar);
498
 
                        line = add_string_to_csv (line, temp_constchar, config);
499
 
 
500
 
                        e_cal_component_get_last_modified (comp, &temp_time);
501
 
 
502
 
                        /* Append a newline (record delimiter) */
503
 
                        delimiter_temp = config->delimiter;
504
 
                        config->delimiter = config->newline;
505
 
 
506
 
                        line = add_time_to_csv (line, temp_time, config);
507
 
 
508
 
                        /* And restore for the next record */
509
 
                        config->delimiter = delimiter_temp;
510
 
 
511
 
                        /* Important note!
512
 
                         * The documentation is not requiring this!
513
 
                         *
514
 
                         * if (temp_time)
515
 
                         *     e_cal_component_free_icaltimetype (temp_time);
516
 
                         *
517
 
                         * Please uncomment and fix documentation if untrue
518
 
                         * http://www.gnome.org/projects/evolution/
519
 
                         *      developer-doc/libecal/ECalComponent.html
520
 
                         *      #e-cal-component-get-last-modified
521
 
                         */
522
 
                        g_output_stream_write_all (
523
 
                                stream, line->str, line->len,
524
 
                                NULL, NULL, &error);
525
 
 
526
 
                        /* It's written, so we can free it */
527
 
                        g_string_free (line, TRUE);
528
 
                }
529
 
 
530
 
                g_output_stream_close (stream, NULL, NULL);
531
 
 
532
 
                e_cal_client_free_ecalcomp_slist (objects);
533
 
        }
534
 
 
535
 
        if (stream)
536
 
                g_object_unref (stream);
537
 
 
538
 
        g_object_unref (source_client);
539
 
 
540
 
        g_free (config->delimiter);
541
 
        g_free (config->quote);
542
 
        g_free (config->newline);
543
 
        g_free (config);
544
 
 
545
 
        if (error) {
546
 
                display_error_message (
547
 
                        gtk_widget_get_toplevel (GTK_WIDGET (selector)),
548
 
                        error);
549
 
                g_error_free (error);
550
 
        }
551
 
 
552
 
        return;
553
 
}
554
 
 
555
 
static GtkWidget *
556
 
create_options_widget (FormatHandler *handler)
557
 
{
558
 
        GtkWidget *table = gtk_table_new (4, 2, FALSE), *label = NULL,
559
 
                  *csv_options = gtk_expander_new_with_mnemonic (
560
 
                        _("A_dvanced options for the CSV format")),
561
 
                  *vbox = gtk_vbox_new (FALSE, 0);
562
 
        CsvPluginData *d = handler->data;
563
 
 
564
 
        d->delimiter_entry = gtk_entry_new ();
565
 
        d->newline_entry = gtk_entry_new ();
566
 
        d->quote_entry = gtk_entry_new ();
567
 
        d->header_check = gtk_check_button_new_with_mnemonic (
568
 
                _("Prepend a _header"));
569
 
 
570
 
        /* Advanced CSV options */
571
 
        gtk_entry_set_text (GTK_ENTRY(d->delimiter_entry), ", ");
572
 
        gtk_entry_set_text (GTK_ENTRY(d->quote_entry), "\"");
573
 
        gtk_entry_set_text (GTK_ENTRY(d->newline_entry), "\\n");
574
 
 
575
 
        gtk_table_set_row_spacings (GTK_TABLE (table), 5);
576
 
        gtk_table_set_col_spacings (GTK_TABLE (table), 5);
577
 
        label = gtk_label_new_with_mnemonic (_("_Value delimiter:"));
578
 
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0);
579
 
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), d->delimiter_entry);
580
 
        gtk_table_attach (
581
 
                GTK_TABLE (table), label, 0, 1, 0, 1,
582
 
                (GtkAttachOptions) (GTK_FILL),
583
 
                (GtkAttachOptions) (0), 0, 0);
584
 
        gtk_table_attach (
585
 
                GTK_TABLE (table), d->delimiter_entry, 1, 2, 0, 1,
586
 
                (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
587
 
                (GtkAttachOptions) (0), 0, 0);
588
 
        label = gtk_label_new_with_mnemonic (_("_Record delimiter:"));
589
 
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0);
590
 
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), d->newline_entry);
591
 
        gtk_table_attach (
592
 
                GTK_TABLE (table), label, 0, 1, 1, 2,
593
 
                (GtkAttachOptions) (GTK_FILL),
594
 
                (GtkAttachOptions) (0), 0, 0);
595
 
        gtk_table_attach (
596
 
                GTK_TABLE (table), d->newline_entry, 1, 2, 1, 2,
597
 
                (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
598
 
                (GtkAttachOptions) (0), 0, 0);
599
 
        label = gtk_label_new_with_mnemonic (_("_Encapsulate values with:"));
600
 
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0);
601
 
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), d->quote_entry);
602
 
        gtk_table_attach (
603
 
                GTK_TABLE (table), label, 0, 1, 2, 3,
604
 
                (GtkAttachOptions) (GTK_FILL),
605
 
                (GtkAttachOptions) (0), 0, 0);
606
 
        gtk_table_attach (
607
 
                GTK_TABLE (table), d->quote_entry, 1, 2, 2, 3,
608
 
                (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
609
 
                (GtkAttachOptions) (0), 0, 0);
610
 
 
611
 
        gtk_box_pack_start (GTK_BOX (vbox), d->header_check, TRUE, TRUE, 0);
612
 
        gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
613
 
        gtk_widget_show_all (vbox);
614
 
 
615
 
        gtk_container_add (GTK_CONTAINER (csv_options), vbox);
616
 
 
617
 
        return csv_options;
618
 
}
619
 
 
620
 
FormatHandler *csv_format_handler_new (void)
621
 
{
622
 
        FormatHandler *handler = g_new (FormatHandler, 1);
623
 
 
624
 
        handler->isdefault = FALSE;
625
 
        handler->combo_label = _("Comma separated value format (.csv)");
626
 
        handler->filename_ext = ".csv";
627
 
        handler->data = g_new (CsvPluginData, 1);
628
 
        handler->options_widget = create_options_widget (handler);
629
 
        handler->save = do_save_calendar_csv;
630
 
 
631
 
        return handler;
632
 
}