Code

Added curves
[inkscape.git] / 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>
30 #include "inkscape.h"
31 #include "extension/implementation/implementation.h"
33 #include "db.h"
34 #include "dependency.h"
35 #include "timer.h"
36 #include "parameter.h"
38 namespace Inkscape {
39 namespace Extension {
41 /* Inkscape::Extension::Extension */
43 std::vector<const gchar *> Extension::search_path;
44 std::ofstream Extension::error_file;
46 Parameter * param_shared (const gchar * name, GSList * list);
48 /**
49     \return  none
50     \brief   Constructs an Extension from a Inkscape::XML::Node
51     \param   in_repr    The repr that should be used to build it
53     This function is the basis of building an extension for Inkscape.  It
54     currently extracts the fields from the Repr that are used in the
55     extension.  The Repr will likely include other children that are
56     not related to the module directly.  If the Repr does not include
57     a name and an ID the module will be left in an errored state.
58 */
59 Extension::Extension (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp) : _help(NULL)
60 {
61     repr = in_repr;
62     Inkscape::GC::anchor(in_repr);
64     id = NULL;
65     name = NULL;
66     _state = STATE_UNLOADED;
67     parameters = NULL;
69     if (in_imp == NULL) {
70         imp = new Implementation::Implementation();
71     } else {
72         imp = in_imp;
73     }
75     // printf("Extension Constructor: ");
76     if (repr != NULL) {
77         Inkscape::XML::Node *child_repr = sp_repr_children(repr);
78         /* TODO: Handle what happens if we don't have these two */
79         while (child_repr != NULL) {
80             char const * chname = child_repr->name();
81             if (chname[0] == '_') /* Allow _ for translation of tags */
82                 chname++;
83             if (!strcmp(chname, "id")) {
84                 gchar const *val = sp_repr_children(child_repr)->content();
85                 id = g_strdup (val);
86             } /* id */
87             if (!strcmp(chname, "name")) {
88                 name = g_strdup (sp_repr_children(child_repr)->content());
89             } /* name */
90             if (!strcmp(chname, "help")) {
91                 _help = g_strdup (sp_repr_children(child_repr)->content());
92             } /* name */
93             if (!strcmp(chname, "param")) {
94                                 Parameter * param;
95                                 param = Parameter::make(child_repr, this);
96                                 if (param != NULL)
97                                         parameters = g_slist_append(parameters, param);
98             } /* param */
99             if (!strcmp(chname, "dependency")) {
100                 _deps.push_back(new Dependency(child_repr));
101             } /* param */
102             child_repr = sp_repr_next(child_repr);
103         }
105         db.register_ext (this);
106     }
107     // printf("%s\n", name);
108         timer = NULL;
110     return;
113 /**
114     \return   none
115     \brief    Destroys the Extension
117     This function frees all of the strings that could be attached
118     to the extension and also unreferences the repr.  This is better
119     than freeing it because it may (I wouldn't know why) be referenced
120     in another place.
121 */
122 Extension::~Extension (void)
124 //      printf("Extension Destructor: %s\n", name);
125         set_state(STATE_UNLOADED);
126         db.unregister_ext(this);
127     Inkscape::GC::release(repr);
128     g_free(id);
129     g_free(name);
130         delete timer;
131         timer = NULL;
132     /** \todo Need to do parameters here */
134         for (unsigned int i = 0 ; i < _deps.size(); i++) {
135                 delete _deps[i];
136         }
137         _deps.clear();
139     return;
142 /**
143     \return   none
144     \brief    A function to set whether the extension should be loaded
145               or unloaded
146     \param    in_state  Which state should the extension be in?
148     It checks to see if this is a state change or not.  If we're changing
149     states it will call the appropriate function in the implementation,
150     load or unload.  Currently, there is no error checking in this
151     function.  There should be.
152 */
153 void
154 Extension::set_state (state_t in_state)
156         if (_state == STATE_DEACTIVATED) return;
157     if (in_state != _state) {
158         /** \todo Need some more error checking here! */
159                 switch (in_state) {
160                         case STATE_LOADED:
161                                 if (imp->load(this))
162                                         _state = STATE_LOADED;
164                                 if (timer != NULL) {
165                                         delete timer;
166                                 }
167                                 timer = new ExpirationTimer(this);
169                                 break;
170                         case STATE_UNLOADED:
171                                 // std::cout << "Unloading: " << name << std::endl;
172                                 imp->unload(this);
173                                 _state = STATE_UNLOADED;
175                                 if (timer != NULL) {
176                                         delete timer;
177                                         timer = NULL;
178                                 }
179                                 break;
180                         case STATE_DEACTIVATED:
181                                 _state = STATE_DEACTIVATED;
183                                 if (timer != NULL) {
184                                         delete timer;
185                                         timer = NULL;
186                                 }
187                                 break;
188                         default:
189                                 break;
190                 }
191     }
193     return;
196 /**
197     \return   The state the extension is in
198     \brief    A getter for the state variable.
199 */
200 Extension::state_t
201 Extension::get_state (void)
203     return _state;
206 /**
207     \return  Whether the extension is loaded or not
208     \brief   A quick function to test the state of the extension
209 */
210 bool
211 Extension::loaded (void)
213     return get_state() == STATE_LOADED;
216 /**
217     \return  A boolean saying whether the extension passed the checks
218         \brief   A function to check the validity of the extension
220         This function chekcs to make sure that there is an id, a name, a
221         repr and an implemenation for this extension.  Then it checks all
222         of the dependencies to see if they pass.  Finally, it asks the
223         implmentation to do a check of itself.
225         On each check, if there is a failure, it will print a message to the
226         error log for that failure.  It is important to note that the function
227         keeps executing if it finds an error, to try and get as many of them
228         into the error log as possible.  This should help people debug
229         installations, and figure out what they need to get for the full
230         functionality of Inkscape to be available.
231 */
232 bool
233 Extension::check (void)
235         bool retval = true;
237         // static int i = 0;
238         // std::cout << "Checking module[" << i++ << "]: " << name << std::endl;
240         const char * inx_failure = _("  This is caused by an improper .inx file for this extension."
241                                          "  An improper .inx file could have been caused by a faulty installation of Inkscape.");
242         if (id == NULL) {
243                 printFailure(Glib::ustring(_("an ID was not defined for it.")) + inx_failure);
244                 retval = false;
245         }
246         if (name == NULL) {
247                 printFailure(Glib::ustring(_("there was no name defined for it.")) + inx_failure);
248                 retval = false;
249         }
250         if (repr == NULL) {
251                 printFailure(Glib::ustring(_("the XML description of it got lost.")) + inx_failure);
252                 retval = false;
253         }
254         if (imp == NULL) {
255                 printFailure(Glib::ustring(_("no implementation was defined for the extension.")) + inx_failure);
256                 retval = false;
257         }
259         for (unsigned int i = 0 ; i < _deps.size(); i++) {
260                 if (_deps[i]->check() == FALSE) {
261                         // std::cout << "Failed: " << *(_deps[i]) << std::endl;
262                         printFailure(Glib::ustring(_("a dependency was not met.")));
263                         error_file << *_deps[i] << std::endl;
264                         retval = false;
265                 }
266         }
268         if (retval)
269                 return imp->check(this);
270         return retval;
273 /** \brief A quick function to print out a standard start of extension
274            errors in the log.
275         \param reason  A string explaining why this failed
277         Real simple, just put everything into \c error_file.
278 */
279 void
280 Extension::printFailure (Glib::ustring reason)
282         error_file << _("Extension \"") << name << _("\" failed to load because ");
283         error_file << reason;
284         error_file << std::endl;
285         return;
288 /**
289     \return  The XML tree that is used to define the extension
290     \brief   A getter for the internal Repr, does not add a reference.
291 */
292 Inkscape::XML::Node *
293 Extension::get_repr (void)
295     return repr;
298 /**
299     \return  The textual id of this extension
300     \brief   Get the ID of this extension - not a copy don't delete!
301 */
302 gchar *
303 Extension::get_id (void)
305     return id;
308 /**
309     \return  The textual name of this extension
310     \brief   Get the name of this extension - not a copy don't delete!
311 */
312 gchar *
313 Extension::get_name (void)
315     return name;
318 /**
319     \return  None
320         \brief   This function diactivates the extension (which makes it
321                  unusable, but not deleted)
323     This function is used to removed an extension from functioning, but
324         not delete it completely.  It sets the state to \c STATE_DEACTIVATED to
325         mark to the world that it has been deactivated.  It also removes
326         the current implementation and replaces it with a standard one.  This
327         makes it so that we don't have to continually check if there is an
328         implementation, but we are gauranteed to have a benign one.
330         \warning It is important to note that there is no 'activate' function.
331         Running this function is irreversable.
332 */
333 void
334 Extension::deactivate (void)
336         set_state(STATE_DEACTIVATED);
338         /* Removing the old implementation, and making this use the default. */
339         /* This should save some memory */
340         delete imp;
341         imp = new Implementation::Implementation();
343         return;
346 /**
347     \return  Whether the extension has been deactivated
348         \brief   Find out the status of the extension
349 */
350 bool
351 Extension::deactivated (void)
353         return get_state() == STATE_DEACTIVATED;
356 /**
357     \return    Parameter structure with a name of 'name'
358     \brief     This function looks through the linked list for a parameter
359                structure with the name of the passed in name
360     \param     name   The name to search for
361     \param     list   The list to look for
363     This is an inline function that is used by all the get_param and
364     set_param functions to find a param_t in the linked list with
365     the passed in name.  It is done as an inline so that it will be
366     optimized into a 'jump' by the compiler.
368     This function can throw a 'param_not_exist' exception if the
369     name is not found.
371     The first thing that this function checks is if the list is NULL.
372     It could be NULL because there are no parameters for this extension
373     or because all of them have been checked (I'll spoil the ending and
374     tell you that this function is called recursively).  If the list
375     is NULL then the 'param_not_exist' exception is thrown.
377     Otherwise, the function looks at the current param_t that the element
378     list points to.  If the name of that param_t matches the passed in
379     name then that param_t is returned.  Otherwise, this function is
380     called again with g_slist_next as a parameter.
381 */
382 Parameter *
383 param_shared (const gchar * name, GSList * list)
385     Parameter * output;
387     if (name == NULL) {
388         throw Extension::param_not_exist();
389     }
390     if (list == NULL) {
391         throw Extension::param_not_exist();
392     }
394     output = static_cast<Parameter *>(list->data);
395     if (!strcmp(output->name(), name)) {
396         return output;
397     }
399     return param_shared(name, g_slist_next(list));
402 /**
403     \return   A constant pointer to the string held by the parameters.
404     \brief    Gets a parameter identified by name with the string placed
405               in value.  It isn't duplicated into the value string.
406     \param    name    The name of the parameter to get
407         \param    doc    The document to look in for document specific parameters
409         Look up in the parameters list, then execute the function on that
410         found parameter.
411 */
412 const gchar *
413 Extension::get_param_string (const gchar * name, const Inkscape::XML::Document * doc)
415     Parameter * param;
417     param = param_shared(name, parameters);
418         return param->get_string(doc);
421 /**
422     \return   The value of the parameter identified by the name
423     \brief    Gets a parameter identified by name with the bool placed
424               in value.
425     \param    name    The name of the parameter to get
426         \param    doc    The document to look in for document specific parameters
428         Look up in the parameters list, then execute the function on that
429         found parameter.
430 */
431 bool
432 Extension::get_param_bool (const gchar * name, const Inkscape::XML::Document * doc)
434     Parameter * param;
436     param = param_shared(name, parameters);
437     return param->get_bool(doc);
440 /**
441     \return   The integer value for the parameter specified
442     \brief    Gets a parameter identified by name with the integer placed
443               in value.
444     \param    name    The name of the parameter to get
445         \param    doc    The document to look in for document specific parameters
447         Look up in the parameters list, then execute the function on that
448         found parameter.
449 */
450 int
451 Extension::get_param_int (const gchar * name, const Inkscape::XML::Document * doc)
453     Parameter * param;
455     param = param_shared(name, parameters);
456     return param->get_int(doc);
459 /**
460     \return   The float value for the parameter specified
461     \brief    Gets a parameter identified by name with the float placed
462               in value.
463     \param    name    The name of the parameter to get
464         \param    doc    The document to look in for document specific parameters
466         Look up in the parameters list, then execute the function on that
467         found parameter.
468 */
469 float
470 Extension::get_param_float (const gchar * name, const Inkscape::XML::Document * doc)
472     Parameter * param;
473     param = param_shared(name, parameters);
474     return param->get_float(doc);
477 /**
478     \return   The passed in value
479     \brief    Sets a parameter identified by name with the boolean
480               in the parameter value.
481     \param    name    The name of the parameter to set
482     \param    value   The value to set the parameter to
483         \param    doc    The document to look in for document specific parameters
485         Look up in the parameters list, then execute the function on that
486         found parameter.
487 */
488 bool
489 Extension::set_param_bool (const gchar * name, bool value, Inkscape::XML::Document * doc)
491     Parameter * param;
492     param = param_shared(name, parameters);
493         return param->set_bool(value, doc);
496 /**
497     \return   The passed in value
498     \brief    Sets a parameter identified by name with the integer
499               in the parameter value.
500     \param    name    The name of the parameter to set
501     \param    value   The value to set the parameter to
502         \param    doc    The document to look in for document specific parameters
504         Look up in the parameters list, then execute the function on that
505         found parameter.
506 */
507 int
508 Extension::set_param_int (const gchar * name, int value, Inkscape::XML::Document * doc)
510     Parameter * param;
511     param = param_shared(name, parameters);
512         return param->set_int(value, doc);
515 /**
516     \return   The passed in value
517     \brief    Sets a parameter identified by name with the integer
518               in the parameter value.
519     \param    name    The name of the parameter to set
520     \param    value   The value to set the parameter to
521         \param    doc    The document to look in for document specific parameters
523         Look up in the parameters list, then execute the function on that
524         found parameter.
525 */
526 float
527 Extension::set_param_float (const gchar * name, float value, Inkscape::XML::Document * doc)
529     Parameter * param;
530     param = param_shared(name, parameters);
531         return param->set_float(value, doc);
534 /**
535     \return   The passed in value
536     \brief    Sets a parameter identified by name with the string
537               in the parameter value.
538     \param    name    The name of the parameter to set
539     \param    value   The value to set the parameter to
540         \param    doc    The document to look in for document specific parameters
542         Look up in the parameters list, then execute the function on that
543         found parameter.
544 */
545 const gchar *
546 Extension::set_param_string (const gchar * name, const gchar * value, Inkscape::XML::Document * doc)
548     Parameter * param;
549     param = param_shared(name, parameters);
550         return param->set_string(value, doc);
553 /** \brief A function to open the error log file. */
554 void
555 Extension::error_file_open (void)
557         gchar * ext_error_file = profile_path(EXTENSION_ERROR_LOG_FILENAME);
558         gchar * filename = g_filename_from_utf8( ext_error_file, -1, NULL, NULL, NULL );
559         error_file.open(filename);
560         if (!error_file.is_open()) {
561                 g_warning(_("Could not create extension error log file '%s'"),
562                           filename);
563         }
564         g_free(filename);
565         g_free(ext_error_file);
566 };
568 /** \brief A function to close the error log file. */
569 void
570 Extension::error_file_close (void)
572         error_file.close();
573 };
575 /** \brief  A function to automatically generate a GUI using the parameters
576         \return Generated widget
578         This function just goes through each parameter, and calls it's 'get_widget'
579         function to get each widget.  Then, each of those is placed into
580         a Gtk::VBox, which is then returned to the calling function.
582         If there are no parameters, this function just returns NULL.
583 */
584 Gtk::Widget *
585 Extension::autogui (void)
587         if (g_slist_length(parameters) == 0) return NULL;
589         Gtk::VBox * vbox = new Gtk::VBox();
590     vbox = new Gtk::VBox();
592         for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
593                 Parameter * param = reinterpret_cast<Parameter *>(list->data);
594                 Gtk::Widget * widg = param->get_widget();
595                 if (widg != NULL)
596                         vbox->pack_start(*widg, true, true);
597         }
599         vbox->show();
600         return vbox;
601 };
603 /**
604         \brief  A function to get the parameters in a string form
605         \return A string with all the parameters as command line arguements
607         I don't really like this function, but it works for now.
609         \todo  Do this better.
610 */
611 Glib::ustring *
612 Extension::paramString (void)
614         Glib::ustring * param_string = new Glib::ustring("");
616         for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
617                 Parameter * param = reinterpret_cast<Parameter *>(list->data);
619                 *param_string += " --";
620                 *param_string += param->name();
621                 *param_string += "=";
622                 Glib::ustring * paramstr = param->string();
623                 *param_string += *paramstr;
624                 delete paramstr;
625         }
627         return param_string;
630 /* Extension editor dialog stuff */
632 Gtk::VBox *
633 Extension::get_info_widget(void)
635     Gtk::VBox * retval = Gtk::manage(new Gtk::VBox());
637     Gtk::Frame * info = Gtk::manage(new Gtk::Frame("General Extension Information"));
638     retval->pack_start(*info, true, true, 5);
640     Gtk::Table * table = Gtk::manage(new Gtk::Table());
641     info->add(*table);
643     int row = 0;
644     add_val(_("Name:"), _(name), table, &row);
645     add_val(_("ID:"), id, table, &row);
646     add_val(_("State:"), _state == STATE_LOADED ? _("Loaded") : _state == STATE_UNLOADED ? _("Unloaded") : _("Deactivated"), table, &row);
649     retval->show_all();
650     return retval;
653 void
654 Extension::add_val(Glib::ustring labelstr, Glib::ustring valuestr, Gtk::Table * table, int * row)
656     Gtk::Label * label;
657     Gtk::Label * value;
659     (*row)++; 
660     label = Gtk::manage(new Gtk::Label(labelstr));
661     value = Gtk::manage(new Gtk::Label(valuestr));
662     table->attach(*label, 0, 1, (*row) - 1, *row);
663     table->attach(*value, 1, 2, (*row) - 1, *row);
665     label->show();
666     value->show();
668     return;
671 Gtk::VBox *
672 Extension::get_help_widget(void)
674     Gtk::VBox * retval = Gtk::manage(new Gtk::VBox());
676     if (_help == NULL) {
677         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."));
678         retval->pack_start(*content, true, true, 5);
679         content->set_line_wrap(true);
680         content->show();
681     } else {
685     }
687     retval->show();
688     return retval;
691 Gtk::VBox *
692 Extension::get_params_widget(void)
694     Gtk::VBox * retval = Gtk::manage(new Gtk::VBox());
695     Gtk::Widget * content = Gtk::manage(new Gtk::Label("Params"));
696     retval->pack_start(*content, true, true, 5);
697     content->show();
698     retval->show();
699     return retval;
702 }  /* namespace Extension */
703 }  /* namespace Inkscape */
706 /*
707   Local Variables:
708   mode:c++
709   c-file-style:"stroustrup"
710   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
711   indent-tabs-mode:nil
712   fill-column:99
713   End:
714 */
715 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :