~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/extension/system.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This is file is kind of the junk file.  Basically everything that
 
3
 * didn't fit in one of the other well defined areas, well, it's now
 
4
 * here.  Which is good in someways, but this file really needs some
 
5
 * definition.  Hopefully that will come ASAP.
 
6
 *
 
7
 * Authors:
 
8
 *   Ted Gould <ted@gould.cx>
 
9
 *   Johan Engelen <johan@shouraizou.nl>
 
10
 *
 
11
 * Copyright (C) 2006-2007 Johan Engelen
 
12
 * Copyright (C) 2002-2004 Ted Gould
 
13
 *
 
14
 * Released under GNU GPL, read the file 'COPYING' for more information
 
15
 */
 
16
 
 
17
#ifdef HAVE_CONFIG_H
 
18
# include <config.h>
 
19
#endif
 
20
 
 
21
#include <interface.h>
 
22
 
 
23
#include "extension.h"
 
24
#include "db.h"
 
25
#include "input.h"
 
26
#include "output.h"
 
27
#include "effect.h"
 
28
#include "patheffect.h"
 
29
#include "print.h"
 
30
#include "implementation/script.h"
 
31
#include "implementation/xslt.h"
 
32
#include "xml/rebase-hrefs.h"
 
33
/* #include "implementation/plugin.h" */
 
34
 
 
35
namespace Inkscape {
 
36
namespace Extension {
 
37
 
 
38
static void open_internal(Inkscape::Extension::Extension *in_plug, gpointer in_data);
 
39
static void save_internal(Inkscape::Extension::Extension *in_plug, gpointer in_data);
 
40
static Extension *build_from_reprdoc(Inkscape::XML::Document *doc, Implementation::Implementation *in_imp);
 
41
 
 
42
/**
 
43
 * \return   A new document created from the filename passed in
 
44
 * \brief    This is a generic function to use the open function of
 
45
 *           a module (including Autodetect)
 
46
 * \param    key       Identifier of which module to use
 
47
 * \param    filename  The file that should be opened
 
48
 *
 
49
 * First things first, are we looking at an autodetection?  Well if that's the case then the module
 
50
 * needs to be found, and that is done with a database lookup through the module DB.  The foreach
 
51
 * function is called, with the parameter being a gpointer array.  It contains both the filename
 
52
 * (to find its extension) and where to write the module when it is found.
 
53
 *
 
54
 * If there is no autodetection, then the module database is queried with the key given.
 
55
 *
 
56
 * If everything is cool at this point, the module is loaded, and there is possibility for
 
57
 * preferences.  If there is a function, then it is executed to get the dialog to be displayed.
 
58
 * After it is finished the function continues.
 
59
 *
 
60
 * Lastly, the open function is called in the module itself.
 
61
 */
 
62
SPDocument *
 
63
open(Extension *key, gchar const *filename)
 
64
{
 
65
    Input *imod = NULL;
 
66
    if (key == NULL) {
 
67
        gpointer parray[2];
 
68
        parray[0] = (gpointer)filename;
 
69
        parray[1] = (gpointer)&imod;
 
70
        db.foreach(open_internal, (gpointer)&parray);
 
71
    } else {
 
72
        imod = dynamic_cast<Input *>(key);
 
73
    }
 
74
 
 
75
    bool last_chance_svg = false;
 
76
    if (key == NULL && imod == NULL) {
 
77
        last_chance_svg = true;
 
78
        imod = dynamic_cast<Input *>(db.get(SP_MODULE_KEY_INPUT_SVG));
 
79
    }
 
80
 
 
81
    if (imod == NULL) {
 
82
        throw Input::no_extension_found();
 
83
    }
 
84
 
 
85
    imod->set_state(Extension::STATE_LOADED);
 
86
 
 
87
    if (!imod->loaded()) {
 
88
        throw Input::open_failed();
 
89
    }
 
90
 
 
91
    if (!imod->prefs(filename))
 
92
        return NULL;
 
93
 
 
94
    SPDocument *doc = imod->open(filename);
 
95
    if (!doc) {
 
96
        throw Input::open_failed();
 
97
    }
 
98
 
 
99
    if (last_chance_svg) {
 
100
        /* We can't call sp_ui_error_dialog because we may be
 
101
           running from the console, in which case calling sp_ui
 
102
           routines will cause a segfault.  See bug 1000350 - bryce */
 
103
        // sp_ui_error_dialog(_("Format autodetect failed. The file is being opened as SVG."));
 
104
        g_warning(_("Format autodetect failed. The file is being opened as SVG."));
 
105
    }
 
106
 
 
107
    /* This kinda overkill as most of these are already set, but I want
 
108
       to make sure for this release -- TJG */
 
109
    doc->setModifiedSinceSave(false);
 
110
 
 
111
    sp_document_set_uri(doc, filename);
 
112
 
 
113
    return doc;
 
114
}
 
115
 
 
116
/**
 
117
 * \return   none
 
118
 * \brief    This is the function that searches each module to see
 
119
 *           if it matches the filename for autodetection.
 
120
 * \param    in_plug  The module to be tested
 
121
 * \param    in_data  An array of pointers containing the filename, and
 
122
 *                    the place to put a successfully found module.
 
123
 *
 
124
 * Basically this function only looks at input modules as it is part of the open function.  If the
 
125
 * module is an input module, it then starts to take it apart, and the data that is passed in.
 
126
 * Because the data being passed in is in such a weird format, there are a few casts to make it
 
127
 * easier to use.  While it looks like a lot of local variables, they'll all get removed by the
 
128
 * compiler.
 
129
 *
 
130
 * First thing that is checked is if the filename is shorter than the extension itself.  There is
 
131
 * no way for a match in that case.  If it's long enough then there is a string compare of the end
 
132
 * of the filename (for the length of the extension), and the extension itself.  If this passes
 
133
 * then the pointer passed in is set to the current module.
 
134
 */
 
135
static void
 
136
open_internal(Extension *in_plug, gpointer in_data)
 
137
{
 
138
    if (!in_plug->deactivated() && dynamic_cast<Input *>(in_plug)) {
 
139
        gpointer *parray = (gpointer *)in_data;
 
140
        gchar const *filename = (gchar const *)parray[0];
 
141
        Input **pimod = (Input **)parray[1];
 
142
 
 
143
        // skip all the rest if we already found a function to open it
 
144
        // since they're ordered by preference now.
 
145
        if (!*pimod) {
 
146
            gchar const *ext = dynamic_cast<Input *>(in_plug)->get_extension();
 
147
 
 
148
            gchar *filenamelower = g_utf8_strdown(filename, -1);
 
149
            gchar *extensionlower = g_utf8_strdown(ext, -1);
 
150
 
 
151
            if (g_str_has_suffix(filenamelower, extensionlower)) {
 
152
                *pimod = dynamic_cast<Input *>(in_plug);
 
153
            }
 
154
 
 
155
            g_free(filenamelower);
 
156
            g_free(extensionlower);
 
157
        }
 
158
    }
 
159
 
 
160
    return;
 
161
}
 
162
 
 
163
/**
 
164
 * \return   None
 
165
 * \brief    This is a generic function to use the save function of
 
166
 *           a module (including Autodetect)
 
167
 * \param    key       Identifier of which module to use
 
168
 * \param    doc       The document to be saved
 
169
 * \param    filename  The file that the document should be saved to
 
170
 * \param    official  (optional) whether to set :output_module and :modified in the
 
171
 *                     document; is true for normal save, false for temporary saves
 
172
 *
 
173
 * First things first, are we looking at an autodetection?  Well if that's the case then the module
 
174
 * needs to be found, and that is done with a database lookup through the module DB.  The foreach
 
175
 * function is called, with the parameter being a gpointer array.  It contains both the filename
 
176
 * (to find its extension) and where to write the module when it is found.
 
177
 *
 
178
 * If there is no autodetection the module database is queried with the key given.
 
179
 *
 
180
 * If everything is cool at this point, the module is loaded, and there is possibility for
 
181
 * preferences.  If there is a function, then it is executed to get the dialog to be displayed.
 
182
 * After it is finished the function continues.
 
183
 *
 
184
 * Lastly, the save function is called in the module itself.
 
185
 */
 
186
void
 
187
save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension, bool check_overwrite, bool official)
 
188
{
 
189
    Output *omod;
 
190
    if (key == NULL) {
 
191
        gpointer parray[2];
 
192
        parray[0] = (gpointer)filename;
 
193
        parray[1] = (gpointer)&omod;
 
194
        omod = NULL;
 
195
        db.foreach(save_internal, (gpointer)&parray);
 
196
 
 
197
        /* This is a nasty hack, but it is required to ensure that
 
198
           autodetect will always save with the Inkscape extensions
 
199
           if they are available. */
 
200
        if (omod != NULL && !strcmp(omod->get_id(), SP_MODULE_KEY_OUTPUT_SVG)) {
 
201
            omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE));
 
202
        }
 
203
        /* If autodetect fails, save as Inkscape SVG */
 
204
        if (omod == NULL) {
 
205
            omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE));
 
206
        }
 
207
    } else {
 
208
        omod = dynamic_cast<Output *>(key);
 
209
    }
 
210
 
 
211
    if (!dynamic_cast<Output *>(omod)) {
 
212
        g_warning("Unable to find output module to handle file: %s\n", filename);
 
213
        throw Output::no_extension_found();
 
214
        return;
 
215
    }
 
216
 
 
217
    omod->set_state(Extension::STATE_LOADED);
 
218
    if (!omod->loaded()) {
 
219
        throw Output::save_failed();
 
220
    }
 
221
 
 
222
    if (!omod->prefs()) {
 
223
        throw Output::save_cancelled();
 
224
    }
 
225
 
 
226
    gchar *fileName = NULL;
 
227
    if (setextension) {
 
228
        gchar *lowerfile = g_utf8_strdown(filename, -1);
 
229
        gchar *lowerext = g_utf8_strdown(omod->get_extension(), -1);
 
230
 
 
231
        if (!g_str_has_suffix(lowerfile, lowerext)) {
 
232
            fileName = g_strdup_printf("%s%s", filename, omod->get_extension());
 
233
        }
 
234
 
 
235
        g_free(lowerfile);
 
236
        g_free(lowerext);
 
237
    }
 
238
 
 
239
    if (fileName == NULL) {
 
240
        fileName = g_strdup(filename);
 
241
    }
 
242
 
 
243
    if (check_overwrite && !sp_ui_overwrite_file(fileName)) {
 
244
        g_free(fileName);
 
245
        throw Output::no_overwrite();
 
246
    }
 
247
 
 
248
    Inkscape::XML::Node *repr = sp_document_repr_root(doc);
 
249
 
 
250
    // remember attributes in case this is an unofficial save
 
251
    bool saved_modified = false;
 
252
    gchar *saved_output_extension = NULL;
 
253
    gchar *saved_dataloss = NULL;
 
254
    if (!official) {
 
255
        saved_modified = doc->isModifiedSinceSave();
 
256
        saved_output_extension = g_strdup(repr->attribute("inkscape:output_extension"));
 
257
        saved_dataloss = g_strdup(repr->attribute("inkscape:dataloss"));
 
258
    } else {
 
259
        /* The document is changing name/uri. */
 
260
        sp_document_change_uri_and_hrefs(doc, fileName);
 
261
    }
 
262
 
 
263
    // Update attributes:
 
264
    {
 
265
        bool const saved = sp_document_get_undo_sensitive(doc);
 
266
        sp_document_set_undo_sensitive(doc, false);
 
267
        {
 
268
            // also save the extension for next use
 
269
            repr->setAttribute("inkscape:output_extension", omod->get_id());
 
270
            // set the "dataloss" attribute if the chosen extension is lossy
 
271
            repr->setAttribute("inkscape:dataloss", NULL);
 
272
            if (omod->causes_dataloss()) {
 
273
                repr->setAttribute("inkscape:dataloss", "true");
 
274
            }
 
275
        }
 
276
        sp_document_set_undo_sensitive(doc, saved);
 
277
        doc->setModifiedSinceSave(false);
 
278
    }
 
279
 
 
280
    omod->save(doc, fileName);
 
281
 
 
282
    // If it is an unofficial save, set the modified attributes back to what they were.
 
283
    if ( !official) {
 
284
        bool const saved = sp_document_get_undo_sensitive(doc);
 
285
        sp_document_set_undo_sensitive(doc, false);
 
286
        {
 
287
            repr->setAttribute("inkscape:output_extension", saved_output_extension);
 
288
            repr->setAttribute("inkscape:dataloss", saved_dataloss);
 
289
        }
 
290
        sp_document_set_undo_sensitive(doc, saved);
 
291
        doc->setModifiedSinceSave(saved_modified);
 
292
 
 
293
        g_free(saved_output_extension);
 
294
        g_free(saved_dataloss);
 
295
    }
 
296
 
 
297
    g_free(fileName);
 
298
    return;
 
299
}
 
300
 
 
301
/**
 
302
 * \return   none
 
303
 * \brief    This is the function that searches each module to see
 
304
 *           if it matches the filename for autodetection.
 
305
 * \param    in_plug  The module to be tested
 
306
 * \param    in_data  An array of pointers containing the filename, and
 
307
 *                    the place to put a successfully found module.
 
308
 *
 
309
 * Basically this function only looks at output modules as it is part of the open function.  If the
 
310
 * module is an output module, it then starts to take it apart, and the data that is passed in.
 
311
 * Because the data being passed in is in such a weird format, there are a few casts to make it
 
312
 * easier to use.  While it looks like a lot of local variables, they'll all get removed by the
 
313
 * compiler.
 
314
 *
 
315
 * First thing that is checked is if the filename is shorter than the extension itself.  There is
 
316
 * no way for a match in that case.  If it's long enough then there is a string compare of the end
 
317
 * of the filename (for the length of the extension), and the extension itself.  If this passes
 
318
 * then the pointer passed in is set to the current module.
 
319
 */
 
320
static void
 
321
save_internal(Extension *in_plug, gpointer in_data)
 
322
{
 
323
    if (!in_plug->deactivated() && dynamic_cast<Output *>(in_plug)) {
 
324
        gpointer *parray = (gpointer *)in_data;
 
325
        gchar const *filename = (gchar const *)parray[0];
 
326
        Output **pomod = (Output **)parray[1];
 
327
 
 
328
        // skip all the rest if we already found someone to save it
 
329
        // since they're ordered by preference now.
 
330
        if (!*pomod) {
 
331
            gchar const *ext = dynamic_cast<Output *>(in_plug)->get_extension();
 
332
 
 
333
            gchar *filenamelower = g_utf8_strdown(filename, -1);
 
334
            gchar *extensionlower = g_utf8_strdown(ext, -1);
 
335
 
 
336
            if (g_str_has_suffix(filenamelower, extensionlower)) {
 
337
                *pomod = dynamic_cast<Output *>(in_plug);
 
338
            }
 
339
 
 
340
            g_free(filenamelower);
 
341
            g_free(extensionlower);
 
342
        }
 
343
    }
 
344
 
 
345
    return;
 
346
}
 
347
 
 
348
Print *
 
349
get_print(gchar const *key)
 
350
{
 
351
    return dynamic_cast<Print *>(db.get(key));
 
352
}
 
