Code

Extensions. General UI improvements (gnome HIG). New group header extension parameter.
[inkscape.git] / src / extension / param / parameter.cpp
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;
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)
164     ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
165     if (boolpntr == NULL)
166         throw Extension::param_not_bool_param();
167     return boolpntr->get(doc, node);
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)
174     ParamInt * intpntr = dynamic_cast<ParamInt *>(this);
175     if (intpntr == NULL)
176         throw Extension::param_not_int_param();
177     return intpntr->get(doc, node);
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)
184     ParamFloat * floatpntr = dynamic_cast<ParamFloat *>(this);
185     if (floatpntr == NULL)
186         throw Extension::param_not_float_param();
187     return floatpntr->get(doc, node);
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)
194     ParamString * stringpntr = dynamic_cast<ParamString *>(this);
195     if (stringpntr == NULL)
196         throw Extension::param_not_string_param();
197     return stringpntr->get(doc, node);
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)
204     ParamComboBox * param = dynamic_cast<ParamComboBox *>(this);
205     if (param == NULL)
206         throw Extension::param_not_enum_param();
207     return param->get(doc, node);
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)
213     ParamRadioButton * param = dynamic_cast<ParamRadioButton *>(this);
214     if (!param) {
215         throw Extension::param_not_optiongroup_param();
216     }
217     return param->get(doc, node);
220 guint32
221 Parameter::get_color(const SPDocument* doc, const Inkscape::XML::Node* node)
223     ParamColor* param = dynamic_cast<ParamColor *>(this);
224     if (param == NULL)
225         throw Extension::param_not_color_param();
226     return param->get(doc, node);
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)
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);
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)
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);
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)
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);
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)
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);
270 gchar const * Parameter::set_optiongroup( gchar const * in, SPDocument * doc, Inkscape::XML::Node * node )
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);
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)
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);
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)
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;
315 /** \brief  Just free the allocated name. */
316 Parameter::~Parameter (void)
318     g_free(_name);
319     g_free(_text);
320         g_free(_gui_tip);
321     g_free(_desc);
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)
329     return g_strdup_printf("%s.%s", extension->get_id(), _name);
332 Inkscape::XML::Node *
333 Parameter::find_child (Inkscape::XML::Node * adult)
335     return sp_repr_lookup_child(adult, "name", _name);
338 Inkscape::XML::Node *
339 Parameter::new_child (Inkscape::XML::Node * parent)
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;
350 Inkscape::XML::Node *
351 Parameter::document_param_node (SPDocument * doc)
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;
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*/)
383     return NULL;
386 /** \brief  If I'm not sure which it is, just don't return a value. */
387 void
388 Parameter::string (std::string &/*string*/)
390     return;
393 void
394 Parameter::string (std::list <std::string> &list)
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;
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 :