Code

updated spanish.nsh and inkscape.nsi to reflect latest file-changes
[inkscape.git] / trunk / src / extension / extension.cpp
1 #define __SP_MODULE_C__
2 /** \file
3  *
4  * Inkscape::Extension::Extension: 
5  * the ability to have features that are more modular so that they
6  * can be added and removed easily.  This is the basis for defining
7  * those actions.
8  */
10 /*
11  * Authors:
12  *   Ted Gould <ted@gould.cx>
13  *
14  * Copyright (C) 2002-2005 Authors
15  *
16  * Released under GNU GPL, read the file 'COPYING' for more information
17  */
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
24 #include <glibmm/i18n.h>
25 #include <gtkmm/box.h>
26 #include <gtkmm/label.h>
27 #include <gtkmm/frame.h>
28 #include <gtkmm/table.h>
29 #include <gtkmm/tooltips.h>
31 #include "inkscape.h"
32 #include "extension/implementation/implementation.h"
34 #include "db.h"
35 #include "dependency.h"
36 #include "timer.h"
37 #include "param/parameter.h"
39 namespace Inkscape {
40 namespace Extension {
42 /* Inkscape::Extension::Extension */
44 std::vector<const gchar *> Extension::search_path;
45 std::ofstream Extension::error_file;
47 Parameter * param_shared (const gchar * name, GSList * list);
49 /**
50     \return  none
51     \brief   Constructs an Extension from a Inkscape::XML::Node
52     \param   in_repr    The repr that should be used to build it
54     This function is the basis of building an extension for Inkscape.  It
55     currently extracts the fields from the Repr that are used in the
56     extension.  The Repr will likely include other children that are
57     not related to the module directly.  If the Repr does not include
58     a name and an ID the module will be left in an errored state.
59 */
60 Extension::Extension (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp) : _help(NULL)
61 {
62     repr = in_repr;
63     Inkscape::GC::anchor(in_repr);
65     id = NULL;
66     name = NULL;
67     _state = STATE_UNLOADED;
68     parameters = NULL;
70     if (in_imp == NULL) {
71         imp = new Implementation::Implementation();
72     } else {
73         imp = in_imp;
74     }
76     // printf("Extension Constructor: ");
77     if (repr != NULL) {
78         Inkscape::XML::Node *child_repr = sp_repr_children(repr);
79         /* TODO: Handle what happens if we don't have these two */
80         while (child_repr != NULL) {
81             char const * chname = child_repr->name();
82                         if (!strncmp(chname, INKSCAPE_EXTENSION_NS_NC, strlen(INKSCAPE_EXTENSION_NS_NC))) {
83                                 chname += strlen(INKSCAPE_EXTENSION_NS);
84                         }
85             if (chname[0] == '_') /* Allow _ for translation of tags */
86                 chname++;
87             if (!strcmp(chname, "id")) {
88                 gchar const *val = sp_repr_children(child_repr)->content();
89                 id = g_strdup (val);
90             } /* id */
91             if (!strcmp(chname, "name")) {
92                 name = g_strdup (sp_repr_children(child_repr)->content());
93             } /* name */
94             if (!strcmp(chname, "help")) {
95                 _help = g_strdup (sp_repr_children(child_repr)->content());
96             } /* name */
97             if (!strcmp(chname, "param") || !strcmp(chname, "_param")) {
98                 Parameter * param;
99                 param = Parameter::make(child_repr, this);
100                 if (param != NULL)
101                     parameters = g_slist_append(parameters, param);
102             } /* param || _param */
103             if (!strcmp(chname, "dependency")) {
104                 _deps.push_back(new Dependency(child_repr));
105             } /* dependency */
106             child_repr = sp_repr_next(child_repr);
107         }
109         db.register_ext (this);
110     }
111     // printf("%s\n", name);
112     timer = NULL;
114     return;
117 /**
118     \return   none
119     \brief    Destroys the Extension
121     This function frees all of the strings that could be attached
122     to the extension and also unreferences the repr.  This is better
123     than freeing it because it may (I wouldn't know why) be referenced
124     in another place.
125 */
126 Extension::~Extension (void)
128 //    printf("Extension Destructor: %s\n", name);
129     set_state(STATE_UNLOADED);
130     db.unregister_ext(this);
131     Inkscape::GC::release(repr);
132     g_free(id);
133     g_free(name);
134     delete timer;
135     timer = NULL;
136     /** \todo Need to do parameters here */
137     
138     // delete parameters: 
139     for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
140         Parameter * param = reinterpret_cast<Parameter *>(list->data);
141         delete param;
142     }
143     g_slist_free(parameters);
144     
145     
146     for (unsigned int i = 0 ; i < _deps.size(); i++) {
147         delete _deps[i];
148     }
149     _deps.clear();
151     return;
154 /**
155     \return   none
156     \brief    A function to set whether the extension should be loaded
157               or unloaded
158     \param    in_state  Which state should the extension be in?
160     It checks to see if this is a state change or not.  If we're changing
161     states it will call the appropriate function in the implementation,
162     load or unload.  Currently, there is no error checking in this
163     function.  There should be.
164 */
165 void
166 Extension::set_state (state_t in_state)
168     if (_state == STATE_DEACTIVATED) return;
169     if (in_state != _state) {
170         /** \todo Need some more error checking here! */
171         switch (in_state) {
172             case STATE_LOADED:
173                 if (imp->load(this))
174                     _state = STATE_LOADED;
176                 if (timer != NULL) {
177                     delete timer;
178                 }
179                 timer = new ExpirationTimer(this);
181                 break;
182             case STATE_UNLOADED:
183                 // std::cout << "Unloading: " << name << std::endl;
184                 imp->unload(this);
185                 _state = STATE_UNLOADED;
187                 if (timer != NULL) {
188                     delete timer;
189                     timer = NULL;
190                 }
191                 break;
192             case STATE_DEACTIVATED:
193                 _state = STATE_DEACTIVATED;
195                 if (timer != NULL) {
196                     delete timer;
197                     timer = NULL;
198                 }
199                 break;
200             default:
201                 break;
202         }
203     }
205     return;
208 /**
209     \return   The state the extension is in
210     \brief    A getter for the state variable.
211 */
212 Extension::state_t
213 Extension::get_state (void)
215     return _state;
218 /**
219     \return  Whether the extension is loaded or not
220     \brief   A quick function to test the state of the extension
221 */
222 bool
223 Extension::loaded (void)
225     return get_state() == STATE_LOADED;
228 /**
229     \return  A boolean saying whether the extension passed the checks
230     \brief   A function to check the validity of the extension
232     This function chekcs to make sure that there is an id, a name, a
233     repr and an implemenation for this extension.  Then it checks all
234     of the dependencies to see if they pass.  Finally, it asks the
235     implmentation to do a check of itself.
237     On each check, if there is a failure, it will print a message to the
238     error log for that failure.  It is important to note that the function
239     keeps executing if it finds an error, to try and get as many of them
240     into the error log as possible.  This should help people debug
241     installations, and figure out what they need to get for the full
242     functionality of Inkscape to be available.
243 */
244 bool
245 Extension::check (void)
247     bool retval = true;
249     // static int i = 0;
250     // std::cout << "Checking module[" << i++ << "]: " << name << std::endl;
252     const char * inx_failure = _("  This is caused by an improper .inx file for this extension."
253                                  "  An improper .inx file could have been caused by a faulty installation of Inkscape.");
254     if (id == NULL) {
255         printFailure(Glib::ustring(_("an ID was not defined for it.")) + inx_failure);
256         retval = false;
257     }
258     if (name == NULL) {
259         printFailure(Glib::ustring(_("there was no name defined for it.")) + inx_failure);
260         retval = false;
261     }
262     if (repr == NULL) {
263         printFailure(Glib::ustring(_("the XML description of it got lost.")) + inx_failure);
264         retval = false;
265     }
266     if (imp == NULL) {
267         printFailure(Glib::ustring(_("no implementation was defined for the extension.")) + inx_failure);
268         retval = false;
269     }
271     for (unsigned int i = 0 ; i < _deps.size(); i++) {
272         if (_deps[i]->check() == FALSE) {
273             // std::cout << "Failed: " << *(_deps[i]) << std::endl;
274             printFailure(Glib::ustring(_("a dependency was not met.")));
275             error_file << *_deps[i] << std::endl;
276             retval = false;
277         }
278     }
280     if (retval)
281         return imp->check(this);
282     return retval;
285 /** \brief A quick function to print out a standard start of extension
286            errors in the log.
287     \param reason  A string explaining why this failed
289     Real simple, just put everything into \c error_file.
290 */
291 void
292 Extension::printFailure (Glib::ustring reason)
294     error_file << _("Extension \"") << name << _("\" failed to load because ");
295     error_file << reason.raw();
296     error_file << std::endl;
297     return;
300 /**
301     \return  The XML tree that is used to define the extension
302     \brief   A getter for the internal Repr, does not add a reference.
303 */
304 Inkscape::XML::Node *
305 Extension::get_repr (void)
307     return repr;
310 /**
311     \return  The textual id of this extension
312     \brief   Get the ID of this extension - not a copy don't delete!
313 */
314 gchar *
315 Extension::get_id (void)
317     return id;
320 /**
321     \return  The textual name of this extension
322     \brief   Get the name of this extension - not a copy don't delete!
323 */
324 gchar *
325 Extension::get_name (void)
327     return name;
330 /**
331     \return  None
332     \brief   This function diactivates the extension (which makes it
333              unusable, but not deleted)
335     This function is used to removed an extension from functioning, but
336     not delete it completely.  It sets the state to \c STATE_DEACTIVATED to
337     mark to the world that it has been deactivated.  It also removes
338     the current implementation and replaces it with a standard one.  This
339     makes it so that we don't have to continually check if there is an
340     implementation, but we are gauranteed to have a benign one.
342     \warning It is important to note that there is no 'activate' function.
343     Running this function is irreversable.
344 */
345 void
346 Extension::deactivate (void)
348     set_state(STATE_DEACTIVATED);
350     /* Removing the old implementation, and making this use the default. */
351     /* This should save some memory */
352     delete imp;
353     imp = new Implementation::Implementation();
355     return;
358 /**
359     \return  Whether the extension has been deactivated
360     \brief   Find out the status of the extension
361 */
362 bool
363 Extension::deactivated (void)
365     return get_state() == STATE_DEACTIVATED;
368 /**
369     \return    Parameter structure with a name of 'name'
370     \brief     This function looks through the linked list for a parameter
371                structure with the name of the passed in name
372     \param     name   The name to search for
373     \param     list   The list to look for
375     This is an inline function that is used by all the get_param and
376     set_param functions to find a param_t in the linked list with
377     the passed in name.  It is done as an inline so that it will be
378     optimized into a 'jump' by the compiler.
380     This function can throw a 'param_not_exist' exception if the
381     name is not found.
383     The first thing that this function checks is if the list is NULL.
384     It could be NULL because there are no parameters for this extension
385     or because all of them have been checked (I'll spoil the ending and
386     tell you that this function is called recursively).  If the list
387     is NULL then the 'param_not_exist' exception is thrown.
389     Otherwise, the function looks at the current param_t that the element
390     list points to.  If the name of that param_t matches the passed in
391     name then that param_t is returned.  Otherwise, this function is
392     called again with g_slist_next as a parameter.
393 */
394 Parameter *
395 param_shared (const gchar * name, GSList * list)
397     Parameter * output;
399     if (name == NULL) {
400         throw Extension::param_not_exist();
401     }
402     if (list == NULL) {
403         throw Extension::param_not_exist();
404     }
406     output = static_cast<Parameter *>(list->data);
407     if (!strcmp(output->name(), name)) {
408         return output;
409     }
411     return param_shared(name, g_slist_next(list));
414 /**
415     \return   A constant pointer to the string held by the parameters.
416     \brief    Gets a parameter identified by name with the string placed
417               in value.  It isn't duplicated into the value string.
418     \param    name    The name of the parameter to get
419     \param    doc    The document to look in for document specific parameters
420     \param    node   The node to look in for a specific parameter
422     Look up in the parameters list, then execute the function on that
423     found parameter.
424 */
425 const gchar *
426 Extension::get_param_string (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node)
428     Parameter * param;
430     param = param_shared(name, parameters);
431     return param->get_string(doc, node);
434 const gchar *
435 Extension::get_param_enum (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node)
437     Parameter* param = param_shared(name, parameters);
438     return param->get_enum(doc, node);
441 /**
442     \return   The value of the parameter identified by the name
443     \brief    Gets a parameter identified by name with the bool placed
444               in value.
445     \param    name    The name of the parameter to get
446     \param    doc    The document to look in for document specific parameters
447     \param    node   The node to look in for a specific parameter
449     Look up in the parameters list, then execute the function on that
450     found parameter.
451 */
452 bool
453 Extension::get_param_bool (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node)
455     Parameter * param;
457     param = param_shared(name, parameters);
458     return param->get_bool(doc, node);
461 /**
462     \return   The integer value for the parameter specified
463     \brief    Gets a parameter identified by name with the integer placed
464               in value.
465     \param    name    The name of the parameter to get
466     \param    doc    The document to look in for document specific parameters
467     \param    node   The node to look in for a specific parameter
469     Look up in the parameters list, then execute the function on that
470     found parameter.
471 */
472 int
473 Extension::get_param_int (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node)
475     Parameter * param;
477     param = param_shared(name, parameters);
478     return param->get_int(doc, node);
481 /**
482     \return   The float value for the parameter specified
483     \brief    Gets a parameter identified by name with the float placed
484               in value.
485     \param    name    The name of the parameter to get
486     \param    doc    The document to look in for document specific parameters
487     \param    node   The node to look in for a specific parameter
489     Look up in the parameters list, then execute the function on that
490     found parameter.
491 */
492 float
493 Extension::get_param_float (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node)
495     Parameter * param;
496     param = param_shared(name, parameters);
497     return param->get_float(doc, node);
500 /**
501     \return   The string value for the parameter specified
502     \brief    Gets a parameter identified by name with the float placed
503               in value.
504     \param    name    The name of the parameter to get
505     \param    doc    The document to look in for document specific parameters
506     \param    node   The node to look in for a specific parameter
508     Look up in the parameters list, then execute the function on that
509     found parameter.
510 */
511 guint32
512 Extension::get_param_color (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node)
514     Parameter* param = param_shared(name, parameters);
515     return param->get_color(doc, node);
518 /**
519     \return   The passed in value
520     \brief    Sets a parameter identified by name with the boolean
521               in the parameter value.
522     \param    name    The name of the parameter to set
523     \param    value   The value to set the parameter to
524     \param    doc    The document to look in for document specific parameters
525     \param    node   The node to look in for a specific parameter
527     Look up in the parameters list, then execute the function on that
528     found parameter.
529 */
530 bool
531 Extension::set_param_bool (const gchar * name, bool value, SPDocument * doc, Inkscape::XML::Node * node)
533     Parameter * param;
534     param = param_shared(name, parameters);
535     return param->set_bool(value, doc, node);
538 /**
539     \return   The passed in value
540     \brief    Sets a parameter identified by name with the integer
541               in the parameter value.
542     \param    name    The name of the parameter to set
543     \param    value   The value to set the parameter to
544     \param    doc    The document to look in for document specific parameters
545     \param    node   The node to look in for a specific parameter
547     Look up in the parameters list, then execute the function on that
548     found parameter.
549 */
550 int
551 Extension::set_param_int (const gchar * name, int value, SPDocument * doc, Inkscape::XML::Node * node)
553     Parameter * param;
554     param = param_shared(name, parameters);
555     return param->set_int(value, doc, node);
558 /**
559     \return   The passed in value
560     \brief    Sets a parameter identified by name with the integer
561               in the parameter value.
562     \param    name    The name of the parameter to set
563     \param    value   The value to set the parameter to
564     \param    doc    The document to look in for document specific parameters
565     \param    node   The node to look in for a specific parameter
567     Look up in the parameters list, then execute the function on that
568     found parameter.
569 */
570 float
571 Extension::set_param_float (const gchar * name, float value, SPDocument * doc, Inkscape::XML::Node * node)
573     Parameter * param;
574     param = param_shared(name, parameters);
575     return param->set_float(value, doc, node);
578 /**
579     \return   The passed in value
580     \brief    Sets a parameter identified by name with the string
581               in the parameter value.
582     \param    name    The name of the parameter to set
583     \param    value   The value to set the parameter to
584     \param    doc    The document to look in for document specific parameters
585     \param    node   The node to look in for a specific parameter
587     Look up in the parameters list, then execute the function on that
588     found parameter.
589 */
590 const gchar *
591 Extension::set_param_string (const gchar * name, const gchar * value, SPDocument * doc, Inkscape::XML::Node * node)
593     Parameter * param;
594     param = param_shared(name, parameters);
595     return param->set_string(value, doc, node);
598 /**
599     \return   The passed in value
600     \brief    Sets a parameter identified by name with the string
601               in the parameter value.
602     \param    name    The name of the parameter to set
603     \param    value   The value to set the parameter to
604     \param    doc    The document to look in for document specific parameters
605     \param    node   The node to look in for a specific parameter
607     Look up in the parameters list, then execute the function on that
608     found parameter.
609 */
610 guint32
611 Extension::set_param_color (const gchar * name, guint32 color, SPDocument * doc, Inkscape::XML::Node * node)
613     Parameter* param = param_shared(name, parameters);
614     return param->set_color(color, doc, node);
617 /** \brief A function to open the error log file. */
618 void
619 Extension::error_file_open (void)
621     gchar * ext_error_file = profile_path(EXTENSION_ERROR_LOG_FILENAME);
622     gchar * filename = g_filename_from_utf8( ext_error_file, -1, NULL, NULL, NULL );
623     error_file.open(filename);
624     if (!error_file.is_open()) {
625         g_warning(_("Could not create extension error log file '%s'"),
626                   filename);
627     }
628     g_free(filename);
629     g_free(ext_error_file);
630 };
632 /** \brief A function to close the error log file. */
633 void
634 Extension::error_file_close (void)
636     error_file.close();
637 };
639 /** \brief  A widget to represent the inside of an AutoGUI widget */
640 class AutoGUI : public Gtk::VBox {
641     Gtk::Tooltips _tooltips;
642 public:
643     /** \brief  Create an AutoGUI object */
644     AutoGUI (void) : Gtk::VBox() {};
645     /** \brief  Adds a widget with a tool tip into the autogui
646         \param  widg  Widget to add
647         \param  tooltip   Tooltip for the widget
648         
649         If there is no widget, nothing happens.  Otherwise it is just
650         added into the VBox.  If there is a tooltip (non-NULL) then it
651         is placed on the widget.
652     */
653     void addWidget (Gtk::Widget * widg, gchar const * tooltip) {
654         if (widg == NULL) return;
655         this->pack_start(*widg, true, true, 2);
656         if (tooltip != NULL) {
657             _tooltips.set_tip(*widg, Glib::ustring(tooltip));
658         }
659         return;
660     };
661 };
663 /** \brief  A function to automatically generate a GUI using the parameters
664     \return Generated widget
666     This function just goes through each parameter, and calls it's 'get_widget'
667     function to get each widget.  Then, each of those is placed into
668     a Gtk::VBox, which is then returned to the calling function.
670     If there are no visible parameters, this function just returns NULL.
671     If all parameters are gui_visible = false NULL is returned as well.    
672 */
673 Gtk::Widget *
674 Extension::autogui (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
676     if (param_visible_count() == 0) return NULL;
678     AutoGUI * agui = Gtk::manage(new AutoGUI());
680     //go through the list of parameters to see if there are any non-hidden ones
681     for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
682         Parameter * param = reinterpret_cast<Parameter *>(list->data);
683         if (param->get_gui_hidden()) continue; //Ignore hidden parameters
684         Gtk::Widget * widg = param->get_widget(doc, node, changeSignal);
685         gchar const * tip = param->get_tooltip();
686         agui->addWidget(widg, tip);
687     }    
688     
689     agui->show();
690     return agui;
691 };
693 /**
694     \brief  A function to get the parameters in a string form
695     \return An array with all the parameters in it.
697 */
698 void
699 Extension::paramListString (std::list <std::string> &retlist)
701     for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
702         Parameter * param = reinterpret_cast<Parameter *>(list->data);
703         param->string(retlist);
704     }
706     return;
709 /* Extension editor dialog stuff */
711 Gtk::VBox *
712 Extension::get_info_widget(void)
714     Gtk::VBox * retval = Gtk::manage(new Gtk::VBox());
716     Gtk::Frame * info = Gtk::manage(new Gtk::Frame("General Extension Information"));
717     retval->pack_start(*info, true, true, 5);
719     Gtk::Table * table = Gtk::manage(new Gtk::Table());
720     info->add(*table);
722     int row = 0;
723     add_val(_("Name:"), _(name), table, &row);
724     add_val(_("ID:"), id, table, &row);
725     add_val(_("State:"), _state == STATE_LOADED ? _("Loaded") : _state == STATE_UNLOADED ? _("Unloaded") : _("Deactivated"), table, &row);
728     retval->show_all();
729     return retval;
732 void
733 Extension::add_val(Glib::ustring labelstr, Glib::ustring valuestr, Gtk::Table * table, int * row)
735     Gtk::Label * label;
736     Gtk::Label * value;
738     (*row)++; 
739     label = Gtk::manage(new Gtk::Label(labelstr));
740     value = Gtk::manage(new Gtk::Label(valuestr));
741     table->attach(*label, 0, 1, (*row) - 1, *row);
742     table->attach(*value, 1, 2, (*row) - 1, *row);
744     label->show();
745     value->show();
747     return;
750 Gtk::VBox *
751 Extension::get_help_widget(void)
753     Gtk::VBox * retval = Gtk::manage(new Gtk::VBox());
755     if (_help == NULL) {
756         Gtk::Label * content = Gtk::manage(new Gtk::Label(_("Currently there is no help available for this Extension.  Please look on the Inkscape website or ask on the mailing lists if you have questions regarding this extension.")));
757         retval->pack_start(*content, true, true, 5);
758         content->set_line_wrap(true);
759         content->show();
760     } else {
764     }
766     retval->show();
767     return retval;
770 Gtk::VBox *
771 Extension::get_params_widget(void)
773     Gtk::VBox * retval = Gtk::manage(new Gtk::VBox());
774     Gtk::Widget * content = Gtk::manage(new Gtk::Label("Params"));
775     retval->pack_start(*content, true, true, 5);
776     content->show();
777     retval->show();
778     return retval;
781 unsigned int Extension::param_visible_count ( ) 
783     unsigned int _visible_count = 0;
784     for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
785         Parameter * param = reinterpret_cast<Parameter *>(list->data);
786         if (!param->get_gui_hidden()) _visible_count++;
787     }    
788     return _visible_count;
791 }  /* namespace Extension */
792 }  /* namespace Inkscape */
795 /*
796   Local Variables:
797   mode:c++
798   c-file-style:"stroustrup"
799   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
800   indent-tabs-mode:nil
801   fill-column:99
802   End:
803 */
804 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :