1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** @file
3  * Parameters for extensions.
4  */
5 /* Author:
6  *   Ted Gould <ted@gould.cx>
7  *   Johan Engelen <johan@shouraizou.nl>
8  *   Jon A. Cruz <jon@joncruz.org>
9  *
10  * Copyright (C) 2005-2007 Authors
11  *
12  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13  */
14 
15 #include <cstring>
16 #include <list>
17 
18 #include <glibmm/i18n.h>
19 #include <sigc++/sigc++.h>
20 
21 #include "parameter.h"
22 #include "parameter-bool.h"
23 #include "parameter-color.h"
24 #include "parameter-float.h"
25 #include "parameter-int.h"
26 #include "parameter-notebook.h"
27 #include "parameter-optiongroup.h"
28 #include "parameter-path.h"
29 #include "parameter-string.h"
30 #include "widget.h"
31 #include "widget-label.h"
32 
33 #include "extension/extension.h"
34 
35 #include "object/sp-defs.h"
36 
37 #include "ui/widget/color-notebook.h"
38 
39 #include "xml/node.h"
40 
41 
42 namespace Inkscape {
43 namespace Extension {
44 
45 
46 // Re-implement ParamDescription for backwards-compatibility, deriving from both, WidgetLabel and InxParameter.
47 // TODO: Should go away eventually...
48 class ParamDescription : public virtual WidgetLabel, public virtual InxParameter {
49 public:
ParamDescription(Inkscape::XML::Node * xml,Inkscape::Extension::Extension * ext)50     ParamDescription(Inkscape::XML::Node *xml, Inkscape::Extension::Extension *ext)
51         : WidgetLabel(xml, ext)
52         , InxParameter(xml, ext)
53     {}
54 
get_widget(sigc::signal<void> * changeSignal)55     Gtk::Widget *get_widget(sigc::signal<void> *changeSignal) override
56     {
57         return this->WidgetLabel::get_widget(changeSignal);
58     }
59 
60     // Well, no, I don't have a value! That's why I should not be an InxParameter!
value_to_string() const61     std::string value_to_string() const override { return ""; }
62 };
63 
64 
65 
make(Inkscape::XML::Node * in_repr,Inkscape::Extension::Extension * in_ext)66 InxParameter *InxParameter::make(Inkscape::XML::Node *in_repr, Inkscape::Extension::Extension *in_ext)
67 {
68     InxParameter *param = nullptr;
69 
70     try {
71         const char *type = in_repr->attribute("type");
72         if (!type) {
73             // we can't create a parameter without type
74             g_warning("Parameter without type in extension '%s'.", in_ext->get_id());
75         } else if(!strcmp(type, "bool") || !strcmp(type, "boolean")) { // support "boolean" for backwards-compatibility
76             param = new ParamBool(in_repr, in_ext);
77         } else if (!strcmp(type, "int")) {
78             param = new ParamInt(in_repr, in_ext);
79         } else if (!strcmp(type, "float")) {
80             param = new ParamFloat(in_repr, in_ext);
81         } else if (!strcmp(type, "string")) {
82             param = new ParamString(in_repr, in_ext);
83         } else if (!strcmp(type, "path")) {
84             param = new ParamPath(in_repr, in_ext);
85         } else if (!strcmp(type, "description")) {
86             // support deprecated "description" for backwards-compatibility
87             in_repr->setAttribute("gui-text", "description"); // TODO: hack to allow descriptions to be parameters
88             param = new ParamDescription(in_repr, in_ext);
89         } else if (!strcmp(type, "notebook")) {
90             in_repr->setAttribute("gui-text", "notebook"); // notebooks have no 'gui-text' (but Parameters need one)
91             param = new ParamNotebook(in_repr, in_ext);
92         } else if (!strcmp(type, "optiongroup")) {
93             param = new ParamOptionGroup(in_repr, in_ext);
94         } else if (!strcmp(type, "enum")) { // support deprecated "enum" for backwards-compatibility
95             in_repr->setAttribute("appearance", "combo");
96             param = new ParamOptionGroup(in_repr, in_ext);
97         } else if (!strcmp(type, "color")) {
98             param = new ParamColor(in_repr, in_ext);
99         } else {
100             g_warning("Unknown parameter type ('%s') in extension '%s'", type, in_ext->get_id());
101         }
102     } catch (const param_no_name&) {
103     } catch (const param_no_text&) {
104     }
105 
106     // Note: param could equal nullptr
107     return param;
108 }
109 
get_bool() const110 bool InxParameter::get_bool() const
111 {
112     ParamBool const *boolpntr = dynamic_cast<ParamBool const *>(this);
113     if (!boolpntr) {
114         throw param_not_bool_param();
115     }
116     return boolpntr->get();
117 }
118 
get_int() const119 int InxParameter::get_int() const
120 {
121     ParamInt const *intpntr = dynamic_cast<ParamInt const *>(this);
122     if (!intpntr) {
123         throw param_not_int_param();
124     }
125     return intpntr->get();
126 }
127 
get_float() const128 float InxParameter::get_float() const
129 {
130     ParamFloat const *floatpntr = dynamic_cast<ParamFloat const *>(this);
131     if (!floatpntr) {
132         throw param_not_float_param();
133     }
134     return floatpntr->get();
135 }
136 
get_string() const137 const char *InxParameter::get_string() const
138 {
139     ParamString const *stringpntr = dynamic_cast<ParamString const *>(this);
140     if (!stringpntr) {
141         throw param_not_string_param();
142     }
143     return stringpntr->get().c_str();
144 }
145 
get_optiongroup() const146 const char *InxParameter::get_optiongroup() const
147 {
148     ParamOptionGroup const *param = dynamic_cast<ParamOptionGroup const *>(this);
149     if (!param) {
150         throw param_not_optiongroup_param();
151     }
152     return param->get().c_str();
153 }
154 
get_optiongroup_contains(const char * value) const155 bool InxParameter::get_optiongroup_contains(const char *value) const
156 {
157     ParamOptionGroup const *param = dynamic_cast<ParamOptionGroup const *>(this);
158     if (!param) {
159         throw param_not_optiongroup_param();
160     }
161     return param->contains(value);
162 }
163 
get_color() const164 unsigned int InxParameter::get_color() const
165 {
166     ParamColor const *param = dynamic_cast<ParamColor const *>(this);
167     if (!param) {
168         throw param_not_color_param();
169     }
170     return param->get();
171 }
172 
set_bool(bool in)173 bool InxParameter::set_bool(bool in)
174 {
175     ParamBool * boolpntr = dynamic_cast<ParamBool *>(this);
176     if (boolpntr == nullptr)
177         throw param_not_bool_param();
178     return boolpntr->set(in);
179 }
180 
set_int(int in)181 int InxParameter::set_int(int in)
182 {
183     ParamInt *intpntr = dynamic_cast<ParamInt *>(this);
184     if (intpntr == nullptr)
185         throw param_not_int_param();
186     return intpntr->set(in);
187 }
188 
set_float(float in)189 float InxParameter::set_float(float in)
190 {
191     ParamFloat * floatpntr;
192     floatpntr = dynamic_cast<ParamFloat *>(this);
193     if (floatpntr == nullptr)
194         throw param_not_float_param();
195     return floatpntr->set(in);
196 }
197 
set_string(const char * in)198 const char *InxParameter::set_string(const char *in)
199 {
200     ParamString * stringpntr = dynamic_cast<ParamString *>(this);
201     if (stringpntr == nullptr)
202         throw param_not_string_param();
203     return stringpntr->set(in).c_str();
204 }
205 
set_optiongroup(const char * in)206 const char *InxParameter::set_optiongroup(const char *in)
207 {
208     ParamOptionGroup *param = dynamic_cast<ParamOptionGroup *>(this);
209     if (!param) {
210         throw param_not_optiongroup_param();
211     }
212     return param->set(in).c_str();
213 }
214 
set_color(unsigned int in)215 unsigned int InxParameter::set_color(unsigned int in)
216 {
217     ParamColor*param = dynamic_cast<ParamColor *>(this);
218     if (param == nullptr)
219         throw param_not_color_param();
220     return param->set(in);
221 }
222 
223 
InxParameter(Inkscape::XML::Node * in_repr,Inkscape::Extension::Extension * ext)224 InxParameter::InxParameter(Inkscape::XML::Node *in_repr, Inkscape::Extension::Extension *ext)
225     : InxWidget(in_repr, ext)
226 {
227     // name (mandatory for all parameters)
228     const char *name = in_repr->attribute("name");
229     if (name) {
230         _name = g_strstrip(g_strdup(name));
231     }
232     if (!_name || !strcmp(_name, "")) {
233         g_warning("Parameter without name in extension '%s'.", _extension->get_id());
234         throw param_no_name();
235     }
236 
237     // gui-text
238     const char *gui_text = in_repr->attribute("gui-text");
239     if (!gui_text) {
240         gui_text = in_repr->attribute("_gui-text"); // backwards-compatibility with underscored variants
241     }
242     if (gui_text) {
243         if (_translatable != NO) { // translate unless explicitly marked untranslatable
244             gui_text = get_translation(gui_text);
245         }
246         _text = g_strdup(gui_text);
247     }
248     if (!_text && !_hidden) {
249         g_warning("Parameter '%s' in extension '%s' is visible but does not have a 'gui-text'.",
250                   _name, _extension->get_id());
251         throw param_no_text();
252     }
253 
254     // gui-description (optional)
255     const char *gui_description = in_repr->attribute("gui-description");
256     if (!gui_description) {
257         gui_description = in_repr->attribute("_gui-description"); // backwards-compatibility with underscored variants
258     }
259     if (gui_description) {
260         if (_translatable != NO) { // translate unless explicitly marked untranslatable
261             gui_description = get_translation(gui_description);
262         }
263         _description = g_strdup(gui_description);
264     }
265 }
266 
~InxParameter()267 InxParameter::~InxParameter()
268 {
269     g_free(_name);
270     _name = nullptr;
271 
272     g_free(_text);
273     _text = nullptr;
274 
275     g_free(_description);
276     _description = nullptr;
277 }
278 
pref_name() const279 Glib::ustring InxParameter::pref_name() const
280 {
281     return Glib::ustring::compose("/extensions/%1.%2", _extension->get_id(), _name);
282 }
283 
value_to_string() const284 std::string InxParameter::value_to_string() const
285 {
286     // if we end up here we're missing a definition of ::string() in one of the subclasses
287     g_critical("InxParameter::value_to_string called from parameter '%s' in extension '%s'", _name, _extension->get_id());
288     g_assert_not_reached();
289     return "";
290 }
291 
292 }  // namespace Extension
293 }  // namespace Inkscape
294 
295 /*
296   Local Variables:
297   mode:c++
298   c-file-style:"stroustrup"
299   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
300   indent-tabs-mode:nil
301   fill-column:99
302   End:
303 */
304 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
305