1 /** \file
2 * Parameters for extensions.
3 */
5 /*
6 * Author:
7 * Ted Gould <ted@gould.cx>
8 * Johan Engelen <johan@shouraizou.nl>
9 *
10 * Copyright (C) 2005-2007 Authors
11 *
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
19 #ifdef linux // does the dollar sign need escaping when passed as string parameter?
20 # define ESCAPE_DOLLAR_COMMANDLINE
21 #endif
23 #include <gtkmm/adjustment.h>
24 #include <gtkmm/box.h>
25 #include <gtkmm/spinbutton.h>
27 #include <xml/node.h>
29 #include "extension.h"
30 #include "document-private.h"
31 #include "sp-object.h"
32 #include "color.h"
33 #include "widgets/sp-color-selector.h"
34 #include "widgets/sp-color-notebook.h"
36 #include "parameter.h"
37 #include "parambool.h"
38 #include "paramcolor.h"
39 #include "paramdescription.h"
40 #include "paramenum.h"
41 #include "paramfloat.h"
42 #include "paramint.h"
43 #include "paramnotebook.h"
44 #include "paramradiobutton.h"
45 #include "paramstring.h"
47 namespace Inkscape {
48 namespace Extension {
50 class ParamEnum : public Parameter {
51 private:
52 class Choice {
53 public:
54 gchar * _gui_name;
55 gchar * _value;
56 Choice(gchar * gui_name, gchar * value) : _gui_name(NULL), _value(NULL) {
57 if (gui_name != NULL)
58 _gui_name = g_strdup(_(gui_name));
59 if (value != NULL)
60 _value = g_strdup(value);
61 return;
62 };
63 ~Choice (void) {
64 g_free(_gui_name);
65 g_free(_value);
66 };
67 }; /* class Choice */
68 /** \brief Internal value. This should point to a string that has
69 been allocated in memory. And should be free'd. */
70 Choice * _current_choice;
71 typedef std::list<Choice *> choice_list_t;
72 choice_list_t _choice_list;
73 public:
74 ParamEnum(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
75 ~ParamEnum(void);
76 /** \brief Returns \c _value, with a \i const to protect it. */
77 const gchar * get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _current_choice != NULL ? _current_choice->_value : NULL; }
78 const gchar * set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node);
79 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal);
80 Glib::ustring * string (void);
81 }; /* class ParamEnum */
83 /**
84 \return None
85 \brief This function creates a parameter that can be used later. This
86 is typically done in the creation of the extension and defined
87 in the XML file describing the extension (it's private so people
88 have to use the system) :)
89 \param in_repr The XML describing the parameter
91 This function first grabs all of the data out of the Repr and puts
92 it into local variables. Actually, these are just pointers, and the
93 data is not duplicated so we need to be careful with it. If there
94 isn't a name or a type in the XML, then no parameter is created as
95 the function just returns.
97 From this point on, we're pretty committed as we've allocated an
98 object and we're starting to fill it. The name is set first, and
99 is created with a strdup to actually allocate memory for it. Then
100 there is a case statement (roughly because strcmp requires 'ifs')
101 based on what type of parameter this is. Depending which type it
102 is, the value is interpreted differently, but they are relatively
103 straight forward. In all cases the value is set to the default
104 value from the XML and the type is set to the interpreted type.
105 */
106 Parameter *
107 Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext)
108 {
109 const char * name;
110 const char * type;
111 const char * guitext;
112 const char * desc;
113 const char * scope_str;
114 Parameter::_scope_t scope = Parameter::SCOPE_USER;
116 name = in_repr->attribute("name");
117 type = in_repr->attribute("type");
118 guitext = in_repr->attribute("gui-text");
119 if (guitext == NULL)
120 guitext = in_repr->attribute("_gui-text");
121 desc = in_repr->attribute("gui-description");
122 if (desc == NULL)
123 desc = in_repr->attribute("_gui-description");
124 scope_str = in_repr->attribute("scope");
126 /* In this case we just don't have enough information */
127 if (name == NULL || type == NULL) {
128 return NULL;
129 }
131 if (scope_str != NULL) {
132 if (!strcmp(scope_str, "user")) {
133 scope = Parameter::SCOPE_USER;
134 } else if (!strcmp(scope_str, "document")) {
135 scope = Parameter::SCOPE_DOCUMENT;
136 } else if (!strcmp(scope_str, "node")) {
137 scope = Parameter::SCOPE_NODE;
138 }
139 }
141 Parameter * param = NULL;
142 if (!strcmp(type, "boolean")) {
143 param = new ParamBool(name, guitext, desc, scope, in_ext, in_repr);
144 } else if (!strcmp(type, "int")) {
145 param = new ParamInt(name, guitext, desc, scope, in_ext, in_repr);
146 } else if (!strcmp(type, "float")) {
147 param = new ParamFloat(name, guitext, desc, scope, in_ext, in_repr);
148 } else if (!strcmp(type, "string")) {
149 param = new ParamString(name, guitext, desc, scope, in_ext, in_repr);
150 } else if (!strcmp(type, "description")) {
151 param = new ParamDescription(name, guitext, desc, scope, in_ext, in_repr);
152 } else if (!strcmp(type, "enum")) {
153 param = new ParamComboBox(name, guitext, desc, scope, in_ext, in_repr);
154 } else if (!strcmp(type, "notebook")) {
155 param = new ParamNotebook(name, guitext, desc, scope, in_ext, in_repr);
156 } else if (!strcmp(type, "optiongroup")) {
157 param = new ParamRadioButton(name, guitext, desc, scope, in_ext, in_repr);
158 } else if (!strcmp(type, "color")) {
159 param = new ParamColor(name, guitext, desc, scope, in_ext, in_repr);
160 }
162 /* Note: param could equal NULL */
163 return param;
164 }
168 /** \brief Wrapper to cast to the object and use it's function. */
169 bool
170 Parameter::get_bool (const SPDocument * doc, const Inkscape::XML::Node * node)
171 {
172 ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
173 if (boolpntr == NULL)
174 throw Extension::param_not_bool_param();
175 return boolpntr->get(doc, node);
176 }
178 /** \brief Wrapper to cast to the object and use it's function. */
179 int
180 Parameter::get_int (const SPDocument * doc, const Inkscape::XML::Node * node)
181 {
182 ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
183 if (intpntr == NULL)
184 throw Extension::param_not_int_param();
185 return intpntr->get(doc, node);
186 }
188 /** \brief Wrapper to cast to the object and use it's function. */
189 float
190 Parameter::get_float (const SPDocument * doc, const Inkscape::XML::Node * node)
191 {
192 ParamFloat * floatpntr = dynamic_cast<ParamFloat *>(this);
193 if (floatpntr == NULL)
194 throw Extension::param_not_float_param();
195 return floatpntr->get(doc, node);
196 }
198 /** \brief Wrapper to cast to the object and use it's function. */
199 const gchar *
200 Parameter::get_string (const SPDocument * doc, const Inkscape::XML::Node * node)
201 {
202 ParamString * stringpntr = dynamic_cast<ParamString *>(this);
203 if (stringpntr == NULL)
204 throw Extension::param_not_string_param();
205 return stringpntr->get(doc, node);
206 }
208 /** \brief Wrapper to cast to the object and use it's function. */
209 const gchar *
210 Parameter::get_enum (const SPDocument * doc, const Inkscape::XML::Node * node)
211 {
212 ParamComboBox * param = dynamic_cast<ParamComboBox *>(this);
213 if (param == NULL)
214 throw Extension::param_not_enum_param();
215 return param->get(doc, node);
216 }
218 guint32
219 Parameter::get_color(const SPDocument* doc, const Inkscape::XML::Node* node)
220 {
221 ParamColor* param = dynamic_cast<ParamColor *>(this);
222 if (param == NULL)
223 throw Extension::param_not_color_param();
224 return param->get(doc, node);
225 }
227 /** \brief Wrapper to cast to the object and use it's function. */
228 bool
229 Parameter::set_bool (bool in, SPDocument * doc, Inkscape::XML::Node * node)
230 {
231 ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
232 if (boolpntr == NULL)
233 throw Extension::param_not_bool_param();
234 return boolpntr->set(in, doc, node);
235 }
237 /** \brief Wrapper to cast to the object and use it's function. */
238 int
239 Parameter::set_int (int in, SPDocument * doc, Inkscape::XML::Node * node)
240 {
241 ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
242 if (intpntr == NULL)
243 throw Extension::param_not_int_param();
244 return intpntr->set(in, doc, node);
245 }
247 /** \brief Wrapper to cast to the object and use it's function. */
248 float
249 Parameter::set_float (float in, SPDocument * doc, Inkscape::XML::Node * node)
250 {
251 ParamFloat * floatpntr;
252 floatpntr = dynamic_cast<ParamFloat *>(this);
253 if (floatpntr == NULL)
254 throw Extension::param_not_float_param();
255 return floatpntr->set(in, doc, node);
256 }
258 /** \brief Wrapper to cast to the object and use it's function. */
259 const gchar *
260 Parameter::set_string (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
261 {
262 ParamString * stringpntr = dynamic_cast<ParamString *>(this);
263 if (stringpntr == NULL)
264 throw Extension::param_not_string_param();
265 return stringpntr->set(in, doc, node);
266 }
267 /** \brief Wrapper to cast to the object and use it's function. */
268 guint32
269 Parameter::set_color (guint32 in, SPDocument * doc, Inkscape::XML::Node * node)
270 {
271 ParamColor* param = dynamic_cast<ParamColor *>(this);
272 if (param == NULL)
273 throw Extension::param_not_color_param();
274 return param->set(in, doc, node);
275 }
278 /** \brief Oop, now that we need a parameter, we need it's name. */
279 Parameter::Parameter (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext) :
280 extension(ext), _name(NULL), _desc(NULL), _scope(scope), _text(NULL)
281 {
282 if (name != NULL)
283 _name = g_strdup(name);
284 if (desc != NULL) {
285 _desc = g_strdup(desc);
286 // printf("Adding description: '%s' on '%s'\n", _desc, _name);
287 }
290 if (guitext != NULL)
291 _text = g_strdup(guitext);
292 else
293 _text = g_strdup(name);
295 return;
296 }
298 /** \brief Just free the allocated name. */
299 Parameter::~Parameter (void)
300 {
301 g_free(_name);
302 g_free(_text);
303 }
305 /** \brief Build the name to write the parameter from the extension's
306 ID and the name of this parameter. */
307 gchar *
308 Parameter::pref_name (void)
309 {
310 return g_strdup_printf("%s.%s", extension->get_id(), _name);
311 }
313 Inkscape::XML::Node *
314 Parameter::find_child (Inkscape::XML::Node * adult)
315 {
316 return sp_repr_lookup_child(adult, "name", _name);
317 }
319 Inkscape::XML::Node *
320 Parameter::new_child (Inkscape::XML::Node * parent)
321 {
322 Inkscape::XML::Node * retval;
323 retval = parent->document()->createElement("inkscape:extension-param");
324 retval->setAttribute("name", _name);
326 parent->appendChild(retval);
327 return retval;
328 }
330 Inkscape::XML::Node *
331 Parameter::document_param_node (SPDocument * doc)
332 {
333 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
334 Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc));
335 Inkscape::XML::Node * params = NULL;
337 GQuark const name_quark = g_quark_from_string("inkscape:extension-params");
339 for (Inkscape::XML::Node * child = defs->firstChild();
340 child != NULL;
341 child = child->next()) {
342 if ((GQuark)child->code() == name_quark &&
343 !strcmp(child->attribute("extension"), extension->get_id())) {
344 params = child;
345 break;
346 }
347 }
349 if (params == NULL) {
350 params = xml_doc->createElement("inkscape:extension-param");
351 params->setAttribute("extension", extension->get_id());
352 defs->appendChild(params);
353 }
355 return params;
356 }
358 /** \brief Basically, if there is no widget pass a NULL. */
359 Gtk::Widget *
360 Parameter::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
361 {
362 return NULL;
363 }
365 /** \brief If I'm not sure which it is, just don't return a value. */
366 Glib::ustring *
367 Parameter::string (void)
368 {
369 Glib::ustring * mystring = new Glib::ustring("");
370 return mystring;
371 }
377 ParamEnum::ParamEnum (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
378 Parameter(name, guitext, desc, scope, ext), _current_choice(NULL)
379 {
380 return;
381 }
383 ParamEnum::~ParamEnum (void)
384 {
386 }
388 /** \brief Return the value as a string */
389 Glib::ustring *
390 ParamEnum::string (void)
391 {
392 Glib::ustring * mystring = new Glib::ustring("");
393 *mystring += this->get(NULL, NULL);
394 return mystring;
395 }
397 Gtk::Widget *
398 ParamEnum::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
399 {
400 return NULL;
401 }
403 const gchar *
404 ParamEnum::set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
405 {
406 return NULL;
407 }
410 } /* namespace Extension */
411 } /* namespace Inkscape */
413 /*
414 Local Variables:
415 mode:c++
416 c-file-style:"stroustrup"
417 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
418 indent-tabs-mode:nil
419 fill-column:99
420 End:
421 */
422 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :