1 /** @file
2 * @brief Parameters for extensions.
3 */
4 /* Author:
5 * Ted Gould <ted@gould.cx>
6 * Johan Engelen <johan@shouraizou.nl>
7 *
8 * Copyright (C) 2005-2007 Authors
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
17 #ifdef linux // does the dollar sign need escaping when passed as string parameter?
18 # define ESCAPE_DOLLAR_COMMANDLINE
19 #endif
21 #include <gtkmm/adjustment.h>
22 #include <gtkmm/box.h>
23 #include <gtkmm/spinbutton.h>
25 #include <xml/node.h>
27 #include <extension/extension.h>
28 #include "document-private.h"
29 #include "sp-object.h"
30 #include <color.h>
31 #include "widgets/sp-color-selector.h"
32 #include "widgets/sp-color-notebook.h"
34 #include "parameter.h"
35 #include "bool.h"
36 #include "color.h"
37 #include "description.h"
38 #include "enum.h"
39 #include "float.h"
40 #include "int.h"
41 #include "notebook.h"
42 #include "radiobutton.h"
43 #include "string.h"
45 namespace Inkscape {
46 namespace Extension {
48 /**
49 \return None
50 \brief This function creates a parameter that can be used later. This
51 is typically done in the creation of the extension and defined
52 in the XML file describing the extension (it's private so people
53 have to use the system) :)
54 \param in_repr The XML describing the parameter
56 This function first grabs all of the data out of the Repr and puts
57 it into local variables. Actually, these are just pointers, and the
58 data is not duplicated so we need to be careful with it. If there
59 isn't a name or a type in the XML, then no parameter is created as
60 the function just returns.
62 From this point on, we're pretty committed as we've allocated an
63 object and we're starting to fill it. The name is set first, and
64 is created with a strdup to actually allocate memory for it. Then
65 there is a case statement (roughly because strcmp requires 'ifs')
66 based on what type of parameter this is. Depending which type it
67 is, the value is interpreted differently, but they are relatively
68 straight forward. In all cases the value is set to the default
69 value from the XML and the type is set to the interpreted type.
70 */
71 Parameter *
72 Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext)
73 {
74 const char * name;
75 const char * type;
76 const char * guitext;
77 const char * desc;
78 const char * scope_str;
79 Parameter::_scope_t scope = Parameter::SCOPE_USER;
80 bool gui_hidden = false;
81 const char * gui_hide;
82 const char * gui_tip;
84 name = in_repr->attribute("name");
85 type = in_repr->attribute("type");
86 guitext = in_repr->attribute("gui-text");
87 if (guitext == NULL)
88 guitext = in_repr->attribute("_gui-text");
89 gui_tip = in_repr->attribute("gui-tip");
90 if (gui_tip == NULL)
91 gui_tip = in_repr->attribute("_gui-tip");
92 desc = in_repr->attribute("gui-description");
93 if (desc == NULL)
94 desc = in_repr->attribute("_gui-description");
95 scope_str = in_repr->attribute("scope");
96 gui_hide = in_repr->attribute("gui-hidden");
97 if (gui_hide != NULL) {
98 if (strcmp(gui_hide, "1") == 0 ||
99 strcmp(gui_hide, "true") == 0) {
100 gui_hidden = true;
101 }
102 /* else stays false */
103 }
104 const gchar* appearance = in_repr->attribute("appearance");
106 /* In this case we just don't have enough information */
107 if (name == NULL || type == NULL) {
108 return NULL;
109 }
111 if (scope_str != NULL) {
112 if (!strcmp(scope_str, "user")) {
113 scope = Parameter::SCOPE_USER;
114 } else if (!strcmp(scope_str, "document")) {
115 scope = Parameter::SCOPE_DOCUMENT;
116 } else if (!strcmp(scope_str, "node")) {
117 scope = Parameter::SCOPE_NODE;
118 }
119 }
121 Parameter * param = NULL;
122 if (!strcmp(type, "boolean")) {
123 param = new ParamBool(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
124 } else if (!strcmp(type, "int")) {
125 param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
126 } else if (!strcmp(type, "float")) {
127 param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
128 } else if (!strcmp(type, "string")) {
129 param = new ParamString(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
130 const gchar * max_length = in_repr->attribute("max_length");
131 if (max_length != NULL) {
132 ParamString * ps = dynamic_cast<ParamString *>(param);
133 ps->setMaxLength(atoi(max_length));
134 }
135 } else if (!strcmp(type, "description")) {
136 param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
137 } else if (!strcmp(type, "enum")) {
138 param = new ParamComboBox(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
139 } else if (!strcmp(type, "notebook")) {
140 param = new ParamNotebook(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
141 } else if (!strcmp(type, "optiongroup")) {
142 if (appearance && !strcmp(appearance, "minimal")) {
143 param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamRadioButton::MINIMAL);
144 } else {
145 param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamRadioButton::FULL);
146 }
147 } else if (!strcmp(type, "color")) {
148 param = new ParamColor(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
149 }
151 /* Note: param could equal NULL */
152 return param;
153 }
157 /** \brief Wrapper to cast to the object and use it's function. */
158 bool
159 Parameter::get_bool (const SPDocument * doc, const Inkscape::XML::Node * node)
160 {
161 ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
162 if (boolpntr == NULL)
163 throw Extension::param_not_bool_param();
164 return boolpntr->get(doc, node);
165 }
167 /** \brief Wrapper to cast to the object and use it's function. */
168 int
169 Parameter::get_int (const SPDocument * doc, const Inkscape::XML::Node * node)
170 {
171 ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
172 if (intpntr == NULL)
173 throw Extension::param_not_int_param();
174 return intpntr->get(doc, node);
175 }
177 /** \brief Wrapper to cast to the object and use it's function. */
178 float
179 Parameter::get_float (const SPDocument * doc, const Inkscape::XML::Node * node)
180 {
181 ParamFloat * floatpntr = dynamic_cast<ParamFloat *>(this);
182 if (floatpntr == NULL)
183 throw Extension::param_not_float_param();
184 return floatpntr->get(doc, node);
185 }
187 /** \brief Wrapper to cast to the object and use it's function. */
188 const gchar *
189 Parameter::get_string (const SPDocument * doc, const Inkscape::XML::Node * node)
190 {
191 ParamString * stringpntr = dynamic_cast<ParamString *>(this);
192 if (stringpntr == NULL)
193 throw Extension::param_not_string_param();
194 return stringpntr->get(doc, node);
195 }
197 /** \brief Wrapper to cast to the object and use it's function. */
198 const gchar *
199 Parameter::get_enum (const SPDocument * doc, const Inkscape::XML::Node * node)
200 {
201 ParamComboBox * param = dynamic_cast<ParamComboBox *>(this);
202 if (param == NULL)
203 throw Extension::param_not_enum_param();
204 return param->get(doc, node);
205 }
207 guint32
208 Parameter::get_color(const SPDocument* doc, const Inkscape::XML::Node* node)
209 {
210 ParamColor* param = dynamic_cast<ParamColor *>(this);
211 if (param == NULL)
212 throw Extension::param_not_color_param();
213 return param->get(doc, node);
214 }
216 /** \brief Wrapper to cast to the object and use it's function. */
217 bool
218 Parameter::set_bool (bool in, SPDocument * doc, Inkscape::XML::Node * node)
219 {
220 ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
221 if (boolpntr == NULL)
222 throw Extension::param_not_bool_param();
223 return boolpntr->set(in, doc, node);
224 }
226 /** \brief Wrapper to cast to the object and use it's function. */
227 int
228 Parameter::set_int (int in, SPDocument * doc, Inkscape::XML::Node * node)
229 {
230 ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
231 if (intpntr == NULL)
232 throw Extension::param_not_int_param();
233 return intpntr->set(in, doc, node);
234 }
236 /** \brief Wrapper to cast to the object and use it's function. */
237 float
238 Parameter::set_float (float in, SPDocument * doc, Inkscape::XML::Node * node)
239 {
240 ParamFloat * floatpntr;
241 floatpntr = dynamic_cast<ParamFloat *>(this);
242 if (floatpntr == NULL)
243 throw Extension::param_not_float_param();
244 return floatpntr->set(in, doc, node);
245 }
247 /** \brief Wrapper to cast to the object and use it's function. */
248 const gchar *
249 Parameter::set_string (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
250 {
251 ParamString * stringpntr = dynamic_cast<ParamString *>(this);
252 if (stringpntr == NULL)
253 throw Extension::param_not_string_param();
254 return stringpntr->set(in, doc, node);
255 }
256 /** \brief Wrapper to cast to the object and use it's function. */
257 guint32
258 Parameter::set_color (guint32 in, SPDocument * doc, Inkscape::XML::Node * node)
259 {
260 ParamColor* param = dynamic_cast<ParamColor *>(this);
261 if (param == NULL)
262 throw Extension::param_not_color_param();
263 return param->set(in, doc, node);
264 }
267 /** \brief Oop, now that we need a parameter, we need it's name. */
268 Parameter::Parameter (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext) :
269 extension(ext), _name(NULL), _desc(NULL), _scope(scope), _text(NULL), _gui_hidden(gui_hidden), _gui_tip(NULL)
270 {
271 if (name != NULL) {
272 _name = g_strdup(name);
273 }
274 if (desc != NULL) {
275 _desc = g_strdup(desc);
276 // printf("Adding description: '%s' on '%s'\n", _desc, _name);
277 }
278 if (gui_tip != NULL) {
279 _gui_tip = g_strdup(gui_tip);
280 }
283 if (guitext != NULL)
284 _text = g_strdup(guitext);
285 else
286 _text = g_strdup(name);
288 return;
289 }
291 /** \brief Just free the allocated name. */
292 Parameter::~Parameter (void)
293 {
294 g_free(_name);
295 g_free(_text);
296 g_free(_gui_tip);
297 }
299 /** \brief Build the name to write the parameter from the extension's
300 ID and the name of this parameter. */
301 gchar *
302 Parameter::pref_name (void)
303 {
304 return g_strdup_printf("%s.%s", extension->get_id(), _name);
305 }
307 Inkscape::XML::Node *
308 Parameter::find_child (Inkscape::XML::Node * adult)
309 {
310 return sp_repr_lookup_child(adult, "name", _name);
311 }
313 Inkscape::XML::Node *
314 Parameter::new_child (Inkscape::XML::Node * parent)
315 {
316 Inkscape::XML::Node * retval;
317 retval = parent->document()->createElement("inkscape:extension-param");
318 retval->setAttribute("name", _name);
320 parent->appendChild(retval);
321 Inkscape::GC::release(retval);
322 return retval;
323 }
325 Inkscape::XML::Node *
326 Parameter::document_param_node (SPDocument * doc)
327 {
328 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
329 Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc));
330 Inkscape::XML::Node * params = NULL;
332 GQuark const name_quark = g_quark_from_string("inkscape:extension-params");
334 for (Inkscape::XML::Node * child = defs->firstChild();
335 child != NULL;
336 child = child->next()) {
337 if ((GQuark)child->code() == name_quark &&
338 !strcmp(child->attribute("extension"), extension->get_id())) {
339 params = child;
340 break;
341 }
342 }
344 if (params == NULL) {
345 params = xml_doc->createElement("inkscape:extension-param");
346 params->setAttribute("extension", extension->get_id());
347 defs->appendChild(params);
348 Inkscape::GC::release(params);
349 }
351 return params;
352 }
354 /** \brief Basically, if there is no widget pass a NULL. */
355 Gtk::Widget *
356 Parameter::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/, sigc::signal<void> * /*changeSignal*/)
357 {
358 return NULL;
359 }
361 /** \brief If I'm not sure which it is, just don't return a value. */
362 void
363 Parameter::string (std::string &/*string*/)
364 {
365 return;
366 }
368 void
369 Parameter::string (std::list <std::string> &list)
370 {
371 std::string value;
372 string(value);
373 if (value == "") {
374 return;
375 }
377 std::string final;
378 final += "--";
379 final += name();
380 final += "=";
381 final += value;
383 list.insert(list.end(), final);
384 return;
385 }
387 Glib::ustring const extension_pref_root = "/extensions/";
389 } /* namespace Extension */
390 } /* namespace Inkscape */
392 /*
393 Local Variables:
394 mode:c++
395 c-file-style:"stroustrup"
396 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
397 indent-tabs-mode:nil
398 fill-column:99
399 End:
400 */
401 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :