libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/base/config.hpp
Go to the documentation of this file.
00001 
00012 /*
00013  *  Copyright (C) 2007, 2009 Juan Pedro BolĂ­var Puente
00014  *  
00015  *  This program is free software: you can redistribute it and/or modify
00016  *  it under the terms of the GNU General Public License as published by
00017  *  the Free Software Foundation, either version 3 of the License, or
00018  *  (at your option) any later version.
00019  *
00020  *  This program is distributed in the hope that it will be useful,
00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  *  GNU General Public License for more details.
00024  *
00025  *  You should have received a copy of the GNU General Public License
00026  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00027  *
00028  */
00029 
00030 #ifndef PSYNTH_BASE_CONFIG_H
00031 #define PSYNTH_BASE_CONFIG_H
00032 
00033 #include <list>
00034 #include <map>
00035 #include <iostream>
00036 #include <typeinfo>
00037 
00038 #include <boost/any.hpp>
00039 
00040 #include <psynth/base/tree.hpp>
00041 #include <psynth/base/misc.hpp>
00042 #include <psynth/base/singleton.hpp>
00043 #include <psynth/base/exception.hpp>
00044 #include <psynth/base/observer.hpp>
00045 
00046 #include <psynth/base/config_fwd.hpp>
00047 
00048 namespace psynth
00049 {
00050 namespace base
00051 {
00052 
00053 PSYNTH_DECLARE_ERROR (error,        config_error);
00054 PSYNTH_DECLARE_ERROR (config_error, config_type_error);
00055 PSYNTH_DECLARE_ERROR (config_error, config_backend_error);
00056 
00057 class conf_node;
00058 
00063 class conf_listener : public listener_base
00064 {
00065 public:
00070     virtual void handle_conf_change (conf_node& c)    = 0;
00071 
00076     virtual void handle_conf_nudge (conf_node& c)     = 0;
00077 
00082     virtual void handle_conf_add_child (conf_node& c) = 0;
00083 
00088     virtual void handle_conf_del_child (conf_node& c) = 0;
00089 };
00090 
00094 class conf_subject : public subject_base <conf_listener>
00095 {
00096 public:
00097     typedef boost::signal <void (conf_node&)> signal;
00098     //typedef psynth::base::signal <void, conf_node&> signal;
00099     
00101     signal on_change;
00102     
00107     signal on_nudge;
00108 
00110     signal on_add_child;
00111 
00113     signal on_del_child;
00114 
00118     void add_listener (conf_listener& l);
00119 
00123     void del_listener (conf_listener& l);
00124 };
00125 
00130 class conf_backend : public conf_listener
00131 {
00132 public:
00134     virtual ~conf_backend() {}
00135 
00142     virtual void attach (conf_node& node) = 0;
00143 
00150     virtual void datach (conf_node& node) = 0;
00151 
00156     virtual void save (conf_node& node) = 0;
00157 
00162     virtual void load (conf_node& node) = 0;
00163 
00169     virtual void def_load (conf_node& node) = 0;
00170 };
00171 
00181 class conf_node : public conf_subject,
00182                   public tree_node <conf_node>,
00183                   public PSYNTH_DEFAULT_THREADING <conf_node>
00184 {
00185 public:
00189     const std::type_info& type () const
00190     {
00191         lock lock (this);
00192         return _element.type ();
00193     }
00194 
00198     bool empty () const
00199     {
00200         lock lock (this);
00201         return _element.empty ();
00202     }
00203 
00207     void nudge ()
00208     {
00209         on_nudge (*this);
00210     }
00211     
00217     template<class T>
00218     void set (const T& val)
00219     {
00220         lock lock (this);
00221         _element = val;
00222         on_change (*this);
00223     }
00224 
00230     template<class T>
00231     void set (const T& val, bool overwrite);
00232     
00239     template<class T>
00240     void def (const T& val);
00241     
00246     template<class T>
00247     void get (T& data) const;
00248 
00252     template<class T>
00253     T get () const;
00254     
00258     void save ();
00259 
00263     void load ();
00264 
00269     void def_load ();
00270     
00276     void set_backend (conf_backend_ptr backend);
00277 
00281     void unset_backend ();
00282     
00283 private:
00284     boost::any       _element;
00285     conf_backend_ptr _backend;
00286 
00287     void on_init ()
00288     {
00289         _backend.reset ();
00290         if (parent ())
00291             _backend = parent ()->_backend;
00292     }
00293 
00294     void on_uninit ()
00295     {
00296         _backend.reset ();
00297     }
00298 };
00299 
00303 struct config : public singleton_holder <conf_node> {};
00304 
00305 template<class T>
00306 void conf_node::get (T& data) const
00307 {
00308     lock lock (this);
00309     
00310     try {
00311         data = boost::any_cast<T> (_element);
00312     } catch (boost::bad_any_cast&) {
00313         throw config_type_error ();
00314     }
00315 }
00316 
00317 template<class T>
00318 T conf_node::get () const
00319 {
00320     lock lock (this);
00321     T ret;
00322     
00323     try {
00324         ret = boost::any_cast<T> (_element);
00325     } catch (boost::bad_any_cast&) {
00326         throw config_type_error ();
00327     }
00328 
00329     return ret;
00330 }
00331 
00332 
00333 template<class T>
00334 void conf_node::def (const T& val)
00335 {
00336     lock lock (this);
00337     
00338     if (_element.empty ()) {
00339         _element = val;
00340         on_change (*this);
00341     }
00342 }
00343 
00344 template<class T>
00345 void conf_node::set (const T& val, bool overwrite)
00346 {
00347     lock lock (this);
00348     
00349     if (overwrite || _element.empty ()) {
00350         _element = val;
00351         on_change (*this);
00352     }
00353 }
00354 
00355 extern template class subject_base <conf_listener>;
00356 extern template class singleton_holder <conf_node>;
00357 extern template class tree_node <conf_node>;
00358 extern template class PSYNTH_DEFAULT_THREADING <conf_node>;
00359 
00360 } /* namespace base */
00361 } /* namespace psynth */
00362 
00363 #endif /* PSYNTH_BASE_CONFIG_H */