1 /** @file
2 * @brief Parameters for extensions.
3 */
4 /* Author:
5 * Ted Gould <ted@gould.cx>
6 * Johan Engelen <johan@shouraizou.nl>
7 * Jon A. Cruz <jon@joncruz.org>
8 *
9 * Copyright (C) 2005-2007 Authors
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
18 #ifdef linux // does the dollar sign need escaping when passed as string parameter?
19 # define ESCAPE_DOLLAR_COMMANDLINE
20 #endif
22 #include <gtkmm/adjustment.h>
23 #include <gtkmm/box.h>
24 #include <gtkmm/spinbutton.h>
26 #include <xml/node.h>
28 #include <extension/extension.h>
29 #include "document-private.h"
30 #include "sp-object.h"
31 #include <color.h>
32 #include "widgets/sp-color-selector.h"
33 #include "widgets/sp-color-notebook.h"
35 #include "parameter.h"
36 #include "bool.h"
37 #include "color.h"
38 #include "description.h"
39 #include "groupheader.h"
40 #include "enum.h"
41 #include "float.h"
42 #include "int.h"
43 #include "notebook.h"
44 #include "radiobutton.h"
45 #include "string.h"
47 namespace Inkscape {
48 namespace Extension {
50 /**
51 \return None
52 \brief This function creates a parameter that can be used later. This
53 is typically done in the creation of the extension and defined
54 in the XML file describing the extension (it's private so people
55 have to use the system) :)
56 \param in_repr The XML describing the parameter
58 This function first grabs all of the data out of the Repr and puts
59 it into local variables. Actually, these are just pointers, and the
60 data is not duplicated so we need to be careful with it. If there
61 isn't a name or a type in the XML, then no parameter is created as
62 the function just returns.
64 From this point on, we're pretty committed as we've allocated an
65 object and we're starting to fill it. The name is set first, and
66 is created with a strdup to actually allocate memory for it. Then
67 there is a case statement (roughly because strcmp requires 'ifs')
68 based on what type of parameter this is. Depending which type it
69 is, the value is interpreted differently, but they are relatively
70 straight forward. In all cases the value is set to the default
71 value from the XML and the type is set to the interpreted type.
72 */
73 Parameter *
74 Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext)
75 {
76 const char * name;
77 const char * type;
78 const char * guitext;
79 const char * desc;
80 const char * scope_str;
81 Parameter::_scope_t scope = Parameter::SCOPE_USER;
82 bool gui_hidden = false;
83 const char * gui_hide;
84 const char * gui_tip;
86 name = in_repr->attribute("name");
87 type = in_repr->attribute("type");
88 guitext = in_repr->attribute("gui-text");
89 if (guitext == NULL)
90 guitext = in_repr->attribute("_gui-text");
91 gui_tip = in_repr->attribute("gui-tip");
92 if (gui_tip == NULL)
93 gui_tip = in_repr->attribute("_gui-tip");
94 desc = in_repr->attribute("gui-description");
95 if (desc == NULL)
96 desc = in_repr->attribute("_gui-description");
97 scope_str = in_repr->attribute("scope");
98 gui_hide = in_repr->attribute("gui-hidden");
99 if (gui_hide != NULL) {
100 if (strcmp(gui_hide, "1") == 0 ||
101 strcmp(gui_hide, "true") == 0) {
102 gui_hidden = true;
103 }
104 /* else stays false */
105 }
106 const gchar* appearance = in_repr->attribute("appearance");
108 /* In this case we just don't have enough information */
109 if (name == NULL || type == NULL) {
110 return NULL;
111 }
113 if (scope_str != NULL) {
114 if (!strcmp(scope_str, "user")) {
115 scope = Parameter::SCOPE_USER;
116 } else if (!strcmp(scope_str, "document")) {
117 scope = Parameter::SCOPE_DOCUMENT;
118 } else if (!strcmp(scope_str, "node")) {
119 scope = Parameter::SCOPE_NODE;
120 }
121 }
123 Parameter * param = NULL;
124 if (!strcmp(type, "boolean")) {
125 param = new ParamBool(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
126 } else if (!strcmp(type, "int")) {
127 param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
128 } else if (!strcmp(type, "float")) {
129 param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
130 } else if (!strcmp(type, "string")) {
131 param = new ParamString(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
132 const gchar * max_length = in_repr->attribute("max_length");
133 if (max_length != NULL) {
134 ParamString * ps = dynamic_cast<ParamString *>(param);
135 ps->setMaxLength(atoi(max_length));
136 }
137 } else if (!strcmp(type, "description")) {
138 param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
139 } else if (!strcmp(type, "groupheader")) {
140 param = new ParamGroupHeader(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
141 } else if (!strcmp(type, "enum")) {
142 param = new ParamComboBox(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
143 } else if (!strcmp(type, "notebook")) {
144 param = new ParamNotebook(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
145 } else if (!strcmp(type, "optiongroup")) {
146 if (appearance && !strcmp(appearance, "minimal")) {
147 param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamRadioButton::MINIMAL);
148 } else {
149 param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamRadioButton::FULL);
150 }
151 } else if (!strcmp(type, "color")) {
152 param = new ParamColor(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr);
153 }
155 /* Note: param could equal NULL */
156 return param;
157 }
159 /** \brief Wrapper to cast to the object and use it's function. */
160 bool
161 Parameter::get_bool (const SPDocument * doc, const Inkscape::XML::Node * node)
162 {
163 ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
164 if (boolpntr == NULL)
165 throw Extension::param_not_bool_param();
166 return boolpntr->get(doc, node);
167 }
169 /** \brief Wrapper to cast to the object and use it's function. */
170 int
171 Parameter::get_int (const SPDocument * doc, const Inkscape::XML::Node * node)
172 {
173 ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
174 if (intpntr == NULL)
175 throw Extension::param_not_int_param();
176 return intpntr->get(doc, node);
177 }
179 /** \brief Wrapper to cast to the object and use it's function. */
180 float
181 Parameter::get_float (const SPDocument * doc, const Inkscape::XML::Node * node)
182 {
183 ParamFloat * floatpntr = dynamic_cast<ParamFloat *>(this);
184 if (floatpntr == NULL)
185 throw Extension::param_not_float_param();
186 return floatpntr->get(doc, node);
187 }
189 /** \brief Wrapper to cast to the object and use it's function. */
190 const gchar *
191 Parameter::get_string (const SPDocument * doc, const Inkscape::XML::Node * node)
192 {
193 ParamString * stringpntr = dynamic_cast<ParamString *>(this);
194 if (stringpntr == NULL)
195 throw Extension::param_not_string_param();
196 return stringpntr->get(doc, node);
197 }
199 /** \brief Wrapper to cast to the object and use it's function. */
200 const gchar *
201 Parameter::get_enum (const SPDocument * doc, const Inkscape::XML::Node * node)
202 {
203 ParamComboBox * param = dynamic_cast<ParamComboBox *>(this);
204 if (param == NULL)
205 throw Extension::param_not_enum_param();
206 return param->get(doc, node);
207 }
209 /** \brief Wrapper to cast to the object and use it's function. */
210 gchar const *Parameter::get_optiongroup(SPDocument const * doc, Inkscape::XML::Node const * node)
211 {
212 ParamRadioButton * param = dynamic_cast<ParamRadioButton *>(this);
213 if (!param) {
214 throw Extension::param_not_optiongroup_param();
215 }
216 return param->get(doc, node);
217 }
219 guint32
220 Parameter::get_color(const SPDocument* doc, const Inkscape::XML::Node* node)
221 {
222 ParamColor* param = dynamic_cast<ParamColor *>(this);
223 if (param == NULL)
224 throw Extension::param_not_color_param();
225 return param->get(doc, node);
226 }
228 /** \brief Wrapper to cast to the object and use it's function. */
229 bool
230 Parameter::set_bool (bool in, SPDocument * doc, Inkscape::XML::Node * node)
231 {
232 ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
233 if (boolpntr == NULL)
234 throw Extension::param_not_bool_param();
235 return boolpntr->set(in, doc, node);
236 }
238 /** \brief Wrapper to cast to the object and use it's function. */
239 int
240 Parameter::set_int (int in, SPDocument * doc, Inkscape::XML::Node * node)
241 {
242 ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
243 if (intpntr == NULL)
244 throw Extension::param_not_int_param();
245 return intpntr->set(in, doc, node);
246 }
248 /** \brief Wrapper to cast to the object and use it's function. */
249 float
250 Parameter::set_float (float in, SPDocument * doc, Inkscape::XML::Node * node)
251 {
252 ParamFloat * floatpntr;
253 floatpntr = dynamic_cast<ParamFloat *>(this);
254 if (floatpntr == NULL)
255 throw Extension::param_not_float_param();
256 return floatpntr->set(in, doc, node);
257 }
259 /** \brief Wrapper to cast to the object and use it's function. */
260 const gchar *
261 Parameter::set_string (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
262 {
263 ParamString * stringpntr = dynamic_cast<ParamString *>(this);
264 if (stringpntr == NULL)
265 throw Extension::param_not_string_param();
266 return stringpntr->set(in, doc, node);
267 }
269 gchar const * Parameter::set_optiongroup( gchar const * in, SPDocument * doc, Inkscape::XML::Node * node )
270 {
271 ParamRadioButton *param = dynamic_cast<ParamRadioButton *>(this);
272 if (!param) {
273 throw Extension::param_not_optiongroup_param();
274 }
275 return param->set(in, doc, node);
276 }
279 /** \brief Wrapper to cast to the object and use it's function. */
280 guint32
281 Parameter::set_color (guint32 in, SPDocument * doc, Inkscape::XML::Node * node)
282 {
283 ParamColor* param = dynamic_cast<ParamColor *>(this);
284 if (param == NULL)
285 throw Extension::param_not_color_param();
286 return param->set(in, doc, node);
287 }
290 /** \brief Oop, now that we need a parameter, we need it's name. */
291 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) :
292 extension(ext), _name(NULL), _desc(NULL), _scope(scope), _text(NULL), _gui_hidden(gui_hidden), _gui_tip(NULL)
293 {
294 if (name != NULL) {
295 _name = g_strdup(name);
296 }
297 if (desc != NULL) {
298 _desc = g_strdup(desc);
299 // printf("Adding description: '%s' on '%s'\n", _desc, _name);
300 }
301 if (gui_tip != NULL) {
302 _gui_tip = g_strdup(gui_tip);
303 }
306 if (guitext != NULL)
307 _text = g_strdup(guitext);
308 else
309 _text = g_strdup(name);
311 return;
312 }
314 /** \brief Just free the allocated name. */
315 Parameter::~Parameter (void)
316 {
317 g_free(_name);
318 g_free(_text);
319 g_free(_gui_tip);
320 g_free(_desc);
321 }
323 /** \brief Build the name to write the parameter from the extension's
324 ID and the name of this parameter. */
325 gchar *
326 Parameter::pref_name (void)
327 {
328 return g_strdup_printf("%s.%s", extension->get_id(), _name);
329 }
331 Inkscape::XML::Node *
332 Parameter::find_child (Inkscape::XML::Node * adult)
333 {
334 return sp_repr_lookup_child(adult, "name", _name);
335 }
337 Inkscape::XML::Node *
338 Parameter::new_child (Inkscape::XML::Node * parent)
339 {
340 Inkscape::XML::Node * retval;
341 retval = parent->document()->createElement("inkscape:extension-param");
342 retval->setAttribute("name", _name);
344 parent->appendChild(retval);
345 Inkscape::GC::release(retval);
346 return retval;
347 }
349 Inkscape::XML::Node *Parameter::document_param_node(SPDocument * doc)
350 {
351 Inkscape::XML::Document *xml_doc = doc->getReprDoc();
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 :