Code

r18381@shi: ted | 2008-03-07 20:11:34 -0800
[inkscape.git] / src / extension / param / notebook.cpp
1 /** \file
2  * Notebook and NotebookPage parameters for extensions.
3  */
5 /*
6  * Author:
7  *   Johan Engelen <johan@shouraizou.nl>
8  *
9  * Copyright (C) 2006 Author
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
19 #include <gtkmm/adjustment.h>
20 #include <gtkmm/box.h>
21 #include <gtkmm/spinbutton.h>
22 #include <gtkmm/notebook.h>
23 #include <gtkmm/tooltips.h>
25 #include <glibmm/i18n.h>
27 #include <xml/node.h>
29 #include <extension/extension.h>
30 #include "prefs-utils.h"
31 #include "document-private.h"
32 #include "sp-object.h"
34 #include "notebook.h"
36 /** \brief  The root directory in the preferences database for extension
37             related parameters. */
38 #define PREF_DIR "extensions"
40 namespace Inkscape {
41 namespace Extension {
44 // \brief  A class to represent the pages of a notebookparameter of an extension
45 class ParamNotebookPage : public Parameter {
46 private:
47     GSList * parameters; /**< A table to store the parameters for this page.
48                               This only gets created if there are parameters on this
49                               page */
50     Gtk::Tooltips * _tooltips;
52 public:
53     static ParamNotebookPage * makepage (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext);
55     ParamNotebookPage(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, Inkscape::XML::Node * xml);
56     ~ParamNotebookPage(void);
57     Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal);
58     void paramString (std::list <std::string> &list);
59     gchar * get_guitext (void) {return _text;};
61 }; /* class ParamNotebookPage */
64 ParamNotebookPage::ParamNotebookPage (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, Inkscape::XML::Node * xml) :
65     Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext)
66 {
67     parameters = NULL;
69     // Read XML to build page
70     if (xml != NULL) {
71         Inkscape::XML::Node *child_repr = sp_repr_children(xml);
72         while (child_repr != NULL) {
73             char const * chname = child_repr->name();
74             if (chname[0] == '_') // Allow _ for translation of tags
75                 chname++;
76             if (!strcmp(chname, "param") || !strcmp(chname, "_param")) {
77                 Parameter * param;
78                 param = Parameter::make(child_repr, ext);
79                 if (param != NULL) parameters = g_slist_append(parameters, param);
80             }
81             child_repr = sp_repr_next(child_repr);
82         }
83     }
85     return;
86 }
88 ParamNotebookPage::~ParamNotebookPage (void)
89 {
90     if (_tooltips) delete _tooltips;
91     //destroy parameters
92     for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
93         Parameter * param = reinterpret_cast<Parameter *>(list->data);
94         delete param;
95     }
96     g_slist_free(parameters);
97 }
99 /** \brief  Return the value as a string */
100 void
101 ParamNotebookPage::paramString (std::list <std::string> &list)
103     for (GSList * plist = parameters; plist != NULL; plist = g_slist_next(plist)) {
104         Parameter * param = reinterpret_cast<Parameter *>(plist->data);
105         param->string(list);
106     }
108     return;
112 /**
113     \return None
114     \brief  This function creates a page that can be used later.  This
115             is typically done in the creation of the notebook and defined
116             in the XML file describing the extension (it's private so people
117             have to use the system) :)
118     \param  in_repr  The XML describing the page
120     This function first grabs all of the data out of the Repr and puts
121     it into local variables.  Actually, these are just pointers, and the
122     data is not duplicated so we need to be careful with it.  If there
123     isn't a name in the XML, then no page is created as
124     the function just returns.
126     From this point on, we're pretty committed as we've allocated an
127     object and we're starting to fill it.  The name is set first, and
128     is created with a strdup to actually allocate memory for it.  Then
129     there is a case statement (roughly because strcmp requires 'ifs')
130     based on what type of parameter this is.  Depending which type it
131     is, the value is interpreted differently, but they are relatively
132     straight forward.  In all cases the value is set to the default
133     value from the XML and the type is set to the interpreted type.
134 */
135 ParamNotebookPage *
136 ParamNotebookPage::makepage (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext)
138     const char * name;
139     const char * guitext;
140     const char * desc;
141     const char * scope_str;
142     Parameter::_scope_t scope = Parameter::SCOPE_USER;
143         bool gui_hidden = false;
144         const char * gui_hide;
145         const char * gui_tip;
147     name = in_repr->attribute("name");
148     guitext = in_repr->attribute("gui-text");
149     if (guitext == NULL)
150         guitext = in_repr->attribute("_gui-text");
151     gui_tip = in_repr->attribute("gui-tip");
152     if (gui_tip == NULL)
153         gui_tip = in_repr->attribute("_gui-tip");
154     desc = in_repr->attribute("gui-description");
155     if (desc == NULL)
156         desc = in_repr->attribute("_gui-description");
157     scope_str = in_repr->attribute("scope");
158         gui_hide = in_repr->attribute("gui-hidden");
159         if (gui_hide != NULL) {
160                 if (strcmp(gui_hide, "1") == 0 ||
161                         strcmp(gui_hide, "true") == 0) {
162                         gui_hidden = true;
163                 }
164                 /* else stays false */
165         }
167     /* In this case we just don't have enough information */
168     if (name == NULL) {
169         return NULL;
170     }
172     if (scope_str != NULL) {
173         if (!strcmp(scope_str, "user")) {
174             scope = Parameter::SCOPE_USER;
175         } else if (!strcmp(scope_str, "document")) {
176             scope = Parameter::SCOPE_DOCUMENT;
177         } else if (!strcmp(scope_str, "node")) {
178             scope = Parameter::SCOPE_NODE;
179         }
180     }
182     ParamNotebookPage * page = new ParamNotebookPage(name, guitext, desc, scope, gui_hide, gui_tip, in_ext, in_repr);
184     /* Note: page could equal NULL */
185     return page;
190 /**
191     \brief  Creates a notebookpage widget for a notebook
193     Builds a notebook page (a vbox) and puts parameters on it.
194 */
195 Gtk::Widget *
196 ParamNotebookPage::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
198         if (_gui_hidden) return NULL;
200     if (!_tooltips) _tooltips = new Gtk::Tooltips();
202     Gtk::VBox * vbox = Gtk::manage(new Gtk::VBox);
203     vbox->set_border_width(5);
205     // add parameters onto page (if any)
206     for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
207         Parameter * param = reinterpret_cast<Parameter *>(list->data);
208         Gtk::Widget * widg = param->get_widget(doc, node, changeSignal);
209         gchar const * tip = param->get_tooltip();
211         vbox->pack_start(*widg, true, true, 2);
212         if (tip != NULL) {
213             _tooltips->set_tip(*widg, Glib::ustring(tip));
214         }
215     }
217     vbox->show();
219     return dynamic_cast<Gtk::Widget *>(vbox);
230 ParamNotebook::ParamNotebook (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, Inkscape::XML::Node * xml) :
231     Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext)
233     pages = NULL;
235     // Read XML tree to add pages:
236     if (xml != NULL) {
237         Inkscape::XML::Node *child_repr = sp_repr_children(xml);
238         while (child_repr != NULL) {
239             char const * chname = child_repr->name();
240             if (chname[0] == '_') // Allow _ for translation of tags
241                 chname++;
242             if (!strcmp(chname, "page")) {
243                 ParamNotebookPage * page;
244                 page = ParamNotebookPage::makepage(child_repr, ext);
245                 if (page != NULL) pages = g_slist_append(pages, page);
246             }
247             child_repr = sp_repr_next(child_repr);
248         }
249     }
251     // Initialize _value with the current page
252     const char * defaultval = NULL;
253     // set first page as default
254     if (pages != NULL) {
255         ParamNotebookPage * defpage = reinterpret_cast<ParamNotebookPage *>(pages->data);
256         defaultval = defpage->name();
257     }
259     gchar * pref_name = this->pref_name();
260     const gchar * paramval = prefs_get_string_attribute(PREF_DIR, pref_name);
261     g_free(pref_name);
263     if (paramval != NULL)
264         defaultval = paramval;
265     if (defaultval != NULL)
266         _value = g_strdup(defaultval);  // allocate space for _value
268     return;
271 ParamNotebook::~ParamNotebook (void)
273     //destroy pages
274     for (GSList * list = pages; list != NULL; list = g_slist_next(list)) {
275         ParamNotebookPage * page = reinterpret_cast<ParamNotebookPage *>(list->data);
276         delete page;
277     }
278     g_slist_free(pages);
280     g_free(_value);
284 /** \brief  A function to set the \c _value
285     \param  in   The number of the page which value must be set
286     \param  doc  A document that should be used to set the value.
287     \param  node The node where the value may be placed
289     This function sets the internal value, but it also sets the value
290     in the preferences structure.  To put it in the right place, \c PREF_DIR
291     and \c pref_name() are used.
293     To copy the data into _value the old memory must be free'd first.
294     It is important to note that \c g_free handles \c NULL just fine.  Then
295     the passed in value is duplicated using \c g_strdup().
296 */
297 const gchar *
298 ParamNotebook::set (const int in, SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/)
300     ParamNotebookPage * page = NULL;
301     int i = 0;
302     for (GSList * list = pages; (list != NULL) && (i <= in); list = g_slist_next(list)) {
303         page = reinterpret_cast<ParamNotebookPage *>(list->data);
304         i++;
305     }
307     if (page == NULL) return _value;
309     if (_value != NULL) g_free(_value);
310     _value = g_strdup(page->name());
312     gchar * prefname = this->pref_name();
313     prefs_set_string_attribute(PREF_DIR, prefname, _value);
314     g_free(prefname);
316     return _value;
320 /**
321     \brief  A function to get the currentpage and the parameters in a string form
322     \return A string with the 'value' and all the parameters on all pages as command line arguments
323 */
324 void
325 ParamNotebook::string (std::list <std::string> &list)
327     std::string param_string;
328     param_string += "--";
329     param_string += name();
330     param_string += "=";
332     param_string += "\"";
333     param_string += _value;  // the name of the current page
334     param_string += "\"";
335     list.insert(list.end(), param_string);
337     for (GSList * pglist = pages; pglist != NULL; pglist = g_slist_next(pglist)) {
338         ParamNotebookPage * page = reinterpret_cast<ParamNotebookPage *>(pglist->data);
339         page->paramString(list);
340     }
342     return;
345 /** \brief  A special category of Gtk::Notebook to handle notebook parameters */
346 class ParamNotebookWdg : public Gtk::Notebook {
347 private:
348     ParamNotebook * _pref;
349     SPDocument * _doc;
350     Inkscape::XML::Node * _node;
351 public:
352     /** \brief  Build a notebookpage preference for the given parameter
353         \param  pref  Where to get the string (pagename) from, and where to put it
354                       when it changes.
355     */
356     ParamNotebookWdg (ParamNotebook * pref, SPDocument * doc, Inkscape::XML::Node * node) :
357         Gtk::Notebook(), _pref(pref), _doc(doc), _node(node), activated(false) {
358         // don't have to set the correct page: this is done in ParamNotebook::get_widget.
359         // hook function
360         this->signal_switch_page().connect(sigc::mem_fun(this, &ParamNotebookWdg::changed_page));
361         return;
362     };
363     void changed_page(GtkNotebookPage *page, guint pagenum);
364     bool activated;
365 };
367 /** \brief  Respond to the selected page of notebook changing
368     This function responds to the changing by reporting it to
369     ParamNotebook. The change is only reported when the notebook
370     is actually visible. This to exclude 'fake' changes when the
371     notebookpages are added or removed.
372 */
373 void
374 ParamNotebookWdg::changed_page(GtkNotebookPage */*page*/,
375                                    guint pagenum)
377     if (is_visible()) {
378         _pref->set((int)pagenum, _doc, _node);
379     }
380     return;
385 /**
386     \brief  Creates a Notebook widget for a notebook parameter
388     Builds a notebook and puts pages in it.
389 */
390 Gtk::Widget *
391 ParamNotebook::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
393         if (_gui_hidden) return NULL;
395     ParamNotebookWdg * nb = Gtk::manage(new ParamNotebookWdg(this, doc, node));
397     // add pages (if any)
398     int i = -1;
399     int pagenr = i;
400     for (GSList * list = pages; list != NULL; list = g_slist_next(list)) {
401         i++;
402         ParamNotebookPage * page = reinterpret_cast<ParamNotebookPage *>(list->data);
403         Gtk::Widget * widg = page->get_widget(doc, node, changeSignal);
404         nb->append_page(*widg, _(page->get_guitext()));
405         if (!strcmp(_value, page->name())) {
406             pagenr = i; // this is the page to be displayed?
407         }
408     }
410     nb->show();
412     if (pagenr >= 0) nb->set_current_page(pagenr);
414     return dynamic_cast<Gtk::Widget *>(nb);
418 }  /* namespace Extension */
419 }  /* namespace Inkscape */
421 /*
422   Local Variables:
423   mode:c++
424   c-file-style:"stroustrup"
425   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
426   indent-tabs-mode:nil
427   fill-column:99
428   End:
429 */
430 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :