Changeset 471 for library/bdm/base/user_info.h
- Timestamp:
- 08/05/09 00:01:58 (15 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
library/bdm/base/user_info.h
r417 r471 1 1 /*! 2 2 \file 3 \brief UI (user info) class for loading/saving objects from/to configuration files. 3 \brief UI (user info) class for loading/saving objects from/to configuration files. 4 4 It is designed with use of libconfig C/C++ Configuration File Library 5 \ref ui_page 5 6 \author Vaclav Smidl. 6 7 … … 30 31 using namespace libconfig; 31 32 32 namespace bdm 33 { 34 35 /*! 36 \def UIREGISTER(class_name) 37 \brief Macro for registration of class into map of user-infos, registered class is scriptable using UI static methods 38 39 Argument \a class_name has to be a descendant of root class and also, it has to have parameterless constructor prepared. 40 This macro should be used in header file, immediately after a class declaration. 41 42 \sa TODO MODUL 43 */ 44 #ifndef BDMLIB 45 #define UIREGISTER(class_name) template<> const ParticularUI<class_name>& ParticularUI<class_name>::factory = ParticularUI<class_name>(#class_name) 46 #else 47 #define UIREGISTER(class_name) 48 #endif 33 namespace bdm { 49 34 50 35 //! Exception prepared for reporting user-info errors which are always related to some concrete Setting path 51 class UIException : public std::exception 52 { 53 private: 36 //! 37 //! \ref ui_page 38 class UIException : public std::exception { 39 40 public: 54 41 //! Error message 55 42 const string message; 56 43 57 public: 44 //! Path to the problematic setting 45 const string path; 46 58 47 //! Use this constructor when you can pass the problematical Setting as a parameter 59 UIException( const string &message, const Setting &element ) 60 : message( "UI error: " + message + ". Check path \"" + string(element.getPath()) + "\"." ) 61 { 48 UIException ( const string &message, const Setting &element ) 49 : message ( "UI error: " + message + "." ), path ( "Check path \"" + string ( element.getPath() ) + "\"." ) { 62 50 } 63 51 64 52 //! This constructor is for other occasions, when only path of problematical Setting is known 65 UIException( const string &message, const string &path ) 66 : message( "UI error: " + message + "! Check path \"" + path + "\"." ) 67 { 53 UIException ( const string &message, const string &path ) 54 : message ( "UI error: " + message + "." ), path ( "Check path \"" + path + "\"." ) { 68 55 } 69 56 70 57 //! Overriden method for reporting an error message 71 virtual const char* what() const throw() 72 { 73 return message.c_str(); 58 virtual const char* what() const throw() { 59 return ( message + " " + path ).c_str(); 74 60 } 75 61 ~UIException() throw() {}; … … 78 64 79 65 /*! 80 @brief This class serves to load and/or save user-infos into/from 66 @brief This class serves to load and/or save user-infos into/from 81 67 configuration files stored on a hard-disk. 82 68 83 Firstly, save some user-infos into the new UIFile instance. Then, 69 Firstly, save some user-infos into the new UIFile instance. Then, 84 70 call the save method with a filename as its only argument: 85 71 … … 91 77 \endcode 92 78 93 In the other way round, when loading object from a configuration file, 79 In the other way round, when loading object from a configuration file, 94 80 the appropriate code looks like this: 95 81 … … 98 84 CAudi *audi = UI::build<CAudi>(file,"TT"); 99 85 \endcode 86 87 \ref ui_page 100 88 */ 101 class UIFile : public Config 102 { 89 class UIFile : public Config { 103 90 public: 104 91 //! Create empty file instance prepared to store Settings … … 106 93 107 94 //! Creates instance and fills it from the configuration file file_name 108 UIFile ( const string &file_name );95 UIFile ( const string &file_name ); 109 96 110 97 //! Save all the stored Settings into the configuration file file_name 111 void save (const string &file_name);98 void save ( const string &file_name ); 112 99 113 100 //! This operator allows the ability of substituting Setting parameter by UIFile instance … … 116 103 117 104 /*! 118 @brief This class serves to expand links used within configuration files. 105 @brief This class serves to expand links used within configuration files. 119 106 120 107 Value of any type but string can be linked to some other value of the same type 121 108 defined elsewhere in the current configuration file or even in some different 122 configuration file. 123 124 Link have three parts, \<name\> : \<path\> \<\@filename\>. Field \<name\> contains the 109 configuration file. 110 111 Link have three parts, \<name\> : \<path\> \<\@filename\>. Field \<name\> contains the 125 112 name of the new setting, \<path\> is the relative path to the referenced setting, which 126 has to be taken from the %root Setting element. The last part \<\@filename\> is optional, 113 has to be taken from the %root Setting element. The last part \<\@filename\> is optional, 127 114 it contains filename in the case the link should refer to a variable stored in a different 128 115 file. From the previous part \<path\>, it has to be separated by '@'. … … 130 117 \code 131 118 ... 132 jardovo : 119 jardovo : 133 120 { 134 121 class = "Car"; … … 137 124 kilometers = 1555000; 138 125 }; 139 ondrejovo : 126 ondrejovo : 140 127 { 141 128 class = "Bike"; … … 145 132 matr = ( 2, 2, [ 1.0, 0.0, 0.0, 1.0 ] ); 146 133 }; 147 148 #this is the example of local link to another mean of transport 134 135 #this is the example of local link to another mean of transport 149 136 elisky = "jardovo"; 150 137 151 138 ... 152 139 153 # and this link is external link pointing tofile "other_cars.cfg" stored in the154 # same directory , in that file, it refers to the local Setting "magic_cars.skubankovo"140 # And this link is external link pointing to the file "other_cars.cfg" stored in the 141 # same directory. In that file, it refers to the local Setting "magic_cars.skubankovo". 155 142 kati = "magic_cars.skubankovo@other_cars.cfg"; 156 143 … … 172 159 \endcode 173 160 174 The whole point is that a resolved link (class member #result, i.e., "link.result" in the previous example) could point 161 The whole point is that a resolved link (class member #result, i.e., "link.result" in the previous example) could point 175 162 into a different configuration file. In that case there has to be an UIFile instance managing reading from this 176 file. As the libconfig::Config deletes all its Settings when dealocated, UIFile must not be dealocated until all 177 the necessary operation on the linked Setting are finished (otherwise, the link #result would be invalid just after 178 the UIFile dealocation). And that is exactly the mechanism implemented within SettingResolver class. It assures, 163 file. As the libconfig::Config deletes all its Settings when dealocated, UIFile must not be dealocated until all 164 the necessary operation on the linked Setting are finished (otherwise, the link #result would be invalid just after 165 the UIFile dealocation). And that is exactly the mechanism implemented within SettingResolver class. It assures, 179 166 that the #result Setting reference is valid within the scope of SettingResolver instance. 167 168 \ref ui_page 180 169 */ 181 class SettingResolver : root 182 { 170 class SettingResolver : root { 183 171 private: 184 172 //! If necessary, this pointer stores an addres of an opened UIFile, else it equals NULL … … 187 175 //! This method initialize #result reference, i.e., it executes the main code of SettingResolver class 188 176 //! 189 //! This code could be also located directly in constructor. The only reason why we made this 177 //! This code could be also located directly in constructor. The only reason why we made this 190 178 //! method is the keyword 'const' within the declaration of #result reference . Such a reference 191 179 //! have to be intialized before any other constructor command, exactly in the way it is implemented now. 192 const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link);180 const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link ); 193 181 194 182 public: … … 197 185 198 186 //! If potential_link contains a link to some other setting, it is resolved here. Anyway, the Setting reference #result is prepared for use. 199 SettingResolver ( const Setting &potential_link );200 187 SettingResolver ( const Setting &potential_link ); 188 201 189 //! An opened UIFile file is closed here if necessary. 202 ~SettingResolver(); 190 ~SettingResolver(); 203 191 }; 204 192 205 193 /*! 206 @brief UI is an abstract class and it is intended for internal purposes only 207 208 This class exists mainly to allow pointers to its templated descendant ParticularUI<T>. Next, 209 it collects all the auxiliary functions useful to prepare some concret user-infos, see static 210 methods 'build', 'get' and 'save'. 194 @brief UI is an abstract class which collects all the auxiliary functions useful to prepare some concrete 195 user-infos. 196 197 See static methods 'build', 'get' and 'save'. Writing user-infos with these methods is rather simple. The 198 rest of this class is intended for internal purposes only. Its meaning is to allow pointers to its templated 199 descendant ParticularUI<T>. 200 201 \ref ui_page 211 202 */ 212 class UI 213 { 203 class UI { 214 204 private: 215 205 //! 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 216 //! 206 //! 217 207 //! The key property of this class is that it initializes the internal maps on global init, 218 //! before the instance is used for a first time. Therefore, we do not have to care about initialization 208 //! before the instance is used for a first time. Therefore, we do not have to care about initialization 219 209 //! during a call of UIREGISTER macro operating with both these mappings. 220 class MappedUI 221 { 210 class MappedUI { 222 211 private: 223 212 //! Type definition of mapping which transforms class names to the related UI instances … … 234 223 235 224 //! Method for reporting a error when an attempt to operate with an unregistered class occures 236 static void unregistered_class_error ( const string &unregistered_class_name );225 static void unregistered_class_error ( const string &unregistered_class_name ); 237 226 238 227 public: 239 228 //! Add a pair key-userinfo into the internal map 240 static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui );229 static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui ); 241 230 242 231 //! Search for an userinfo related to the passed class name within the internal map 243 static const UI& retrieve_ui ( const string &class_name );232 static const UI& retrieve_ui ( const string &class_name ); 244 233 245 234 //! Search for an class name related to the passed type_info within the internal map 246 static const string& retrieve_class_name ( const type_info* const class_type_info );235 static const string& retrieve_class_name ( const type_info* const class_type_info ); 247 236 }; 248 237 249 238 //! Function assertting that the setting element is of the SettingType type 250 static void assert_type ( const Setting &element, Setting::Type type);239 static void assert_type ( const Setting &element, Setting::Type type ); 251 240 252 241 //! Method assembling a typeless instance, it is implemented in descendant class ParticularUI<T> 253 242 virtual root* new_instance() const = 0; 254 255 //! Method switching from the \a element to its child Setting according the passed \a index, it also does all the necessary error-checking 256 static const Setting& to_child_setting ( const Setting &element, const int index );257 258 //! Method switching from the \a element to its child Setting according the passed \a name, it also does all the necessary error-checking 259 static const Setting& to_child_setting ( const Setting &element, const string &name );260 261 //! This method converts a Setting into a matrix 262 static void from_setting ( mat& matrix, const Setting &element );243 244 //! Method switching from the \a element to its child Setting according the passed \a index, it also does all the necessary error-checking 245 static const Setting& to_child_setting ( const Setting &element, const int index ); 246 247 //! Method switching from the \a element to its child Setting according the passed \a name, it also does all the necessary error-checking 248 static const Setting& to_child_setting ( const Setting &element, const string &name ); 249 250 //! This method converts a Setting into a matrix 251 static void from_setting ( mat& matrix, const Setting &element ); 263 252 //! This method converts a Setting into an integer vector 264 static void from_setting ( ivec &vector, const Setting &element );253 static void from_setting ( ivec &vector, const Setting &element ); 265 254 //! This method converts a Setting into a string 266 static void from_setting ( string &str, const Setting &element );255 static void from_setting ( string &str, const Setting &element ); 267 256 //! This method converts a Setting into a real vector 268 static void from_setting ( vec &vector, const Setting &element );269 //! This method converts a Setting into a integer scalar 270 static void from_setting ( int &integer, const Setting &element );271 //! This method converts a Setting into a real scalar 272 static void from_setting ( double &real, const Setting &element );257 static void from_setting ( vec &vector, const Setting &element ); 258 //! This method converts a Setting into a integer scalar 259 static void from_setting ( int &integer, const Setting &element ); 260 //! This method converts a Setting into a real scalar 261 static void from_setting ( double &real, const Setting &element ); 273 262 //! This method converts a Setting into a class T descendant 274 template<class T> static void from_setting( T* &instance, const Setting &element ) 275 { 276 const SettingResolver link( element ); 277 assert_type(link.result,Setting::TypeGroup); 278 279 // we get a value stored in the "class" attribute 263 template<class T> static void from_setting ( T* &instance, const Setting &element ) { 264 const SettingResolver link ( element ); 265 assert_type ( link.result, Setting::TypeGroup ); 266 267 // we get a value stored in the "class" attribute 280 268 string class_name; 281 if ( !link.result.lookupValue( "class", class_name ) )282 throw UIException ( "the obligatory \"class\" identifier is missing", link.result );283 269 if ( !link.result.lookupValue ( "class", class_name ) ) 270 throw UIException ( "the obligatory \"class\" identifier is missing", link.result ); 271 284 272 // then we find a user-info related to this type 285 const UI& related_UI = MappedUI::retrieve_ui ( class_name );286 273 const UI& related_UI = MappedUI::retrieve_ui ( class_name ); 274 287 275 root* typeless_instance = related_UI.new_instance(); 288 276 289 instance = dynamic_cast<T*>(typeless_instance); 290 if (!instance) 291 throw 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 ); 292 293 try 294 { 295 instance->from_setting( link.result ); 277 instance = dynamic_cast<T*> ( typeless_instance ); 278 if ( !instance ) 279 throw 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 ); 280 281 try { 282 instance->from_setting ( link.result ); 283 } catch ( SettingException sttng_xcptn ) { 284 string msg = "the method " + class_name + ".from_setting(Setting&) has thrown a SettingException. Try to correct this method. Check path \"" + sttng_xcptn.getPath() + "\"."; 285 throw exception ( msg.c_str() ); 286 } catch ( UIException uixcptn ) { 287 string msg = "the method " + class_name + ".from_setting(Setting&) has thrown an UIException \"" + uixcptn.message + "\" Try to correct this method. Check path \"" + uixcptn.path + "\"."; 288 throw exception ( msg.c_str() ); 289 } catch ( exception xcptn ) { 290 string msg = "the method " + class_name + ".from_setting(Setting&) has thrown a general exception \"" + xcptn.what() + "\" Try to correct this method. Check path \"" + element.getPath() + "\"."; 291 throw exception ( msg.c_str() ); 296 292 } 297 catch(SettingException xcptn) 298 { 299 throw UIException( "the method " + class_name + ".from_setting(Setting&) has thrown an SettingException. Try to correct this method", xcptn.getPath()); 300 } 301 } 293 } 302 294 303 295 //! This methods converts a Setting into a new templated array of type Array<T> 304 template<class T> static void from_setting( Array<T> &array_to_load, const Setting &element ) 305 { 306 const SettingResolver link( element ); 307 308 assert_type(link.result,Setting::TypeList); 296 template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) { 297 const SettingResolver link ( element ); 298 299 assert_type ( link.result, Setting::TypeList ); 309 300 310 301 int len = link.result.getLength(); 311 array_to_load.set_length( len ); 312 if( len == 0 ) return; 313 314 for( int i=0; i < len; i++ ) 315 from_setting( array_to_load(i), link.result[i] ); 316 } 302 array_to_load.set_length ( len ); 303 if ( len == 0 ) return; 304 305 for ( int i = 0; i < len; i++ ) 306 from_setting ( array_to_load ( i ), link.result[i] ); 307 } 308 309 //! This is dummy version of the from_setting method for other, unsupported types. It just throws an exception. 310 //! 311 //! At the moment, this is the only way how to compile the library without obtaining the compiler error c2665. 312 //! The exception can help to find the place where the template is misused and also to correct it. 313 template<class T> static void from_setting ( T &array_to_load, const Setting &element ) { 314 throw UIException( "from_setting is not implemented for this type", element ); 315 } 316 317 317 318 318 protected: 319 319 //! Default constructor for internal use only, see \sa ParticularUI<T> 320 UI( const string& class_name, const type_info * const class_type_info ) 321 { 322 MappedUI::add_class( class_name, class_type_info, this ); 323 } 324 325 public: 326 327 //! \name Initialization of classes 320 UI ( const string& class_name, const type_info * const class_type_info ) { 321 MappedUI::add_class ( class_name, class_type_info, this ); 322 } 323 324 public: 325 326 //! Enumerical type used to determine whether the data for concrete Settingis is compulsory or optional 327 enum SettingPresence { optional, compulsory } ; 328 329 //! \name Initialization of classes 328 330 //!@{ 329 //! The type T has to be a root descendant class331 //! The type T has to be a #bdm::root descendant class 330 332 331 333 //! The new instance of type T* is constructed and initialized with values stored in the Setting element[name] 332 template<class T> static T* build( const Setting &element, const string &name ) 333 { 334 //! 335 //! If there is not any sub-element named #name, the null pointer is returned. 336 template<class T> static T* build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) { 337 if ( !element.exists ( name ) ) 338 { 339 if( settingPresence == optional ) 340 return NULL; 341 else 342 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element ); 343 } 344 334 345 T* instance; 335 from_setting<T> ( instance, to_child_setting( element, name ) );346 from_setting<T> ( instance, to_child_setting ( element, name ) ); 336 347 return instance; 337 348 } 349 338 350 //! The new instance of type T* is constructed and initialized with values stored in the Setting element[index] 339 template<class T> static T* build( const Setting &element, const int index ) 340 { 351 //! 352 //! If there is not any sub-element indexed by #index, the null pointer is returned. 353 template<class T> static T* build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) { 354 if ( element.getLength() <= index ) 355 { 356 if( settingPresence == optional ) 357 return NULL; 358 else 359 { 360 stringstream stream; 361 stream << index; 362 throw UIException ( "the compulsory Setting with the index " + stream.str()+ " is missing", element ); 363 } 364 } 365 341 366 T* instance; 342 from_setting<T> ( instance, to_child_setting( element, index ) );367 from_setting<T> ( instance, to_child_setting ( element, index ) ); 343 368 return instance; 344 369 } 370 345 371 //! The new instance of type T* is constructed and initialized with values stored in the Setting element 346 template<class T> static T* build( const Setting &element ) 347 { 372 template<class T> static T* build ( const Setting &element ) { 348 373 T* instance; 349 from_setting<T> ( instance, element );374 from_setting<T> ( instance, element ); 350 375 return instance; 351 } 376 377 } 378 352 379 //!@} 353 380 354 //! \name Initialization of structures 381 //! \name Initialization of structures 355 382 //!@{ 356 383 //! The type T has to be int, double, string, vec, ivec or mat. 357 384 358 385 //! The existing instance of type T is initialized with values stored in the Setting element[name] 359 template<class T> static void get( T &instance, const Setting &element, const string &name ) 360 { 361 from_setting( instance, to_child_setting( element, name ) ); 362 } 363 364 //! The existing instance of type T is initialized with values stored in the Setting element[index] 365 template<class T> static void get( T &instance, const Setting &element, const int index ) 366 { 367 from_setting( instance, to_child_setting( element, index ) ); 386 //! If there is not any sub-element named #name, this method returns false. 387 template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) { 388 if ( !element.exists ( name ) ) 389 { 390 if( settingPresence == optional ) 391 return false; 392 else 393 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element ); 394 } 395 396 from_setting ( instance, to_child_setting ( element, name ) ); 397 return true; 398 } 399 400 //! The existing instance of type T is initialized with values stored in the Setting element[index] 401 //! If there is not any sub-element indexed by #index, this method returns false. 402 template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) { 403 if ( element.getLength() <= index ) 404 { 405 if( settingPresence == optional ) 406 return false; 407 else 408 { 409 stringstream stream; 410 stream << index; 411 throw UIException ( "the compulsory Setting with the index " + stream.str()+ " is missing", element ); 412 } 413 } 414 415 from_setting ( instance, to_child_setting ( element, index ) ); 416 return true; 368 417 } 369 418 370 419 //! The existing instance of type T is initialized with values stored in the Setting element directly 371 template<class T> static void get( T &instance, const Setting &element )372 {373 from_setting( instance, element );420 template<class T> static bool get ( T &instance, const Setting &element ) { 421 from_setting ( instance, element ); 422 return true; 374 423 } 375 424 //!@} … … 380 429 381 430 //! The existing array of type T is initialized with values stored in the Setting element[name] 382 template<class T> static void get( Array<T> &array_to_load, const Setting &element, const string &name ) 383 { 384 from_setting( array_to_load, to_child_setting( element, name ) ); 431 //! If there is not any sub-element named #name, this method returns false. 432 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) { 433 if ( !element.exists ( name ) ) 434 return false; 435 436 from_setting ( array_to_load, to_child_setting ( element, name ) ); 437 return true; 385 438 } 386 439 387 440 //! The existing array of type T is initialized with values stored in the Setting element[index] 388 template<class T> static void get( Array<T> &array_to_load, const Setting &element, const int index ) 389 { 390 from_setting( array_to_load, to_child_setting( element, index ) ); 441 //! If there is not any sub-element indexed by #index, this method returns false. 442 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) { 443 if ( element.getLength() <= index ) 444 return false; 445 446 from_setting ( array_to_load, to_child_setting ( element, index ) ); 447 return true; 391 448 } 392 449 393 450 //! The existing array of type T is initialized with values stored in the Setting element 394 template<class T> static void get( Array<T> &array_to_load, const Setting &element )395 {396 from_setting( array_to_load, element );451 template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) { 452 from_setting ( array_to_load, element ); 453 return true; 397 454 } 398 455 //!@} 399 456 400 //! \name Serialization of objects and structures into a new Setting 457 //! \name Serialization of objects and structures into a new Setting 401 458 //!@{ 402 459 //! The new child Setting can be accessed either by its name - if some name is passed as a parameter - … … 404 461 405 462 //! A root descendant instance is stored in the new child Setting appended to the passed element 406 template< class T> static void save( const T * const instance, Setting &element, const string &name = "") 407 { 408 Setting &set = (name == "") ? element.add( Setting::TypeGroup ) 409 : element.add( name, Setting::TypeGroup ); 410 411 const string &class_name = MappedUI::retrieve_class_name( &typeid(*instance) ); 412 413 // add attribute "class" 414 Setting &type = set.add( "class", Setting::TypeString ); 463 template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) { 464 Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup ) 465 : element.add ( name, Setting::TypeGroup ); 466 467 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) ); 468 469 // add attribute "class" 470 Setting &type = set.add ( "class", Setting::TypeString ); 415 471 type = class_name; 416 472 417 try 418 { 419 instance->to_setting( set ); 473 try { 474 instance->to_setting ( set ); 475 } catch ( SettingException sttng_xcptn ) { 476 string msg = "the method " + class_name + ".to_setting(Setting&) has thrown a SettingException. Try to correct this method. Check path \"" + sttng_xcptn.getPath() + "\"."; 477 throw exception ( msg.c_str() ); 478 } catch ( UIException uixcptn ) { 479 string msg = "the method " + class_name + ".to_setting(Setting&) has thrown an UIException \"" + uixcptn.message + "\" Try to correct this method. Check path \"" + uixcptn.path + "\"."; 480 throw exception ( msg.c_str() ); 481 } catch ( exception xcptn ) { 482 string msg = "the method " + class_name + ".to_setting(Setting&) has thrown a general exception \"" + xcptn.what() + "\" Try to correct this method. Check path \"" + element.getPath() + "\"."; 483 throw exception ( msg.c_str() ); 420 484 } 421 catch(SettingException xcptn)422 {423 throw UIException( "the method " + class_name + ".to_setting(Setting&) has thrown an SettingException. Try to correct this method", xcptn.getPath());424 }425 485 } 426 486 427 487 //! An Array<T> instance is stored in the new child Setting appended to the passed element 428 template<class T> static void save( const Array<T> &array_to_save, Setting &element, const string &name = "" ) 429 { 430 assert_type(element,Setting::TypeGroup); 431 Setting &list = (name == "") ? element.add( Setting::TypeList ) 432 : element.add( name, Setting::TypeList ); 433 for( int i=0; i<array_to_save.length(); i++ ) 434 save( array_to_save(i), list ); 488 template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) { 489 assert_type ( element, Setting::TypeGroup ); 490 Setting &list = ( name == "" ) ? element.add ( Setting::TypeList ) 491 : element.add ( name, Setting::TypeList ); 492 for ( int i = 0; i < array_to_save.length(); i++ ) 493 save ( array_to_save ( i ), list ); 435 494 } 436 495 437 496 //! A matrix(of type mat) is stored in the new child Setting appended to the passed element 438 static void save ( const mat &matrix, Setting &element, const string &name = "" );497 static void save ( const mat &matrix, Setting &element, const string &name = "" ); 439 498 440 499 //! An integer vector (of type ivec) is stored in the new child Setting appended to the passed element 441 static void save ( const ivec &vec, Setting &element, const string &name = "" );442 500 static void save ( const ivec &vec, Setting &element, const string &name = "" ); 501 443 502 //! A double vector (of type vec) is stored in the new child Setting appended to the passed element 444 static void save ( const vec &vector, Setting &element, const string &name = "" );503 static void save ( const vec &vector, Setting &element, const string &name = "" ); 445 504 446 505 //! A string is stored in the new child Setting appended to the passed element 447 static void save ( const string &str, Setting &element, const string &name = "" );506 static void save ( const string &str, Setting &element, const string &name = "" ); 448 507 449 508 //! An integer is stored in the new child Setting appended to the passed element 450 static void save ( const int &integer, Setting &element, const string &name = "" );509 static void save ( const int &integer, Setting &element, const string &name = "" ); 451 510 452 511 //! A double is stored in the new child Setting appended to the passed element 453 static void save ( const double &real, Setting &element, const string &name = "" );512 static void save ( const double &real, Setting &element, const string &name = "" ); 454 513 //!@} 455 514 … … 458 517 459 518 //! The only UI descendant class which is not intended for direct use. It should be accessed within the ::UIREGISTER macro only. 460 template<typename T> class ParticularUI : private UI 461 {519 //! \ref ui_page 520 template<typename T> class ParticularUI : private UI { 462 521 private: 463 522 //! Default constructor, which is intentionally declared as private 464 ParticularUI<T>( const string &class_name) : UI( class_name, &typeid(T) ) 465 {}; 523 ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {}; 466 524 467 525 public: 468 526 //! The only instance of this class (each type T has its own instance) which is used as a factory for processing related UI 469 static const ParticularUI<T>& factory; 527 static const ParticularUI<T>& factory; 470 528 471 529 //! A method returning a brand new instance of class T, this method is the reason why there have to be a parameterless construcotor in class T 472 root* new_instance() const 473 { 530 root* new_instance() const { 474 531 return new T(); 475 532 } … … 478 535 } 479 536 537 /*! 538 \def UIREGISTER(class_name) 539 \brief Macro for registration of class into map of user-infos, registered class is scriptable using UI static methods 540 541 Argument \a class_name has to be a descendant of root class and also, it has to have parameterless constructor prepared. 542 This macro should be used in header file, immediately after a class declaration. 543 544 \ref ui_page 545 */ 546 #ifndef BDMLIB 547 #define UIREGISTER(class_name) template<> const ParticularUI<class_name>& ParticularUI<class_name>::factory = ParticularUI<class_name>(#class_name) 548 #else 549 #define UIREGISTER(class_name) 550 #endif 551 480 552 #endif // #ifndef USER_INFO_H