root/library/bdm/base/user_info.h @ 1064

Revision 1064, 25.8 kB (checked in by mido, 14 years ago)

astyle applied all over the library

  • Property svn:eol-style set to native
RevLine 
[396]1/*!
2  \file
[471]3  \brief UI (user info) class for loading/saving objects from/to configuration files.
[399]4  It is designed with use of libconfig C/C++ Configuration File Library
[659]5  \ref ui
[396]6  \author Vaclav Smidl.
7
8  -----------------------------------
9  BDM++ - C++ library for Bayesian Decision Making under Uncertainty
10
11  Using IT++ for numerical operations
12  -----------------------------------
13*/
14
[357]15#ifndef USER_INFO_H
16#define USER_INFO_H
[254]17
[344]18#include <stdio.h>
19#include <string>
20#include <typeinfo>
21#include <map>
[396]22#include <stdexcept>
[243]23
[384]24#include "../bdmroot.h"
[527]25#include "../shared_ptr.h"
[357]26#include "itpp/itbase.h"
[1015]27#include "../math/square_mat.h"
28#include "../math/chmat.h"
[351]29
[344]30using std::string;
31using namespace std;
[281]32using namespace libconfig;
[246]33
[471]34namespace bdm {
[246]35
[540]36//! Generic exception for reporting configuration errors
[471]37//!
[659]38//!  \ref ui
[471]39class UIException : public std::exception {
[540]40private:
[1064]41    //! Error message
42    const string message;
[271]43
[540]44public:
[1064]45    /*!
46      \brief The constructor
47      \param message the reason for throwing the exception. Should be a complete English sentence (or a couple sentences), starting with "UIException: ".
48    */
49    UIException ( const string &message ) :
50        message ( message ) {
51    }
[471]52
[1064]53    //! Overriden method for reporting the error message
54    virtual const char* what() const throw() {
55        return message.c_str();
56    }
[483]57
[1064]58    ~UIException() throw() {};
[540]59
60protected:
[1064]61    /*!
62      Formats error messages for derived classes, which use a
63      Setting path in addition to the message.
64    */
65    static string format_message ( const string &reason, const string &path );
[540]66};
67
68//! Exception for reporting configuration errors related to some concrete Setting path
69//!
[659]70//!  \ref ui
[540]71class UISettingException : public UIException {
[483]72public:
[1064]73    //! Use this constructor when you can pass the problematical Setting as a parameter
74    UISettingException ( const string &message, const Setting &element ) :
75        UIException ( format_message ( message, string ( element.getPath() ) ) ) {
76    }
[396]77
[1064]78    //! This constructor is for other occasions, when only path of problematical Setting is known
79    UISettingException ( const string &message, const string &path ) :
80        UIException ( format_message ( message, path ) ) {
81    }
[396]82
[1064]83    ~UISettingException() throw() {};
[540]84};
85
86//! Exception for reporting configuration errors in the "class" attribute
87//!
[659]88//!  \ref ui
[540]89class UIClassException : public UIException {
90public:
[1064]91    //! Use this constructor when you can pass the problematical Setting as a parameter
92    UIClassException ( const string &message, const Setting &element ) :
93        UIException ( format_message ( message, string ( element.getPath() ) ) ) {
94    }
[483]95
[1064]96    //! This constructor is for other occasions, when only path of problematical Setting is known
97    UIClassException ( const string &message, const string &path ) :
98        UIException ( format_message ( message, path ) ) {
99    }
[483]100
[1064]101    ~UIClassException() throw() {};
[392]102};
[246]103
[394]104/*!
[471]105@brief This class serves to load and/or save user-infos into/from
[394]106configuration files stored on a hard-disk.
[357]107
[471]108Firstly, save some user-infos into the new UIFile instance. Then,
[394]109call the save method with a filename as its only argument:
[351]110
[344]111\code
112        CAudi audi;
[394]113        UIFile file;
114        UI::save( audi, file, "TT");
115        file.save("cars.cfg");
[344]116\endcode
117
[471]118In the other way round, when loading object from a configuration file,
[394]119the appropriate code looks like this:
120
[344]121\code
[394]122        UIFile file("cars.cfg");
123        CAudi *audi = UI::build<CAudi>(file,"TT");
[344]124\endcode
[471]125
[659]126\ref ui
[344]127*/
[471]128class UIFile : public Config {
[394]129public:
[1064]130    //! Create empty file instance prepared to store Settings
131    UIFile();
[344]132
[1064]133    //! Creates instance and fills it from the configuration file file_name
134    UIFile ( const string &file_name );
[344]135
[1064]136    //! Save all the stored Settings into the configuration file file_name
137    void save ( const string &file_name );
[394]138
[1064]139    //! This operator allows the ability of substituting Setting parameter by UIFile instance
140    operator Setting&();
[394]141};
142
[396]143/*!
[471]144@brief This class serves to expand links used within configuration files.
[394]145
[396]146Value of any type but string can be linked to some other value of the same type
147defined elsewhere in the current configuration file or even in some different
[471]148configuration file.
[394]149
[471]150Link have three parts, \<name\> : \<path\> \<\@filename\>. Field \<name\> contains the
[396]151name of the new setting, \<path\> is the relative path to the referenced setting, which
[471]152has to be taken from the %root Setting element. The last part \<\@filename\> is optional,
[396]153it contains filename in the case the link should refer to a variable stored in a different
154file. From the previous part \<path\>, it has to be separated by '@'.
155
156\code
157    ...
[471]158        jardovo :
[396]159        {
160          class = "Car";
161          year = 1992;
162          manufacturer = "liaz";
163          kilometers = 1555000;
164        };
[471]165        ondrejovo :
[396]166        {
167          class = "Bike";
168          year = 1996;
169          manufacturer = "author";
170          electricLights = true;
171          matr = ( 2, 2, [ 1.0, 0.0, 0.0, 1.0 ] );
172        };
[471]173
174        #this is the example of local link to another mean of transport
[396]175        elisky = "jardovo";
176
177        ...
178
[471]179        # And this link is external link pointing to the file "other_cars.cfg" stored in the
180        # same directory. In that file, it refers to the local Setting "magic_cars.skubankovo".
[396]181        kati = "magic_cars.skubankovo@other_cars.cfg";
182
183    ...
184\endcode
185
186When you want to expand a possible linked setting "element" within your code, it has to be treated this way:
187
188\code
189        ...
190
191        const SettingResolver link( element );
192
193        ...
194
195        int len = link.result.getLength();
196
197        ...
198\endcode
199
[471]200The whole point is that a resolved link (class member #result, i.e., "link.result" in the previous example) could point
[396]201into a different configuration file. In that case there has to be an UIFile instance managing reading from this
[471]202file. As the libconfig::Config deletes all its Settings when dealocated, UIFile must not be dealocated until all
203the necessary operation on the linked Setting are finished (otherwise, the link #result would be invalid just after
204the UIFile dealocation). And that is exactly the mechanism implemented within SettingResolver class. It assures,
[396]205that the #result Setting reference is valid within the scope of SettingResolver instance.
[477]206
[659]207\ref ui
[396]208 */
[471]209class SettingResolver : root {
[396]210private:
[1064]211    //! If necessary, this pointer stores an addres of an opened UIFile, else it equals NULL
212    UIFile *file;
[396]213
[1064]214    //! This method initialize #result reference, i.e., it executes the main code of SettingResolver class
215    //!
216    //! This code could be also located directly in constructor. The only reason why we made this
217    //! method is the keyword 'const' within the declaration of #result reference . Such a reference
218    //! have to be intialized before any other constructor command, exactly in the way it is implemented now.
219    const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link );
[396]220
221public:
[1064]222    //! Reference to a resolved link or to the original Setting in the case it does not contain a link
223    const Setting &result;
[396]224
[1064]225    //! If potential_link contains a link to some other setting, it is resolved here. Anyway, the Setting reference #result is prepared for use.
226    SettingResolver ( const Setting &potential_link );
[471]227
[1064]228    //! An opened UIFile file is closed here if necessary.
229    ~SettingResolver();
[396]230};
231
[942]232
233
[344]234/*!
[471]235@brief UI is an abstract class which collects all the auxiliary functions useful to prepare some concrete
236user-infos.
[344]237
[600]238See static methods 'build', 'get' and 'save'. Writing user-infos with these methods is rather simple. The
[471]239rest of this class is intended for internal purposes only. Its meaning is to allow pointers to its templated
240descendant ParticularUI<T>.
241
[659]242\ref ui
[344]243*/
[471]244class UI {
[344]245private:
[1064]246    //! Class with state shared across all its instances ("monostate"), encapsulating two maps, one mapping names to UI instances and the other mapping type_infos to class names
247    //!
248    //! The key property of this class is that it initializes the internal maps on global init,
249    //! before the instance is used for a first time. Therefore, we do not have to care about initialization
250    //! during a call of UIREGISTER macro operating with both these mappings.
251    class MappedUI {
252    private:
253        //! Type definition of mapping which transforms class names to the related UI instances
254        typedef map< const string, const UI* const > StringToUIMap;
[344]255
[1064]256        //! Type definition of mapping which transforms RTTI type_infos to the related class names
257        typedef map< const type_info * const, const string > TypeInfoToStringMap;
[344]258
[1064]259        //! Immediately initialized instance of type StringToUIMap
260        static StringToUIMap& mapped_strings();
[351]261
[1064]262        //! Immediately initialized instance of type TypeInfoToStringMap
263        static TypeInfoToStringMap& mapped_type_infos();
[351]264
[1064]265        //! Method for reporting a error when an attempt to operate with an unregistered class occures
266        static void unregistered_class_error ( const string &unregistered_class_name );
[394]267
[1064]268    public:
269        //! Add a pair key-userinfo into the internal map
270        static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui );
[344]271
[1064]272        //! Search for an userinfo related to the passed class name within the internal map
273        static const UI& retrieve_ui ( const string &class_name );
[351]274
[1064]275        //! Search for an class name related to the passed type_info within the internal map
276        static const string& retrieve_class_name ( const type_info* const class_type_info );
277    };
[351]278
[1064]279    //! Function assertting that the setting element is of the SettingType type
280    static void assert_type ( const Setting &element, Setting::Type type );
[396]281
[1064]282    /*!
283      \brief Method constructing a configured instance
[527]284
[1064]285      The returned pointer must be allocated using operator new
286      (it's deleted at the end of its life cycle). The method is
287      implemented in descendant class ParticularUI<T>, which knows
288      the correct type T.
289    */
290    virtual root* new_instance() const = 0;
[246]291
[1064]292    //! Method switching from the \a element to its child Setting according the passed \a index, it also does all the necessary error-checking
293    static const Setting& to_child_setting ( const Setting &element, const int index );
[351]294
[1064]295    //! Method switching from the \a element to its child Setting according the passed \a name, it also does all the necessary error-checking
296    static const Setting& to_child_setting ( const Setting &element, const string &name );
[471]297
[1064]298    //! A shortcut for calling instance.from_setting( set ); with some error catches added
299    static void call_from_setting( root &instance, const Setting &set, string class_name = "unknown");
[942]300
[1064]301    //! A shortcut for calling instance.to_setting( set ); with some error catches added
302    static void call_to_setting( const root &instance, Setting &set, string class_name = "unknown" );
[942]303
[1064]304    //! This method converts a Setting into a matrix
305    static void from_setting ( mat& matrix, const Setting &element );
306    //! This method converts a Setting into a ldmat
307    static void from_setting ( ldmat& matrix, const Setting &element );
308    //! This method converts a Setting into an integer vector
309    static void from_setting ( ivec &vector, const Setting &element );
310    //! This method converts a Setting into a string
311    static void from_setting ( string &str, const Setting &element );
312    //! This method converts a Setting into a real vector
313    static void from_setting ( vec &vector, const Setting &element );
314    //! This method converts a Setting into a integer scalar
315    static void from_setting ( int &integer, const Setting &element );
316    //! This method converts a Setting into a real scalar
317    static void from_setting ( double &real, const Setting &element );
318    //! This method converts a Setting into a staticallly allocated root descendant
319    static void from_setting ( root &instance, const Setting &element );
320    //! This method converts a Setting into a log_level
321    //!
322    //! Data is stored in string which has different meaning than usally. For that reason, a specialized
323    //! method is necessary here to avoid the default call of "const SettingResolver link ( element );",
324    //! which would lead to erroneous behaviour in this case
325    static void from_setting ( log_level_base &log_level, const Setting &element );
326    //! This method converts a Setting into a dynamically allocated root descendant
327    template<class T> static void from_setting ( T* &instance, const Setting &element ) {
328        const SettingResolver link ( element );
329        assert_type( link.result, Setting::TypeGroup );
[246]330
[1064]331        // we get a value stored in the "class" attribute
332        string class_name;
333        if ( !link.result.lookupValue ( "class", class_name ) )
334            throw UIClassException ( "UIException: the obligatory \"class\" identifier is missing.", link.result );
[471]335
[1064]336        // then we find a user-info related to this type
337        const UI& related_UI = MappedUI::retrieve_ui ( class_name );
[471]338
[1064]339        root *typeless_instance = related_UI.new_instance();
340        bdm_assert ( typeless_instance, "UI::new_instance failed" );
[344]341
[1064]342        instance = dynamic_cast<T*> ( typeless_instance );
343        if ( !instance ) {
344            delete typeless_instance;
345            throw UIClassException ( "UIException: class " + class_name + " is not a descendant of the desired output class. Try to call the UI::build<T> function with a different type parameter.", link.result );
346        }
[471]347
[1064]348        try {
349            call_from_setting( *instance, link.result, class_name );
350        } catch ( ... ) {
351            delete instance;
352            instance = 0;
353            throw;
354        }
355    }
[344]356
[1064]357    //! This method converts a Setting into a descendant of class
358    //! T, wrapped in an instance of bdm::shared_ptr<T> .
359    template<class T> static void from_setting ( bdm::shared_ptr<T> &instance, const Setting &element ) {
360        T *tmp_inst = 0;
361        from_setting ( tmp_inst, element );
362        bdm_assert ( tmp_inst, "UI::from_setting failed" );
363        instance = tmp_inst;
364    }
[527]365
[1064]366    //! This methods converts a Setting into a new templated array of type Array<T>
367    template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
368        const SettingResolver link ( element );
[345]369
[1064]370        assert_type ( link.result, Setting::TypeList );
[344]371
[1064]372        int len = link.result.getLength();
373        array_to_load.set_length ( len );
374        if ( len == 0 ) return;
[471]375
[1064]376        for ( int i = 0; i < len; i++ )
377            from_setting ( array_to_load ( i ), link.result[i] );
378    }
[471]379
[345]380protected:
[1064]381    //! Constructor for internal use only, see \sa ParticularUI<T>
382    UI ( const string& class_name, const type_info * const class_type_info ) {
383        MappedUI::add_class ( class_name, class_type_info, this );
384    }
[345]385
[471]386public:
[281]387
[1064]388    //! Enum type used to determine whether the data for concrete Settingis is compulsory or optional
389    enum SettingPresence { optional, compulsory } ;
[471]390
[1064]391    //! \name Initialization of classes
392    //!@{
393    //! The type T has to be a #bdm::root descendant class
[394]394
[1064]395    //! The new instance of type T* is constructed and initialized with values stored in the Setting element[name]
396    //!
397    //! If there does not exist any sub-element named name and settingPresence is optional, an empty bdm::shared_ptr<T> is returned.
398    //! When settingPresence is compulsory, the returned bdm::shared_ptr<T> is never empty (an exception is thrown when the object isn't found).
399    template<class T>
400    static bdm::shared_ptr<T> build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
401        if ( !element.exists ( name ) ) {
402            if ( settingPresence == optional )
403                return bdm::shared_ptr<T>();
404            else
405                throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
406        }
[471]407
[1064]408        bdm::shared_ptr<T> instance;
409        from_setting<T> ( instance, to_child_setting ( element, name ) );
410        return instance;
411    }
[471]412
[1064]413    //! The new instance of type T* is constructed and initialized with values stored in the Setting element[index]
414    //!
415    //! If there does not exist  any sub-element indexed by index, and settingPresence is optional, an empty bdm::shared_ptr<T> is returned.
416    //! When settingPresence is compulsory, the returned bdm::shared_ptr<T> is never empty (an exception is thrown when the object isn't found).
417    template<class T>
418    static bdm::shared_ptr<T> build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
419        if ( element.getLength() <= index ) {
420            if ( settingPresence == optional )
421                return bdm::shared_ptr<T>();
422            else {
423                stringstream stream;
424                stream << index;
425                throw UISettingException ( "UIException: the compulsory Setting with the index " + stream.str() + " is missing.", element );
426            }
427        }
[471]428
[1064]429        bdm::shared_ptr<T> instance;
430        from_setting<T> ( instance, to_child_setting ( element, index ) );
431        return instance;
432    }
[471]433
[737]434//! The new instance of type T* is constructed and initialized with values stored in the given Setting
[728]435//!
436//! Handy in mex files. Use with care.
[1064]437    template<class T>
438    static bdm::shared_ptr<T> build ( const Setting &element, SettingPresence settingPresence = optional ) {
439        bdm::shared_ptr<T> instance;
440        from_setting<T> ( instance,  element );
441        return instance;
442    }
[728]443
[1064]444    //!@}
[281]445
[1064]446    //! \name Initialization of structures
447    //!@{
448    //! The type T has to be int, double, string, vec, ivec or mat.
[396]449
[1064]450    //! The existing instance of type T is initialized with values stored in the Setting element[name]
451    //! If there does not exist any sub-element named name, this method returns false.
452    template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
453        if ( !element.exists ( name ) ) {
454            if ( settingPresence == optional )
455                return false;
456            else
457                throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
458        }
[471]459
[1064]460        from_setting ( instance, to_child_setting ( element, name ) );
461        return true;
462    }
[344]463
[1064]464    //! The existing instance of type T is initialized with values stored in the Setting element[index]
465    //! If there does not exist any sub-element indexed by index, this method returns false.
466    template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
467        if ( element.getLength() <= index ) {
468            if ( settingPresence == optional )
469                return false;
470            else {
471                stringstream stream;
472                stream << "UIException: the compulsory Setting with the index " << index << " is missing.";
473                stream << index;
474                throw UISettingException ( stream.str(), element );
475            }
476        }
[471]477
[1064]478        from_setting ( instance, to_child_setting ( element, index ) );
479        return true;
480    }
[344]481
[1064]482    //! The existing instance of type T is initialized with values stored in the Setting element directly
483    template<class T> static bool get ( T &instance, const Setting &element ) {
484        from_setting ( instance, element );
485        return true;
486    }
487    //!@}
[394]488
[1064]489    //! \name Initialization of arrays Array<T>
490    //!@{
491    //! The type T has to be int, double, string, vec, ivec or mat, or pointer to any root descendant.
[396]492
[1064]493    //! The existing array of type T is initialized with values stored in the Setting element[name]
494    //! If there is not any sub-element named name, this method returns false.
495    template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
496        if ( !element.exists ( name ) ) {
497            if ( settingPresence == optional )
498                return false;
499            else
500                throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
501        }
[471]502
[1064]503        from_setting ( array_to_load, to_child_setting ( element, name ) );
504        return true;
505    }
[344]506
[1064]507    //! The existing array of type T is initialized with values stored in the Setting element[index]
508    //! If there is not any sub-element indexed by index, this method returns false.
509    template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
510        if ( element.getLength() <= index ) {
511            if ( settingPresence == optional )
512                return bdm::shared_ptr<T>();
513            else {
514                stringstream stream;
515                stream << index;
516                throw UISettingException ( "UIException: the compulsory Setting with the index " + stream.str() + " is missing.", element );
517            }
518        }
[471]519
[1064]520        from_setting ( array_to_load, to_child_setting ( element, index ) );
521        return true;
522    }
[344]523
[1064]524    //! The existing array of type T is initialized with values stored in the Setting element
525    template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
526        from_setting ( array_to_load, element );
527        return true;
528    }
529    //!@}
[394]530
[1064]531    //! \name Serialization of objects and structures into a new Setting
532    //!@{
533    //! The new child Setting can be accessed either by its name - if some name is passed as a parameter -
534    //! or by its integer index. In that case, the new element is added at the very end of the current list of child Settings.
[396]535
[1064]536    //! A root descendant is stored in the new child Setting appended to the passed element
537    static void save ( const root &instance, Setting &element, const string &name = "" );
[344]538
[1064]539    //! A pointer to root descendant is stored in the new child Setting appended to the passed element
540    static void save ( const root * const instance, Setting &element, const string &name = "" );
[471]541
[1064]542    //! A shared pointer to root descendant is stored in the new child Setting appended to the passed element
543    template< class T> static void save ( const bdm::shared_ptr<T> &instance, Setting &element, const string &name = "" ) {
544        save( instance.get(), element, name );
545    }
[527]546
[1064]547    //! An Array<T> instance is stored in the new child Setting appended to the passed element
548    template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
549        assert_type ( element, Setting::TypeGroup );
550        Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
551                        : element.add ( name, Setting::TypeList );
552        for ( int i = 0; i < array_to_save.length(); i++ )
553            save ( array_to_save ( i ), list );
554    }
[351]555
[1064]556    //! A matrix(of type mat) is stored in the new child Setting appended to the passed element
557    static void save ( const mat &matrix, Setting &element, const string &name = "" );
[471]558
[1064]559    //! A matrix(of type mat) is stored in the new child Setting appended to the passed element
560    static void save ( const ldmat &matrix, Setting &element, const string &name = "" );
[396]561
[1064]562    //! An integer vector (of type ivec) is stored in the new child Setting appended to the passed element
563    static void save ( const ivec &vec, Setting &element, const string &name = "" );
[351]564
[1064]565    //! A double vector (of type vec) is stored in the new child Setting appended to the passed element
566    static void save ( const vec &vector, Setting &element, const string &name = "" );
[394]567
[1064]568    //! A string is stored in the new child Setting appended to the passed element
569    static void save ( const string &str, Setting &element, const string &name = "" );
[907]570
[1064]571    //! An integer is stored in the new child Setting appended to the passed element
572    static void save ( const int &integer, Setting &element, const string &name = "" );
573
574    //! A double is stored in the new child Setting appended to the passed element
575    static void save ( const double &real, Setting &element, const string &name = "" );
576
[942]577    // The only difference from classical UserInfo approach here is the fact
[1064]578    // that the actual UI element related to log_level_base could possibly exists yet. In this case,
579    // we do not want to throw an exception as usually. We rather append current data into the existig element. This way, it is
580    // possible that more instances of log_level_base  (templated with different classes)
581    // can be stored in only one line in a configuration file
582    static void save ( const log_level_base &log_level, Setting &element );
[907]583
[1064]584    //!@}
[394]585
[1064]586    //! for future use
587    virtual ~UI() {}
[281]588};
589
590
[493]591//! The only UI descendant class which is not intended for direct use. It should be accessed within the UIREGISTER macro only.
[659]592//! \ref ui
[471]593template<typename T> class ParticularUI : private UI {
[493]594public:
[1064]595    //! Constructor used by the UIREGISTER macro.
596    ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
[344]597
[1064]598    //! A method returning a brand new instance of class T, this method is the reason why there have to be a parameterless constructor in class T
599    root* new_instance() const {
600        return new T();
601    }
[281]602};
603
[344]604}
605
[471]606/*!
607  \def UIREGISTER(class_name)
608  \brief Macro for registration of class into map of user-infos, registered class is scriptable using UI static methods
609
[529]610  Argument \a class_name has to be a descendant of root class and also to have a default constructor.
[471]611  This macro should be used in header file, immediately after a class declaration.
612
[659]613  \ref ui
[471]614*/
615#ifndef BDMLIB
[535]616#define UIREGISTER(class_name) static bdm::ParticularUI<class_name> UI##class_name(#class_name)
[471]617#else
618#define UIREGISTER(class_name)
619#endif
620
[535]621//! Instrumental macro for UIREGISTER2
622#define QUOTEME(x) #x
623
624/*!
625  \def UIREGISTER2(class_name,template_name)
626  \brief Variant of UIREGISTER for templated classes
627
628  Technical meann of registering UIREGISTER(class_name<template_name>).
629
[659]630  \ref ui
[535]631 */
632#ifndef BDMLIB
633#define UIREGISTER2(class_name, temp_name) static bdm::ParticularUI<class_name<temp_name> > UI##class_name##_##temp_name( QUOTEME(class_name<temp_name>) )
634#else
[737]635#define UIREGISTER2(class_name,temp_name)
[535]636#endif
637
[358]638#endif // #ifndef USER_INFO_H
Note: See TracBrowser for help on using the browser.