353
 
 
354
/**
 
355
 * \return   The built module
 
356
 * \brief    Creates a module from a Inkscape::XML::Document describing the module
 
357
 * \param    doc  The XML description of the module
 
358
 *
 
359
 * This function basically has two segments.  The first is that it goes through the Repr tree
 
360
 * provided, and determines what kind of of module this is, and what kind of implementation to use.
 
361
 * All of these are then stored in two enums that are defined in this function.  This makes it
 
362
 * easier to add additional types (which will happen in the future, I'm sure).
 
363
 *
 
364
 * Second, there is case statements for these enums.  The first one is the type of module.  This is
 
365
 * the one where the module is actually created.  After that, then the implementation is applied to
 
366
 * get the load and unload functions.  If there is no implementation then these are not set.  This
 
367
 * case could apply to modules that are built in (like the SVG load/save functions).
 
368
 */
 
369
static Extension *
 
370
build_from_reprdoc(Inkscape::XML::Document *doc, Implementation::Implementation *in_imp)
 
371
{
 
372
    enum {
 
373
        MODULE_EXTENSION,
 
374
        MODULE_XSLT,
 
375
        /* MODULE_PLUGIN, */
 
376
        MODULE_UNKNOWN_IMP
 
377
    } module_implementation_type = MODULE_UNKNOWN_IMP;
 
378
    enum {
 
379
        MODULE_INPUT,
 
380
        MODULE_OUTPUT,
 
381
        MODULE_FILTER,
 
382
        MODULE_PRINT,
 
383
        MODULE_PATH_EFFECT,
 
384
        MODULE_UNKNOWN_FUNC
 
385
    } module_functional_type = MODULE_UNKNOWN_FUNC;
 
386
 
 
387
    g_return_val_if_fail(doc != NULL, NULL);
 
388
 
 
389
    Inkscape::XML::Node *repr = doc->root();
 
390
 
 
391
    if (strcmp(repr->name(), INKSCAPE_EXTENSION_NS "inkscape-extension")) {
 
392
        g_warning("Extension definition started with <%s> instead of <" INKSCAPE_EXTENSION_NS "inkscape-extension>.  Extension will not be created. See http://wiki.inkscape.org/wiki/index.php/Extensions for reference.\n", repr->name());
 
393
        return NULL;
 
394
    }
 
395
 
 
396
    Inkscape::XML::Node *child_repr = sp_repr_children(repr);
 
397
    while (child_repr != NULL) {
 
398
        char const *element_name = child_repr->name();
 
399
        /* printf("Child: %s\n", child_repr->name()); */
 
400
        if (!strcmp(element_name, INKSCAPE_EXTENSION_NS "input")) {
 
401
            module_functional_type = MODULE_INPUT;
 
402
        } else if (!strcmp(element_name, INKSCAPE_EXTENSION_NS "output")) {
 
403
            module_functional_type = MODULE_OUTPUT;
 
404
        } else if (!strcmp(element_name, INKSCAPE_EXTENSION_NS "effect")) {
 
405
            module_functional_type = MODULE_FILTER;
 
406
        } else if (!strcmp(element_name, INKSCAPE_EXTENSION_NS "print")) {
 
407
            module_functional_type = MODULE_PRINT;
 
408
        } else if (!strcmp(element_name, INKSCAPE_EXTENSION_NS "path-effect")) {
 
409
            module_functional_type = MODULE_PATH_EFFECT;
 
410
        } else if (!strcmp(element_name, INKSCAPE_EXTENSION_NS "script")) {
 
411
            module_implementation_type = MODULE_EXTENSION;
 
412
        } else if (!strcmp(element_name, INKSCAPE_EXTENSION_NS "xslt")) {
 
413
            module_implementation_type = MODULE_XSLT;
 
414
#if 0
 
415
        } else if (!strcmp(element_name, "plugin")) {
 
416
            module_implementation_type = MODULE_PLUGIN;
 
417
#endif
 
418
        }
 
419
 
 
420
        //Inkscape::XML::Node *old_repr = child_repr;
 
421
        child_repr = sp_repr_next(child_repr);
 
422
        //Inkscape::GC::release(old_repr);
 
423
    }
 
424
 
 
425
    Implementation::Implementation *imp;
 
426
    if (in_imp == NULL) {
 
427
        switch (module_implementation_type) {
 
428
            case MODULE_EXTENSION: {
 
429
                Implementation::Script *script = new Implementation::Script();
 
430
                imp = static_cast<Implementation::Implementation *>(script);
 
431
                break;
 
432
            }
 
433
            case MODULE_XSLT: {
 
434
                Implementation::XSLT *xslt = new Implementation::XSLT();
 
435
                imp = static_cast<Implementation::Implementation *>(xslt);
 
436
                break;
 
437
            }
 
438
#if 0
 
439
            case MODULE_PLUGIN: {
 
440
                Implementation::Plugin *plugin = new Implementation::Plugin();
 
441
                imp = static_cast<Implementation::Implementation *>(plugin);
 
442
                break;
 
443
            }
 
444
#endif
 
445
            default: {
 
446
                imp = NULL;
 
447
                break;
 
448
            }
 
449
        }
 
450
    } else {
 
451
        imp = in_imp;
 
452
    }
 
453
 
 
454
    Extension *module = NULL;
 
455
    switch (module_functional_type) {
 
456
        case MODULE_INPUT: {
 
457
            module = new Input(repr, imp);
 
458
            break;
 
459
        }
 
460
        case MODULE_OUTPUT: {
 
461
            module = new Output(repr, imp);
 
462
            break;
 
463
        }
 
464
        case MODULE_FILTER: {
 
465
            module = new Effect(repr, imp);
 
466
            break;
 
467
        }
 
468
        case MODULE_PRINT: {
 
469
            module = new Print(repr, imp);
 
470
            break;
 
471
        }
 
472
        case MODULE_PATH_EFFECT: {
 
473
            module = new PathEffect(repr, imp);
 
474
            break;
 
475
        }
 
476
        default: {
 
477
            break;
 
478
        }
 
479
    }
 
480
 
 
481
    return module;
 
482
}
 
483
 
 
484
/**
 
485
 * \return   The module created
 
486
 * \brief    This function creates a module from a filename of an
 
487
 *           XML description.
 
488
 * \param    filename  The file holding the XML description of the module.
 
489
 *
 
490
 * This function calls build_from_reprdoc with using sp_repr_read_file to create the reprdoc.
 
491
 */
 
492
Extension *
 
493
build_from_file(gchar const *filename)
 
494
{
 
495
    Inkscape::XML::Document *doc = sp_repr_read_file(filename, INKSCAPE_EXTENSION_URI);
 
496
    Extension *ext = build_from_reprdoc(doc, NULL);
 
497
    if (ext != NULL)
 
498
        Inkscape::GC::release(doc);
 
499
    else
 
500
        g_warning("Unable to create extension from definition file %s.\n", filename);
 
501
    return ext;
 
502
}
 
503
 
 
504
/**
 
505
 * \return   The module created
 
506
 * \brief    This function creates a module from a buffer holding an
 
507
 *           XML description.
 
508
 * \param    buffer  The buffer holding the XML description of the module.
 
509
 *
 
510
 * This function calls build_from_reprdoc with using sp_repr_read_mem to create the reprdoc.  It
 
511
 * finds the length of the buffer using strlen.
 
512
 */
 
513
Extension *
 
514
build_from_mem(gchar const *buffer, Implementation::Implementation *in_imp)
 
515
{
 
516
    Inkscape::XML::Document *doc = sp_repr_read_mem(buffer, strlen(buffer), INKSCAPE_EXTENSION_URI);
 
517
    Extension *ext = build_from_reprdoc(doc, in_imp);
 
518
    Inkscape::GC::release(doc);
 
519
    return ext;
 
520
}
 
521
 
 
522
 
 
523
} } /* namespace Inkscape::Extension */
 
524
 
 
525
/*
 
526
  Local Variables:
 
527
  mode:c++
 
528
  c-file-style:"stroustrup"
 
529
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
530
  indent-tabs-mode:nil
 
531
  fill-column:99
 
532
  End:
 
533
*/
 
534
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :