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.
8
* Ted Gould <ted@gould.cx>
9
* Johan Engelen <johan@shouraizou.nl>
11
* Copyright (C) 2006-2007 Johan Engelen
12
* Copyright (C) 2002-2004 Ted Gould
14
* Released under GNU GPL, read the file 'COPYING' for more information
21
#include <interface.h>
23
#include "extension.h"
28
#include "patheffect.h"
30
#include "implementation/script.h"
31
#include "implementation/xslt.h"
32
#include "xml/rebase-hrefs.h"
33
/* #include "implementation/plugin.h" */
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);
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
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.
54
* If there is no autodetection, then the module database is queried with the key given.
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.
60
* Lastly, the open function is called in the module itself.
63
open(Extension *key, gchar const *filename)
68
parray[0] = (gpointer)filename;
69
parray[1] = (gpointer)&imod;
70
db.foreach(open_internal, (gpointer)&parray);
72
imod = dynamic_cast<Input *>(key);
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));
82
throw Input::no_extension_found();
85
imod->set_state(Extension::STATE_LOADED);
87
if (!imod->loaded()) {
88
throw Input::open_failed();
91
if (!imod->prefs(filename))
94
SPDocument *doc = imod->open(filename);
96
throw Input::open_failed();
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."));
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);
111
sp_document_set_uri(doc, filename);
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.
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
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.
136
open_internal(Extension *in_plug, gpointer in_data)
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];
143
// skip all the rest if we already found a function to open it
144
// since they're ordered by preference now.
146
gchar const *ext = dynamic_cast<Input *>(in_plug)->get_extension();
148
gchar *filenamelower = g_utf8_strdown(filename, -1);
149
gchar *extensionlower = g_utf8_strdown(ext, -1);
151
if (g_str_has_suffix(filenamelower, extensionlower)) {
152
*pimod = dynamic_cast<Input *>(in_plug);
155
g_free(filenamelower);
156
g_free(extensionlower);
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
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.
178
* If there is no autodetection the module database is queried with the key given.
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.
184
* Lastly, the save function is called in the module itself.
187
save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension, bool check_overwrite, bool official)
192
parray[0] = (gpointer)filename;
193
parray[1] = (gpointer)&omod;
195
db.foreach(save_internal, (gpointer)&parray);
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));
203
/* If autodetect fails, save as Inkscape SVG */
205
omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE));
208
omod = dynamic_cast<Output *>(key);
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();
217
omod->set_state(Extension::STATE_LOADED);
218
if (!omod->loaded()) {
219
throw Output::save_failed();
222
if (!omod->prefs()) {
223
throw Output::save_cancelled();
226
gchar *fileName = NULL;
228
gchar *lowerfile = g_utf8_strdown(filename, -1);
229
gchar *lowerext = g_utf8_strdown(omod->get_extension(), -1);
231
if (!g_str_has_suffix(lowerfile, lowerext)) {
232
fileName = g_strdup_printf("%s%s", filename, omod->get_extension());
239
if (fileName == NULL) {
240
fileName = g_strdup(filename);
243
if (check_overwrite && !sp_ui_overwrite_file(fileName)) {
245
throw Output::no_overwrite();
248
Inkscape::XML::Node *repr = sp_document_repr_root(doc);
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;
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"));
259
/* The document is changing name/uri. */
260
sp_document_change_uri_and_hrefs(doc, fileName);
263
// Update attributes:
265
bool const saved = sp_document_get_undo_sensitive(doc);
266
sp_document_set_undo_sensitive(doc, false);
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");
276
sp_document_set_undo_sensitive(doc, saved);
277
doc->setModifiedSinceSave(false);
280
omod->save(doc, fileName);
282
// If it is an unofficial save, set the modified attributes back to what they were.
284
bool const saved = sp_document_get_undo_sensitive(doc);
285
sp_document_set_undo_sensitive(doc, false);
287
repr->setAttribute("inkscape:output_extension", saved_output_extension);
288
repr->setAttribute("inkscape:dataloss", saved_dataloss);
290
sp_document_set_undo_sensitive(doc, saved);
291
doc->setModifiedSinceSave(saved_modified);
293
g_free(saved_output_extension);
294
g_free(saved_dataloss);
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.
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
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.
321
save_internal(Extension *in_plug, gpointer in_data)
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];
328
// skip all the rest if we already found someone to save it
329
// since they're ordered by preference now.
331
gchar const *ext = dynamic_cast<Output *>(in_plug)->get_extension();
333
gchar *filenamelower = g_utf8_strdown(filename, -1);
334
gchar *extensionlower = g_utf8_strdown(ext, -1);
336
if (g_str_has_suffix(filenamelower, extensionlower)) {
337
*pomod = dynamic_cast<Output *>(in_plug);
340
g_free(filenamelower);
341
g_free(extensionlower);
349
get_print(gchar const *key)
351
return dynamic_cast<Print *>(db.get(key));
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
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).
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).
370
build_from_reprdoc(Inkscape::XML::Document *doc, Implementation::Implementation *in_imp)
377
} module_implementation_type = MODULE_UNKNOWN_IMP;
385
} module_functional_type = MODULE_UNKNOWN_FUNC;
387
g_return_val_if_fail(doc != NULL, NULL);
389
Inkscape::XML::Node *repr = doc->root();
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());
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;
415
} else if (!strcmp(element_name, "plugin")) {
416
module_implementation_type = MODULE_PLUGIN;
420
//Inkscape::XML::Node *old_repr = child_repr;
421
child_repr = sp_repr_next(child_repr);
422
//Inkscape::GC::release(old_repr);
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);
434
Implementation::XSLT *xslt = new Implementation::XSLT();
435
imp = static_cast<Implementation::Implementation *>(xslt);
439
case MODULE_PLUGIN: {
440
Implementation::Plugin *plugin = new Implementation::Plugin();
441
imp = static_cast<Implementation::Implementation *>(plugin);
454
Extension *module = NULL;
455
switch (module_functional_type) {
457
module = new Input(repr, imp);
460
case MODULE_OUTPUT: {
461
module = new Output(repr, imp);
464
case MODULE_FILTER: {
465
module = new Effect(repr, imp);
469
module = new Print(repr, imp);
472
case MODULE_PATH_EFFECT: {
473
module = new PathEffect(repr, imp);
485
* \return The module created
486
* \brief This function creates a module from a filename of an
488
* \param filename The file holding the XML description of the module.
490
* This function calls build_from_reprdoc with using sp_repr_read_file to create the reprdoc.
493
build_from_file(gchar const *filename)
495
Inkscape::XML::Document *doc = sp_repr_read_file(filename, INKSCAPE_EXTENSION_URI);
496
Extension *ext = build_from_reprdoc(doc, NULL);
498
Inkscape::GC::release(doc);
500
g_warning("Unable to create extension from definition file %s.\n", filename);
505
* \return The module created
506
* \brief This function creates a module from a buffer holding an
508
* \param buffer The buffer holding the XML description of the module.
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.
514
build_from_mem(gchar const *buffer, Implementation::Implementation *in_imp)
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);
523
} } /* namespace Inkscape::Extension */
528
c-file-style:"stroustrup"
529
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
534
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :