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

Revision 870, 25.9 kB (checked in by mido, 14 years ago)

LOG_LEVEL final cut (or rather semifinal? I hope to improve work with ids soon)
and also it rests to adapt applications, work is in progress

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