Code

r10987@tres: ted | 2006-02-28 01:06:37 -0800
[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>
28 #include "inkscape.h"
29 #include "extension/implementation/implementation.h"
31 #include "db.h"
32 #include "dependency.h"
33 #include "timer.h"
34 #include "parameter.h"
36 namespace Inkscape {
37 namespace Extension {
39 /* Inkscape::Extension::Extension */
41 std::vector<const gchar *> Extension::search_path;
42 std::ofstream Extension::error_file;
44 Parameter * param_shared (const gchar * name, GSList * list);
46 /**
47     \return  none
48     \brief   Constructs an Extension from a Inkscape::XML::Node
49     \param   in_repr    The repr that should be used to build it
51     This function is the basis of building an extension for Inkscape.  It
52     currently extracts the fields from the Repr that are used in the
53     extension.  The Repr will likely include other children that are
54     not related to the module directly.  If the Repr does not include
55     a name and an ID the module will be left in an errored state.
56 */
57 Extension::Extension (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp) : _help(NULL)
58 {
59     repr = in_repr;
60     Inkscape::GC::anchor(in_repr);
62     id = NULL;
63     name = NULL;
64     _state = STATE_UNLOADED;
65     parameters = NULL;
67     if (in_imp == NULL) {
68         imp = new Implementation::Implementation();
69     } else {
70         imp = in_imp;
71     }
73     // printf("Extension Constructor: ");
74     if (repr != NULL) {
75         Inkscape::XML::Node *child_repr = sp_repr_children(repr);
76         /* TODO: Handle what happens if we don't have these two */
77         while (child_repr != NULL) {
78             char const * chname = child_repr->name();
79             if (chname[0] == '_') /* Allow _ for translation of tags */
80                 chname++;
81             if (!strcmp(chname, "id")) {
82                 gchar const *val = sp_repr_children(child_repr)->content();
83                 id = g_strdup (val);
84             } /* id */
85             if (!strcmp(chname, "name")) {
86                 name = g_strdup (sp_repr_children(child_repr)->content());
87             } /* name */
88             if (!strcmp(chname, "help")) {
89                 _help = g_strdup (sp_repr_children(child_repr)->content());
90             } /* name */
91             if (!strcmp(chname, "param")) {
92                                 Parameter * param;
93                                 param = Parameter::make(child_repr, this);
94                                 if (param != NULL)
95                                         parameters = g_slist_append(parameters, param);
96             } /* param */
97             if (!strcmp(chname, "dependency")) {
98                 _deps.push_back(new Dependency(child_repr));
99             } /* param */
100             child_repr = sp_repr_next(child_repr);
101         }
103         db.register_ext (this);
104     }
105     // printf("%s\n", name);
106         timer = NULL;
108     return;
111 /**
112     \return   none
113     \brief    Destroys the Extension
115     This function frees all of the strings that could be attached
116     to the extension and also unreferences the repr.  This is better
117     than freeing it because it may (I wouldn't know why) be referenced
118     in another place.
119 */
120 Extension::~Extension (void)
122 //      printf("Extension Destructor: %s\n", name);
123         set_state(STATE_UNLOADED);
124         db.unregister_ext(this);
125     Inkscape::GC::release(repr);
126     g_free(id);
127     g_free(name);
128         delete timer;
129         timer = NULL;
130     /** \todo Need to do parameters here */
132         for (unsigned int i = 0 ; i < _deps.size(); i++) {
133                 delete _deps[i];
134         }
135         _deps.clear();
137     return;
140 /**
141     \return   none
142     \brief    A function to set whether the extension should be loaded
143               or unloaded
144     \param    in_state  Which state should the extension be in?
146     It checks to see if this is a state change or not.  If we're changing
147     states it will call the appropriate function in the implementation,
148     load or unload.  Currently, there is no error checking in this
149     function.  There should be.
150 */
151 void
152 Extension::set_state (state_t in_state)
154         if (_state == STATE_DEACTIVATED) return;
155     if (in_state != _state) {
156         /** \todo Need some more error checking here! */
157                 switch (in_state) {
158                         case STATE_LOADED:
159                                 if (imp->load(this))
160                                         _state = STATE_LOADED;
162                                 if (timer != NULL) {
163                                         delete timer;
164                                 }
165                                 timer = new ExpirationTimer(this);
167                                 break;
168                         case STATE_UNLOADED:
169                                 // std::cout << "Unloading: " << name << std::endl;
170                                 imp->unload(this);
171                                 _state = STATE_UNLOADED;
173                                 if (timer != NULL) {
174                                         delete timer;
175                                         timer = NULL;
176                                 }
177                                 break;
178                         case STATE_DEACTIVATED:
179                                 _state = STATE_DEACTIVATED;
181                                 if (timer != NULL) {
182                                         delete timer;
183                                         timer = NULL;
184                                 }
185                                 break;
186                         default:
187                                 break;
188                 }
189     }
191     return;
194 /**
195     \return   The state the extension is in
196     \brief    A getter for the state variable.
197 */
198 Extension::state_t
199 Extension::get_state (void)
201     return _state;
204 /**
205     \return  Whether the extension is loaded or not
206     \brief   A quick function to test the state of the extension
207 */
208 bool
209 Extension::loaded (void)
211     return get_state() == STATE_LOADED;
214 /**
215     \return  A boolean saying whether the extension passed the checks
216         \brief   A function to check the validity of the extension
218         This function chekcs to make sure that there is an id, a name, a
219         repr and an implemenation for this extension.  Then it checks all
220         of the dependencies to see if they pass.  Finally, it asks the
221         implmentation to do a check of itself.
223         On each check, if there is a failure, it will print a message to the
224         error log for that failure.  It is important to note that the function
225         keeps executing if it finds an error, to try and get as many of them
226         into the error log as possible.  This should help people debug
227         installations, and figure out what they need to get for the full
228         functionality of Inkscape to be available.
229 */
230 bool
231 Extension::check (void)
233         bool retval = true;
235         // static int i = 0;
236         // std::cout << "Checking module[" << i++ << "]: " << name << std::endl;
238         const char * inx_failure = _("  This is caused by an improper .inx file for this extension."
239                                          "  An improper .inx file could have been caused by a faulty installation of Inkscape.");
240         if (id == NULL) {
241                 printFailure(Glib::ustring(_("an ID was not defined for it.")) + inx_failure);
242                 retval = false;
243         }
244         if (name == NULL) {
245                 printFailure(Glib::ustring(_("there was no name defined for it.")) + inx_failure);
246                 retval = false;
247         }
248         if (repr == NULL) {
249                 printFailure(Glib::ustring(_("the XML description of it got lost.")) + inx_failure);
250                 retval = false;
251         }
252         if (imp == NULL) {
253                 printFailure(Glib::ustring(_("no implementation was defined for the extension.")) + inx_failure);
254                 retval = false;
255         }
257         for (unsigned int i = 0 ; i < _deps.size(); i++) {
258                 if (_deps[i]->check() == FALSE) {
259                         // std::cout << "Failed: " << *(_deps[i]) << std::endl;
260                         printFailure(Glib::ustring(_("a dependency was not met.")));
261                         error_file << *_deps[i] << std::endl;
262                         retval = false;
263                 }
264         }
266         if (retval)
267                 return imp->check(this);
268         return retval;
271 /** \brief A quick function to print out a standard start of extension
272            errors in the log.
273         \param reason  A string explaining why this failed
275         Real simple, just put everything into \c error_file.
276 */
277 void
278 Extension::printFailure (Glib::ustring reason)
280         error_file << _("Extension \"") << name << _("\" failed to load because ");
281         error_file << reason;
282         error_file << std::endl;
283         return;
286 /**
287     \return  The XML tree that is used to define the extension
288     \brief   A getter for the internal Repr, does not add a reference.
289 */
290 Inkscape::XML::Node *
291 Extension::get_repr (void)
293     return repr;
296 /**
297     \return  The textual id of this extension
298     \brief   Get the ID of this extension - not a copy don't delete!
299 */
300 gchar *
301 Extension::get_id (void)
303     return id;
306 /**
307     \return  The textual name of this extension
308     \brief   Get the name of this extension - not a copy don't delete!
309 */
310 gchar *
311 Extension::get_name (void)
313     return name;
316 /**
317     \return  None
318         \brief   This function diactivates the extension (which makes it
319                  unusable, but not deleted)
321     This function is used to removed an extension from functioning, but
322         not delete it completely.  It sets the state to \c STATE_DEACTIVATED to
323         mark to the world that it has been deactivated.  It also removes
324         the current implementation and replaces it with a standard one.  This
325         makes it so that we don't have to continually check if there is an
326         implementation, but we are gauranteed to have a benign one.
328         \warning It is important to note that there is no 'activate' function.
329         Running this function is irreversable.
330 */
331 void
332 Extension::deactivate (void)
334         set_state(STATE_DEACTIVATED);
336         /* Removing the old implementation, and making this use the default. */
337         /* This should save some memory */
338         delete imp;
339         imp = new Implementation::Implementation();
341         return;
344 /**
345     \return  Whether the extension has been deactivated
346         \brief   Find out the status of the extension
347 */
348 bool
349 Extension::deactivated (void)
351         return get_state() == STATE_DEACTIVATED;
354 /**
355     \return    Parameter structure with a name of 'name'
356     \brief     This function looks through the linked list for a parameter
357                structure with the name of the passed in name
358     \param     name   The name to search for
359     \param     list   The list to look for
361     This is an inline function that is used by all the get_param and
362     set_param functions to find a param_t in the linked list with
363     the passed in name.  It is done as an inline so that it will be
364     optimized into a 'jump' by the compiler.
366     This function can throw a 'param_not_exist' exception if the
367     name is not found.
369     The first thing that this function checks is if the list is NULL.
370     It could be NULL because there are no parameters for this extension
371     or because all of them have been checked (I'll spoil the ending and
372     tell you that this function is called recursively).  If the list
373     is NULL then the 'param_not_exist' exception is thrown.
375     Otherwise, the function looks at the current param_t that the element
376     list points to.  If the name of that param_t matches the passed in
377     name then that param_t is returned.  Otherwise, this function is
378     called again with g_slist_next as a parameter.
379 */
380 Parameter *
381 param_shared (const gchar * name, GSList * list)
383     Parameter * output;
385     if (name == NULL) {
386         throw Extension::param_not_exist();
387     }
388     if (list == NULL) {
389         throw Extension::param_not_exist();
390     }
392     output = static_cast<Parameter *>(list->data);
393     if (!strcmp(output->name(), name)) {
394         return output;
395     }
397     return param_shared(name, g_slist_next(list));
400 /**
401     \return   A constant pointer to the string held by the parameters.
402     \brief    Gets a parameter identified by name with the string placed
403               in value.  It isn't duplicated into the value string.
404     \param    name    The name of the parameter to get
405         \param    doc    The document to look in for document specific parameters
407         Look up in the parameters list, then execute the function on that
408         found parameter.
409 */
410 const gchar *
411 Extension::get_param_string (const gchar * name, const Inkscape::XML::Document * doc)
413     Parameter * param;
415     param = param_shared(name, parameters);
416         return param->get_string(doc);
419 /**
420     \return   The value of the parameter identified by the name
421     \brief    Gets a parameter identified by name with the bool placed
422               in value.
423     \param    name    The name of the parameter to get
424         \param    doc    The document to look in for document specific parameters
426         Look up in the parameters list, then execute the function on that
427         found parameter.
428 */
429 bool
430 Extension::get_param_bool (const gchar * name, const Inkscape::XML::Document * doc)
432     Parameter * param;
434     param = param_shared(name, parameters);
435     return param->get_bool(doc);
438 /**
439     \return   The integer value for the parameter specified
440     \brief    Gets a parameter identified by name with the integer placed
441               in value.
442     \param    name    The name of the parameter to get
443         \param    doc    The document to look in for document specific parameters
445         Look up in the parameters list, then execute the function on that
446         found parameter.
447 */
448 int
449 Extension::get_param_int (const gchar * name, const Inkscape::XML::Document * doc)
451     Parameter * param;
453     param = param_shared(name, parameters);
454     return param->get_int(doc);
457 /**
458     \return   The float value for the parameter specified
459     \brief    Gets a parameter identified by name with the float placed
460               in value.
461     \param    name    The name of the parameter to get
462         \param    doc    The document to look in for document specific parameters
464         Look up in the parameters list, then execute the function on that
465         found parameter.
466 */
467 float
468 Extension::get_param_float (const gchar * name, const Inkscape::XML::Document * doc)
470     Parameter * param;
471     param = param_shared(name, parameters);
472     return param->get_float(doc);
475 /**
476     \return   The passed in value
477     \brief    Sets a parameter identified by name with the boolean
478               in the parameter value.
479     \param    name    The name of the parameter to set
480     \param    value   The value to set the parameter to
481         \param    doc    The document to look in for document specific parameters
483         Look up in the parameters list, then execute the function on that
484         found parameter.
485 */
486 bool
487 Extension::set_param_bool (const gchar * name, bool value, Inkscape::XML::Document * doc)
489     Parameter * param;
490     param = param_shared(name, parameters);
491         return param->set_bool(value, doc);
494 /**
495     \return   The passed in value
496     \brief    Sets a parameter identified by name with the integer
497               in the parameter value.
498     \param    name    The name of the parameter to set
499     \param    value   The value to set the parameter to
500         \param    doc    The document to look in for document specific parameters
502         Look up in the parameters list, then execute the function on that
503         found parameter.
504 */
505 int
506 Extension::set_param_int (const gchar * name, int value, Inkscape::XML::Document * doc)
508     Parameter * param;
509     param = param_shared(name, parameters);
510         return param->set_int(value, doc);
513 /**
514     \return   The passed in value
515     \brief    Sets a parameter identified by name with the integer
516               in the parameter value.
517     \param    name    The name of the parameter to set
518     \param    value   The value to set the parameter to
519         \param    doc    The document to look in for document specific parameters
521         Look up in the parameters list, then execute the function on that
522         found parameter.
523 */
524 float
525 Extension::set_param_float (const gchar * name, float value, Inkscape::XML::Document * doc)
527     Parameter * param;
528     param = param_shared(name, parameters);
529         return param->set_float(value, doc);
532 /**
533     \return   The passed in value
534     \brief    Sets a parameter identified by name with the string
535               in the parameter value.
536     \param    name    The name of the parameter to set
537     \param    value   The value to set the parameter to
538         \param    doc    The document to look in for document specific parameters
540         Look up in the parameters list, then execute the function on that
541         found parameter.
542 */
543 const gchar *
544 Extension::set_param_string (const gchar * name, const gchar * value, Inkscape::XML::Document * doc)
546     Parameter * param;
547     param = param_shared(name, parameters);
548         return param->set_string(value, doc);
551 /** \brief A function to open the error log file. */
552 void
553 Extension::error_file_open (void)
555         gchar * ext_error_file = profile_path(EXTENSION_ERROR_LOG_FILENAME);
556         gchar * filename = g_filename_from_utf8( ext_error_file, -1, NULL, NULL, NULL );
557         error_file.open(filename);
558         if (!error_file.is_open()) {
559                 g_warning(_("Could not create extension error log file '%s'"),
560                           filename);
561         }
562         g_free(filename);
563         g_free(ext_error_file);
564 };
566 /** \brief A function to close the error log file. */
567 void
568 Extension::error_file_close (void)
570         error_file.close();
571 };
573 /** \brief  A function to automatically generate a GUI using the parameters
574         \return Generated widget
576         This function just goes through each parameter, and calls it's 'get_widget'
577         function to get each widget.  Then, each of those is placed into
578         a Gtk::VBox, which is then returned to the calling function.
580         If there are no parameters, this function just returns NULL.
581 */
582 Gtk::Widget *
583 Extension::autogui (void)
585         if (g_slist_length(parameters) == 0) return NULL;
587         Gtk::VBox * vbox = new Gtk::VBox();
588     vbox = new Gtk::VBox();
590         for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
591                 Parameter * param = reinterpret_cast<Parameter *>(list->data);
592                 Gtk::Widget * widg = param->get_widget();
593                 if (widg != NULL)
594                         vbox->pack_start(*widg, true, true);
595         }
597         vbox->show();
598         return vbox;
599 };
601 /**
602         \brief  A function to get the parameters in a string form
603         \return A string with all the parameters as command line arguements
605         I don't really like this function, but it works for now.
607         \todo  Do this better.
608 */
609 Glib::ustring *
610 Extension::paramString (void)
612         Glib::ustring * param_string = new Glib::ustring("");
614         for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
615                 Parameter * param = reinterpret_cast<Parameter *>(list->data);
617                 *param_string += " --";
618                 *param_string += param->name();
619                 *param_string += "=";
620                 Glib::ustring * paramstr = param->string();
621                 *param_string += *paramstr;
622                 delete paramstr;
623         }
625         return param_string;
628 /* Extension editor dialog stuff */
630 Gtk::Widget *
631 Extension::get_info_widget(void)
633     Gtk::Widget * retval = Gtk::manage(new Gtk::Label("Info"));
634     retval->show();
635     return retval;
638 Gtk::Widget *
639 Extension::get_help_widget(void)
641     Gtk::Widget * retval = Gtk::manage(new Gtk::Label("Help"));
642     retval->show();
643     return retval;
646 Gtk::Widget *
647 Extension::get_params_widget(void)
649     Gtk::Widget * retval = Gtk::manage(new Gtk::Label("Params"));
650     retval->show();
651     return retval;
654 }  /* namespace Extension */
655 }  /* namespace Inkscape */
658 /*
659   Local Variables:
660   mode:c++
661   c-file-style:"stroustrup"
662   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
663   indent-tabs-mode:nil
664   fill-column:99
665   End:
666 */
667 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :