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 "groupheader.h"
39 #include "enum.h"
40 #include "float.h"
41 #include "int.h"
42 #include "notebook.h"
43 #include "radiobutton.h"
44 #include "string.h"
46 namespace Inkscape {
47 namespace Extension {
49 /**
50 \return None
51 \brief This function creates a parameter that can be used later. This
52 is typically done in the creation of the extension and defined
53 in the XML file describing the extension (it's private so people
54 have to use the system) :)
55 \param in_repr The XML describing the parameter
57 This function first grabs all of the data out of the Repr and puts
58 it into local variables. Actually, these are just pointers, and the
59 data is not duplicated so we need to be careful with it. If there
60 isn't a name or a type in the XML, then no parameter is created as
61 the function just returns.
63 From this point on, we're pretty committed as we've allocated an
64 object and we're starting to fill it. The name is set first, and
65 is created with a strdup to actually allocate memory for it. Then
66 there is a case statement (roughly because strcmp requires 'ifs')
67 based on what type of parameter this is. Depending which type it
68 is, the value is interpreted differently, but they are relatively
69 straight forward. In all cases the value is set to the default
70 value from the XML and the type is set to the interpreted type.
71 */
72 Parameter *
73 Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext)
74 {
75 const char * name;
76 const char * type;
77 const char * guitext;
78 const char * desc;
79 const char * scope_str;
80 Parameter::_scope_t scope = Parameter::SCOPE_USER;
81 bool gui_hidden = false;
82 const char * gui_hide;
83 const char * gui_tip;
85 name = in_repr->attribute("name");
86 type = in_repr->attribute("type");
87 guitext = in_repr->attribute("gui-text");
88 if (guitext == NULL)
89 guitext = in_repr->attribute("_gui-text");
90 gui_tip = in_repr->attribute("gui-tip");
91 if (gui_tip == NULL)
92 gui_tip = in_repr->attribute("_gui-tip");
93 desc = in_repr->attribute("gui-description");
94 if (desc == NULL)
95 desc = in_repr->attribute("_gui-description");
96 scope_str = in_repr->attribute("scope");
97 gui_hide = in_repr->attribute("gui-hidden");
98 if (gui_hide != NULL) {
99 if (strcmp(gui_hide, "1") == 0 ||
100 strcmp(gui_hide, "true") == 0) {
101 gui_hidden = true;
102 }
103 /* else stays false */
104 }
105 const gchar* appearance = in_repr->attribute("appearance");
107 /* In this case we just don't have enough information */
108 if (name == NULL || type == NULL) {
109 return NULL;
110 }
112 if (scope_str != NULL) {
113 if (!strcmp(scope_str, "user")) {
114 scope = Parameter::SCOPE_USER;
115 } else if (!strcmp(scope_str, "document")) {
116 scope = Parameter::SCOPE_DOCUMENT;
117 } else if (!strcmp(scope_str, "node")) {
118 scope = Parameter::SCOPE_NODE;
119 }
120 }
122 Parameter * param = NULL;
123 if (!strcmp(type, "boolean")) {
124 param = new ParamBool(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
125 } else if (!strcmp(type, "int")) {
126 param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
127 } else if (!strcmp(type, "float")) {
128 param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
129 } else if (!strcmp(type, "string")) {
130 param = new ParamString(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
131 const gchar * max_length = in_repr->attribute("max_length");
132 if (max_length != NULL) {
133 ParamString * ps = dynamic_cast<ParamString *>(param);
134 ps->setMaxLength(atoi(max_length));
135 }
136 } else if (!strcmp(type, "description")) {
137 param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
138 } else if (!strcmp(type, "groupheader")) {
139 param = new ParamGroupHeader(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
140 } else if (!strcmp(type, "enum")) {
141 param = new ParamComboBox(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
142 } else if (!strcmp(type, "notebook")) {
143 param = new ParamNotebook(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
144 } else if (!strcmp(type, "optiongroup")) {
145 if (appearance && !strcmp(appearance, "minimal")) {
146 param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamRadioButton::MINIMAL);
147 } else {
148 param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamRadioButton::FULL);
149 }
150 } else if (!strcmp(type, "color")) {
151 param = new ParamColor(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
152 }
154 /* Note: param could equal NULL */
155 return param;
156 }
160 /** \brief Wrapper to cast to the object and use it's function. */
161 bool
162 Parameter::get_bool (const SPDocument * doc, const Inkscape::XML::Node * node)
163 {
164 ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
165 if (boolpntr == NULL)
166 throw Extension::param_not_bool_param();
167 return boolpntr->get(doc, node);
168 }
170 /** \brief Wrapper to cast to the object and use it's function. */
171 int
172 Parameter::get_int (const SPDocument * doc, const Inkscape::XML::Node * node)
173 {
174 ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
175 if (intpntr == NULL)
176 throw Extension::param_not_int_param();
177 return intpntr->get(doc, node);
178 }
180 /** \brief Wrapper to cast to the object and use it's function. */
181 float
182 Parameter::get_float (const SPDocument * doc, const Inkscape::XML::Node * node)
183 {
184 ParamFloat * floatpntr = dynamic_cast<ParamFloat *>(this);
185 if (floatpntr == NULL)
186 throw Extension::param_not_float_param();
187 return floatpntr->get(doc, node);
188 }
190 /** \brief Wrapper to cast to the object and use it's function. */
191 const gchar *
192 Parameter::get_string (const SPDocument * doc, const Inkscape::XML::Node * node)
193 {
194 ParamString * stringpntr = dynamic_cast<ParamString *>(this);
195 if (stringpntr == NULL)
196 throw Extension::param_not_string_param();
197 return stringpntr->get(doc, node);
198 }
200 /** \brief Wrapper to cast to the object and use it's function. */
201 const gchar *
202 Parameter::get_enum (const SPDocument * doc, const Inkscape::XML::Node * node)
203 {
204 ParamComboBox * param = dynamic_cast<ParamComboBox *>(this);
205 if (param == NULL)
206 throw Extension::param_not_enum_param();
207 return param->get(doc, node);
208 }
210 /** \brief Wrapper to cast to the object and use it's function. */
211 gchar const *Parameter::get_optiongroup(SPDocument const * doc, Inkscape::XML::Node const * node)
212 {
213 ParamRadioButton * param = dynamic_cast<ParamRadioButton *>(this);
214 if (!param) {
215 throw Extension::param_not_optiongroup_param();
216 }
217 return param->get(doc, node);
218 }
220 guint32
221 Parameter::get_color(const SPDocument* doc, const Inkscape::XML::Node* node)
222 {
223 ParamColor* param = dynamic_cast<ParamColor *>(this);
224 if (param == NULL)
225 throw Extension::param_not_color_param();
226 return param->get(doc, node);
227 }
229 /** \brief Wrapper to cast to the object and use it's function. */
230 bool
231 Parameter::set_bool (bool in, SPDocument * doc, Inkscape::XML::Node * node)
232 {
233 ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
234 if (boolpntr == NULL)
235 throw Extension::param_not_bool_param();
236 return boolpntr->set(in, doc, node);
237 }
239 /** \brief Wrapper to cast to the object and use it's function. */
240 int
241 Parameter::set_int (int in, SPDocument * doc, Inkscape::XML::Node * node)
242 {
243 ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
244 if (intpntr == NULL)
245 throw Extension::param_not_int_param();
246 return intpntr->set(in, doc, node);
247 }
249 /** \brief Wrapper to cast to the object and use it's function. */
250 float
251 Parameter::set_float (float in, SPDocument * doc, Inkscape::XML::Node * node)
252 {
253 ParamFloat * floatpntr;
254 floatpntr = dynamic_cast<ParamFloat *>(this);
255 if (floatpntr == NULL)
256 throw Extension::param_not_float_param();
257 return floatpntr->set(in, doc, node);
258 }
260 /** \brief Wrapper to cast to the object and use it's function. */
261 const gchar *
262 Parameter::set_string (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
263 {
264 ParamString * stringpntr = dynamic_cast<ParamString *>(this);
265 if (stringpntr == NULL)
266 throw Extension::param_not_string_param();
267 return stringpntr->set(in, doc, node);
268 }
270 gchar const * Parameter::set_optiongroup( gchar const * in, SPDocument * doc, Inkscape::XML::Node * node )
271 {
272 ParamRadioButton *param = dynamic_cast<ParamRadioButton *>(this);
273 if (!param) {
274 throw Extension::param_not_optiongroup_param();
275 }
276 return param->set(in, doc, node);
277 }
280 /** \brief Wrapper to cast to the object and use it's function. */
281 guint32
282 Parameter::set_color (guint32 in, SPDocument * doc, Inkscape::XML::Node * node)
283 {
284 ParamColor* param = dynamic_cast<ParamColor *>(this);
285 if (param == NULL)
286 throw Extension::param_not_color_param();
287 return param->set(in, doc, node);
288 }
291 /** \brief Oop, now that we need a parameter, we need it's name. */
292 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) :
293 extension(ext), _name(NULL), _desc(NULL), _scope(scope), _text(NULL), _gui_hidden(gui_hidden), _gui_tip(NULL)
294 {
295 if (name != NULL) {
296 _name = g_strdup(name);
297 }
298 if (desc != NULL) {
299 _desc = g_strdup(desc);
300 // printf("Adding description: '%s' on '%s'\n", _desc, _name);
301 }
302 if (gui_tip != NULL) {
303 _gui_tip = g_strdup(gui_tip);
304 }
307 if (guitext != NULL)
308 _text = g_strdup(guitext);
309 else
310 _text = g_strdup(name);
312 return;
313 }
315 /** \brief Just free the allocated name. */
316 Parameter::~Parameter (void)
317 {
318 g_free(_name);
319 g_free(_text);
320 g_free(_gui_tip);
321 g_free(_desc);
322 }
324 /** \brief Build the name to write the parameter from the extension's
325 ID and the name of this parameter. */
326 gchar *
327 Parameter::pref_name (void)
328 {
329 return g_strdup_printf("%s.%s", extension->get_id(), _name);
330 }
332 Inkscape::XML::Node *
333 Parameter::find_child (Inkscape::XML::Node * adult)
334 {
335 return sp_repr_lookup_child(adult, "name", _name);
336 }
338 Inkscape::XML::Node *
339 Parameter::new_child (Inkscape::XML::Node * parent)
340 {
341 Inkscape::XML::Node * retval;
342 retval = parent->document()->createElement("inkscape:extension-param");
343 retval->setAttribute("name", _name);
345 parent->appendChild(retval);
346 Inkscape::GC::release(retval);
347 return retval;
348 }
350 Inkscape::XML::Node *
351 Parameter::document_param_node (SPDocument * doc)
352 {
353 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
354 Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc));
355 Inkscape::XML::Node * params = NULL;
357 GQuark const name_quark = g_quark_from_string("inkscape:extension-params");
359 for (Inkscape::XML::Node * child = defs->firstChild();
360 child != NULL;
361 child = child->next()) {
362 if ((GQuark)child->code() == name_quark &&
363 !strcmp(child->attribute("extension"), extension->get_id())) {
364 params = child;
365 break;
366 }
367 }
369 if (params == NULL) {
370 params = xml_doc->createElement("inkscape:extension-param");
371 params->setAttribute("extension", extension->get_id());
372 defs->appendChild(params);
373 Inkscape::GC::release(params);
374 }
376 return params;
377 }
379 /** \brief Basically, if there is no widget pass a NULL. */
380 Gtk::Widget *
381 Parameter::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/, sigc::signal<void> * /*changeSignal*/)
382 {
383 return NULL;
384 }
386 /** \brief If I'm not sure which it is, just don't return a value. */
387 void
388 Parameter::string (std::string &/*string*/)
389 {
390 return;
391 }
393 void
394 Parameter::string (std::list <std::string> &list)
395 {
396 std::string value;
397 string(value);
398 if (value == "") {
399 return;
400 }
402 std::string final;
403 final += "--";
404 final += name();
405 final += "=";
406 final += value;
408 list.insert(list.end(), final);
409 return;
410 }
412 Glib::ustring const extension_pref_root = "/extensions/";
414 } /* namespace Extension */
415 } /* namespace Inkscape */
417 /*
418 Local Variables:
419 mode:c++
420 c-file-style:"stroustrup"
421 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
422 indent-tabs-mode:nil
423 fill-column:99
424 End:
425 */
426 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :