1 /*
2 * Copyright (C) 2008 Authors:
3 * Ted Gould <ted@gould.cx>
4 *
5 * Released under GNU GPL, read the file 'COPYING' for more information
6 */
8 #include "filter.h"
10 #include "io/sys.h"
11 #include "io/inkscapestream.h"
13 /* Directory includes */
14 #include "path-prefix.h"
15 #include "inkscape.h"
17 /* Extension */
18 #include "extension/extension.h"
19 #include "extension/system.h"
21 /* System includes */
22 #include <glibmm/i18n.h>
24 namespace Inkscape {
25 namespace Extension {
26 namespace Internal {
27 namespace Filter {
29 void
30 Filter::filters_all_files (void)
31 {
32 filters_load_dir(INKSCAPE_FILTERDIR, _("Bundled"));
33 filters_load_dir(profile_path("filters"), _("Personal"));
35 return;
36 }
38 #define INKSCAPE_FILTER_FILE ".svg"
40 void
41 Filter::filters_load_dir (gchar const * dirname, gchar * menuname)
42 {
43 if (!dirname) {
44 g_warning(_("Null external module directory name. Filters will not be loaded."));
45 return;
46 }
48 if (!Glib::file_test(std::string(dirname), Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_DIR)) {
49 return;
50 }
52 GError *err;
53 GDir *directory = g_dir_open(dirname, 0, &err);
54 if (!directory) {
55 gchar *safeDir = Inkscape::IO::sanitizeString(dirname);
56 g_warning(_("Modules directory (%s) is unavailable. External modules in that directory will not be loaded."), safeDir);
57 g_free(safeDir);
58 return;
59 }
61 gchar *filename;
62 while ((filename = (gchar *)g_dir_read_name(directory)) != NULL) {
63 if (strlen(filename) < strlen(INKSCAPE_FILTER_FILE)) {
64 continue;
65 }
67 if (strcmp(INKSCAPE_FILTER_FILE, filename + (strlen(filename) - strlen(INKSCAPE_FILTER_FILE)))) {
68 continue;
69 }
71 gchar *pathname = g_build_filename(dirname, filename, NULL);
72 filters_load_file(pathname, menuname);
73 g_free(pathname);
74 }
76 g_dir_close(directory);
78 return;
79 }
81 void
82 Filter::filters_load_file (gchar * filename, gchar * menuname)
83 {
84 Inkscape::XML::Document *doc = sp_repr_read_file(filename, INKSCAPE_EXTENSION_URI);
85 if (doc == NULL) {
86 g_warning("File (%s) is not parseable as XML. Ignored.", filename);
87 return;
88 }
90 Inkscape::XML::Node * root = doc->root();
91 if (strcmp(root->name(), "svg:svg")) {
92 Inkscape::GC::release(doc);
93 g_warning("File (%s) is not SVG. Ignored.", filename);
94 return;
95 }
97 for (Inkscape::XML::Node * child = root->firstChild();
98 child != NULL; child = child->next()) {
99 if (!strcmp(child->name(), "svg:defs")) {
100 for (Inkscape::XML::Node * defs = child->firstChild();
101 defs != NULL; defs = defs->next()) {
102 if (!strcmp(defs->name(), "svg:filter")) {
103 filters_load_node(defs, menuname);
104 } // oh! a filter
105 } //defs
106 } // is defs
107 } // children of root
109 Inkscape::GC::release(doc);
110 return;
111 }
113 #include "extension/internal/clear-n_.h"
115 class mywriter : public Inkscape::IO::BasicWriter {
116 Glib::ustring _str;
117 public:
118 void close(void);
119 void flush(void);
120 void put (gunichar ch);
121 gchar const * c_str (void) { return _str.c_str(); }
122 };
124 void mywriter::close (void) { return; }
125 void mywriter::flush (void) { return; }
126 void mywriter::put (gunichar ch) { _str += ch; }
129 void
130 Filter::filters_load_node (Inkscape::XML::Node * node, gchar * menuname)
131 {
132 gchar const * label = node->attribute("inkscape:label");
133 gchar const * menu = node->attribute("inkscape:menu");
134 gchar const * menu_tooltip = node->attribute("inkscape:menu-tooltip");
135 gchar const * id = node->attribute("id");
137 if (label == NULL) {
138 label = id;
139 }
141 gchar * xml_str = g_strdup_printf(
142 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
143 "<name>%s</name>\n"
144 "<id>org.inkscape.effect.filter.%s</id>\n"
145 "<effect>\n"
146 "<object-type>all</object-type>\n"
147 "<effects-menu>\n"
148 "<submenu name=\"" N_("Filters") "\">\n"
149 "<submenu name=\"%s\"/>\n"
150 "</submenu>\n"
151 "</effects-menu>\n"
152 "<menu-tip>%s</menu-tip>\n"
153 "</effect>\n"
154 "</inkscape-extension>\n", label, id, menu? menu : menuname, menu_tooltip? menu_tooltip : label);
156 // FIXME: Bad hack: since we pull out a single filter node out of SVG file and
157 // serialize it, it loses the namespace declarations from the root, so we must provide
158 // one right here for our inkscape attributes
159 node->setAttribute("xmlns:inkscape", SP_INKSCAPE_NS_URI);
161 mywriter writer;
162 sp_repr_write_stream(node, writer, 0, FALSE, g_quark_from_static_string("svg"), 0, 0);
164 Inkscape::Extension::build_from_mem(xml_str, new Filter(g_strdup(writer.c_str())));
165 g_free(xml_str);
166 return;
167 }
169 }; /* namespace Filter */
170 }; /* namespace Internal */
171 }; /* namespace Extension */
172 }; /* namespace Inkscape */