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 }
158 /** \brief Wrapper to cast to the object and use it's function. */
159 bool
160 Parameter::get_bool (const SPDocument * doc, const Inkscape::XML::Node * node)
161 {
162 ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
163 if (boolpntr == NULL)
164 throw Extension::param_not_bool_param();
165 return boolpntr->get(doc, node);
166 }
168 /** \brief Wrapper to cast to the object and use it's function. */
169 int
170 Parameter::get_int (const SPDocument * doc, const Inkscape::XML::Node * node)
171 {
172 ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
173 if (intpntr == NULL)
174 throw Extension::param_not_int_param();
175 return intpntr->get(doc, node);
176 }
178 /** \brief Wrapper to cast to the object and use it's function. */
179 float
180 Parameter::get_float (const SPDocument * doc, const Inkscape::XML::Node * node)
181 {
182 ParamFloat * floatpntr = dynamic_cast<ParamFloat *>(this);
183 if (floatpntr == NULL)
184 throw Extension::param_not_float_param();
185 return floatpntr->get(doc, node);
186 }
188 /** \brief Wrapper to cast to the object and use it's function. */
189 const gchar *
190 Parameter::get_string (const SPDocument * doc, const Inkscape::XML::Node * node)
191 {
192 ParamString * stringpntr = dynamic_cast<ParamString *>(this);
193 if (stringpntr == NULL)
194 throw Extension::param_not_string_param();
195 return stringpntr->get(doc, node);
196 }
198 /** \brief Wrapper to cast to the object and use it's function. */
199 const gchar *
200 Parameter::get_enum (const SPDocument * doc, const Inkscape::XML::Node * node)
201 {
202 ParamComboBox * param = dynamic_cast<ParamComboBox *>(this);
203 if (param == NULL)
204 throw Extension::param_not_enum_param();
205 return param->get(doc, node);
206 }
208 /** \brief Wrapper to cast to the object and use it's function. */
209 gchar const *Parameter::get_optiongroup(SPDocument const * doc, Inkscape::XML::Node const * node)
210 {
211 ParamRadioButton * param = dynamic_cast<ParamRadioButton *>(this);
212 if (!param) {
213 throw Extension::param_not_optiongroup_param();
214 }
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 }
268 gchar const * Parameter::set_optiongroup( gchar const * in, SPDocument * doc, Inkscape::XML::Node * node )
269 {
270 ParamRadioButton *param = dynamic_cast<ParamRadioButton *>(this);
271 if (!param) {
272 throw Extension::param_not_optiongroup_param();
273 }
274 return param->set(in, doc, node);
275 }
278 /** \brief Wrapper to cast to the object and use it's function. */
279 guint32
280 Parameter::set_color (guint32 in, SPDocument * doc, Inkscape::XML::Node * node)
281 {
282 ParamColor* param = dynamic_cast<ParamColor *>(this);
283 if (param == NULL)
284 throw Extension::param_not_color_param();
285 return param->set(in, doc, node);
286 }
289 /** \brief Oop, now that we need a parameter, we need it's name. */
290 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) :
291 extension(ext), _name(NULL), _desc(NULL), _scope(scope), _text(NULL), _gui_hidden(gui_hidden), _gui_tip(NULL)
292 {
293 if (name != NULL) {
294 _name = g_strdup(name);
295 }
296 if (desc != NULL) {
297 _desc = g_strdup(desc);
298 // printf("Adding description: '%s' on '%s'\n", _desc, _name);
299 }
300 if (gui_tip != NULL) {
301 _gui_tip = g_strdup(gui_tip);
302 }
305 if (guitext != NULL)
306 _text = g_strdup(guitext);
307 else
308 _text = g_strdup(name);
310 return;
311 }
313 /** \brief Just free the allocated name. */
314 Parameter::~Parameter (void)
315 {
316 g_free(_name);
317 g_free(_text);
318 g_free(_gui_tip);
319 g_free(_desc);
320 }
322 /** \brief Build the name to write the parameter from the extension's
323 ID and the name of this parameter. */
324 gchar *
325 Parameter::pref_name (void)
326 {
327 return g_strdup_printf("%s.%s", extension->get_id(), _name);
328 }
330 Inkscape::XML::Node *
331 Parameter::find_child (Inkscape::XML::Node * adult)
332 {
333 return sp_repr_lookup_child(adult, "name", _name);
334 }
336 Inkscape::XML::Node *
337 Parameter::new_child (Inkscape::XML::Node * parent)
338 {
339 Inkscape::XML::Node * retval;
340 retval = parent->document()->createElement("inkscape:extension-param");
341 retval->setAttribute("name", _name);
343 parent->appendChild(retval);
344 Inkscape::GC::release(retval);
345 return retval;
346 }
348 Inkscape::XML::Node *
349 Parameter::document_param_node (SPDocument * doc)
350 {
351 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
352 Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc));
353 Inkscape::XML::Node * params = NULL;
355 GQuark const name_quark = g_quark_from_string("inkscape:extension-params");
357 for (Inkscape::XML::Node * child = defs->firstChild();
358 child != NULL;
359 child = child->next()) {
360 if ((GQuark)child->code() == name_quark &&
361 !strcmp(child->attribute("extension"), extension->get_id())) {
362 params = child;
363 break;
364 }
365 }
367 if (params == NULL) {
368 params = xml_doc->createElement("inkscape:extension-param");
369 params->setAttribute("extension", extension->get_id());
370 defs->appendChild(params);
371 Inkscape::GC::release(params);
372 }
374 return params;
375 }
377 /** \brief Basically, if there is no widget pass a NULL. */
378 Gtk::Widget *
379 Parameter::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/, sigc::signal<void> * /*changeSignal*/)
380 {
381 return NULL;
382 }
384 /** \brief If I'm not sure which it is, just don't return a value. */
385 void
386 Parameter::string (std::string &/*string*/)
387 {
388 return;
389 }
391 void
392 Parameter::string (std::list <std::string> &list)
393 {
394 std::string value;
395 string(value);
396 if (value == "") {
397 return;
398 }
400 std::string final;
401 final += "--";
402 final += name();
403 final += "=";
404 final += value;
406 list.insert(list.end(), final);
407 return;
408 }
410 /** \brief All the code in Notebook::get_param to get the notebook content */
411 Parameter *
412 Parameter::get_param(const gchar * name)
413 {
414 return NULL;
415 }
417 Glib::ustring const extension_pref_root = "/extensions/";
419 } /* namespace Extension */
420 } /* namespace Inkscape */
422 /*
423 Local Variables:
424 mode:c++
425 c-file-style:"stroustrup"
426 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
427 indent-tabs-mode:nil
428 fill-column:99
429 End:
430 */
431 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :