28 | | UIFile ( const char * fname ) :Config() { |
29 | | try{Config::readFile ( fname );} |
30 | | catch ( FileIOException f ) {it_error ( "File " + string ( fname ) + " not found" );} |
31 | | catch ( ParseException& P ) { |
32 | | char msg[200]; |
33 | | sprintf ( msg,"Error in file %s on line %d.", fname, P.getLine() ); |
| 57 | //! attach new RootElement instance to a file (typically with an XML extension) |
| 58 | UIFile( const string &file_name ); |
| 59 | |
| 60 | //! loads root element from a file |
| 61 | void Load(); |
| 62 | |
| 63 | //! Save UserInfo to the file (typically with an XML extension) |
| 64 | void Save (); |
| 65 | |
| 66 | operator Setting&(); |
| 67 | }; |
| 68 | |
| 69 | |
| 70 | /*! |
| 71 | @brief UserInfo is an abstract is for internal purposes only. Use CompoundUserInfo<T> or ParticularUI<T> instead. |
| 72 | The raison d'etre of this class is to allow pointers to its templated descendants. |
| 73 | |
| 74 | Also, the main functions of the whole UserInfo library are included within this class, see |
| 75 | static methods 'Build' and 'Save'. |
| 76 | |
| 77 | |
| 78 | /*!\brief Builds computational object from a UserInfo structure |
| 79 | |
| 80 | Return value is a pointer to the created object (memory management issue?) |
| 81 | / |
| 82 | |
| 83 | */ |
| 84 | class UI |
| 85 | { |
| 86 | private: |
| 87 | //! just a typedef shortuct for a constant pointer to UI |
| 88 | typedef UI* pUI; |
| 89 | |
| 90 | //! static class encalupsating map of names to related UserInfos |
| 91 | //! |
| 92 | //! The key property of this class is that it initilaized the internal map immediately |
| 93 | //! when it is used for a first time. |
| 94 | class StringToUIMap |
| 95 | { |
| 96 | private: |
| 97 | //! Type definition of mapping which transforms type names to the related user infors |
| 98 | typedef map< const string, pUI > MappedString2UI; |
| 99 | |
| 100 | //! immediately initialized instance of type MappedString2UI |
| 101 | static MappedString2UI& privateMap(); |
| 102 | |
| 103 | public: |
| 104 | //! add a pair key-userinfo into the internal map |
| 105 | static void Add( const string &className, pUI pInstance ); |
| 106 | |
| 107 | //! search for an userinfo related to the passed key within the internal map |
| 108 | static pUI Retrieve( const string &className ); |
| 109 | }; |
| 110 | |
| 111 | //! internal method assembling a typeless instance from components obtained by the 'AssemblyComponentsFromSetting()' method |
| 112 | virtual bdmroot* New() = 0; |
| 113 | |
| 114 | //! type name defined by user |
| 115 | const string className; |
| 116 | |
| 117 | protected: |
| 118 | |
| 119 | //! default constructor |
| 120 | UI( const string& className ) : className ( className ) |
| 121 | { |
| 122 | StringToUIMap::Add( className, this ); |
| 123 | } |
| 124 | |
| 125 | //! Virtual destructor for future use; |
| 126 | virtual ~UI(){}; |
| 127 | |
| 128 | private: |
| 129 | |
| 130 | //! This methods tries to save an instance of type T (or some of its descendant types) |
| 131 | //! and build DOM tree accordingly. Then, it creates a new DOMNode named according className |
| 132 | //! and connecti it to the passed Setting as a new child node. |
| 133 | template<class T> static void ToSetting( T &instance, Setting &element ) |
| 134 | { |
| 135 | string &className = ParticularUI<T>::ui.className; |
| 136 | |
| 137 | // add attribute "class" |
| 138 | Setting &type = root.add( "class", Setting::TypeString ); |
| 139 | type = className; |
| 140 | |
| 141 | try |
| 142 | { |
| 143 | // instance disassembling |
| 144 | instance.ToSetting( root ); |
| 145 | } |
| 146 | catch(SettingException xcptn) |
| 147 | { |
| 148 | it_error ( "UI: the method " + className + ".ToSetting(Setting&) has thrown an exception when filling the setting " + xcptn.getPath() + ". Try to correct this method." ); |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | template<class T> static T* FromSetting( const Setting &element ) |
| 153 | { |
| 154 | RevealIfLinked revealed_link( element ); |
| 155 | const Setting &root = revealed_link.root(); |
| 156 | |
| 157 | ASSERT_UITYPE(root,TypeGroup); |
| 158 | |
| 159 | // we get a velue stored in the "class" attribute |
| 160 | string className; |
| 161 | if( !root.lookupValue( "class", className ) ) |
| 162 | { |
| 163 | stringstream msg; |
| 164 | msg << "UI: the class identifier is missing within the setting """ << root.getPath() << """. Check line " |
| 165 | << root.getSourceLine() << "."; |
| 166 | it_error ( msg.str() ); |
| 167 | } |
| 168 | |
| 169 | |
| 170 | // and finally we find a UserInfo related to this type |
| 171 | pUI pRelatedUI = StringToUIMap::Retrieve( className ); |
| 172 | if( !pRelatedUI) |
| 173 | it_error ( "UI: class " + className + " was not properly registered. Use the macro ""UIREGISTER([class name]);"" within your code." ); |
| 174 | |
| 175 | bdmroot* pTypelessInstance = pRelatedUI->New(); |
| 176 | |
| 177 | T* pInstance = NULL; |
| 178 | try |
| 179 | { |
| 180 | pInstance = (T*) pTypelessInstance ; |
| 181 | } |
| 182 | catch(...) |
| 183 | { |
| 184 | it_error ( "UI: class " + className + " is not a descendant of the desired output class. Try to call the UI::Build function with a different type parameter." ); |
| 185 | } |
| 186 | |
| 187 | try |
| 188 | { |
| 189 | // instance assembling |
| 190 | pInstance->FromSetting( root ); |
| 191 | } |
| 192 | catch(SettingException xcptn) |
| 193 | { |
| 194 | string msg = "UI: the method " + className + ".FromSetting(Setting&) has thrown an exception when parsing the setting " + xcptn.getPath() + ". Try to correct this method."; |
36 | | } |
| 197 | return pInstance; |
| 198 | } |
| 199 | |
| 200 | |
| 201 | |
| 202 | public: |
| 203 | |
| 204 | // vraci true, kdyz to byl platny link, jinak false.. v pripade chyby konci it_errorem.. |
| 205 | // do elementu vrati setting prislusny po rozbaleni linku, jinak ponecha beze zmeny |
| 206 | class RevealIfLinked |
| 207 | { |
| 208 | private: |
| 209 | UIFile *file; |
| 210 | const Setting * result; |
| 211 | |
| 212 | public: |
| 213 | |
| 214 | RevealIfLinked( const Setting &element ) |
| 215 | { |
| 216 | file = NULL; |
| 217 | result = &element; |
| 218 | |
| 219 | if( element.getType() != Setting::TypeString ) |
| 220 | return; |
| 221 | |
| 222 | string link = (string) element; |
| 223 | size_t aerobase = link.find('@'); |
| 224 | if( aerobase != string::npos ) |
| 225 | { |
| 226 | string file_name = link.substr( aerobase + 1, link.length() ); |
| 227 | file = new UIFile( file_name ); |
| 228 | file->Load(); |
| 229 | // TODO OSETRIT FALSE, vyhodit iterr |
| 230 | |
| 231 | result = &(Setting&)(*file); |
| 232 | |
| 233 | link = link.substr( 0, aerobase ); |
| 234 | } |
| 235 | else |
| 236 | while ( !result->isRoot() ) |
| 237 | result = &result->getParent(); |
| 238 | |
| 239 | if( !result->exists( link ) ) |
| 240 | { |
| 241 | // vyhodi chybu v pripade chyby |
| 242 | printf(""); |
| 243 | } |
| 244 | result = &(*result)[link]; |
| 245 | return; |
| 246 | } |
| 247 | |
| 248 | ~RevealIfLinked() |
| 249 | { |
| 250 | if( file ) delete file; |
| 251 | } |
| 252 | |
| 253 | |
| 254 | const Setting& root() |
| 255 | { |
| 256 | return *result; |
| 257 | } |
| 258 | }; |
| 259 | |
| 260 | private: |
| 261 | static const Setting* ToChildSetting( const Setting &element, const int index ) |
| 262 | { |
| 263 | if( !element.isAggregate()) |
| 264 | return NULL; |
| 265 | |
| 266 | if( element.getLength() <= index ) |
| 267 | return NULL; |
| 268 | |
| 269 | return &element[index]; |
| 270 | } |
| 271 | |
| 272 | static const Setting* ToChildSetting( const Setting &element, const string &name ) |
| 273 | { |
| 274 | if( !element.isGroup() ) |
| 275 | return NULL; |
| 276 | |
| 277 | if( !element.exists( name ) ) |
| 278 | return NULL; |
| 279 | |
| 280 | return &element[name]; |
| 281 | } |
| 282 | |
| 283 | static Setting& ToChildSetting( Setting &element, const int index ) |
| 284 | { |
| 285 | if( !element.isAggregate()) |
| 286 | { |
| 287 | // TODO CO ZA TYP? ASI NE GROUP, COZ.. |
| 288 | } |
| 289 | if( element.getLength() <= index ) |
| 290 | { |
| 291 | stringstream msg; |
| 292 | msg << "UI: there is not any child with index " << index << " in the parsed setting " |
| 293 | << element.getPath() << ", check line " << element.getSourceLine() << "."; |
| 294 | |
| 295 | it_error ( msg.str() ); |
| 296 | } |
| 297 | return element[index]; |
| 298 | } |
| 299 | |
| 300 | static Setting& ToChildSetting( Setting &element, const string &name ) |
| 301 | { |
| 302 | ASSERT_UITYPE(element,TypeGroup); |
| 303 | if( !element.exists( name ) ) |
| 304 | { |
| 305 | stringstream msg; |
| 306 | msg << "UI: there is not any child named """ << name << """ in the parsed setting " |
| 307 | << element.getPath() << ", check line " << element.getSourceLine() << "."; |
| 308 | |
| 309 | it_error ( msg.str() ); |
| 310 | } |
| 311 | return element[name]; |
| 312 | } |
| 313 | |
| 314 | //! This methods tries to build a new double matrix |
| 315 | static bool FromSetting( mat& matrix, const Setting &root ) |
| 316 | { |
| 317 | ASSERT_UITYPE(root,TypeList); |
| 318 | if( root.getLength() != 3 ) |
| 319 | { |
| 320 | stringstream msg; |
| 321 | msg << "UI: the setting " << root.getPath() << """ supposed to represent a matrix element has wrong syntax"". Check line " |
| 322 | << root.getSourceLine() << "."; |
| 323 | it_error ( msg.str() ); |
| 324 | } |
| 325 | |
| 326 | Setting &cols_setting = root[0]; |
| 327 | Setting &rows_setting = root[1]; |
| 328 | Setting &values = root[2]; |
| 329 | |
| 330 | ASSERT_UITYPE(cols_setting,TypeInt); |
| 331 | ASSERT_UITYPE(rows_setting,TypeInt); |
| 332 | ASSERT_UITYPE(values,TypeArray); |
| 333 | |
| 334 | int cols = cols_setting; |
| 335 | int rows = rows_setting; |
| 336 | |
| 337 | if( values.getLength() != cols * rows ) |
| 338 | { |
| 339 | stringstream msg; |
| 340 | msg << "UI: the lenght of array containing matrix values within setting " << root.getPath() << """ is improper, check line " |
| 341 | << root.getSourceLine() << "."; |
| 342 | it_error ( msg.str() ); |
| 343 | } |
| 344 | |
| 345 | matrix.set_size( rows, cols ); |
| 346 | |
| 347 | if( cols == 0 || rows == 0 ) |
| 348 | return true; |
| 349 | |
| 350 | if( !values[0].isNumber() ) |
| 351 | { |
| 352 | stringstream msg; |
| 353 | msg << "UI: the array containing matrix values within setting " << root.getPath() << """ has to contain numeric values only! Check line " |
| 354 | << root.getSourceLine() << "."; |
| 355 | it_error ( msg.str() ); |
| 356 | } |
| 357 | |
| 358 | // Build matrix row-wise |
| 359 | int k = 0; |
| 360 | for( int i=0;i<rows;i++ ) |
| 361 | for( int j=0; j<cols; j++) |
| 362 | matrix(i,j) = values[k++]; |
| 363 | |
| 364 | return true; |
| 365 | } |
| 366 | |
| 367 | //! This methods tries to save a double matrix |
| 368 | static void ToSetting( mat &matrix, Setting &root ) |
| 369 | { |
| 370 | Setting &cols = root.add( Setting::TypeInt ); |
| 371 | cols = matrix.cols(); |
| 372 | |
| 373 | Setting &rows = root.add( Setting::TypeInt ); |
| 374 | rows = matrix.rows(); |
| 375 | |
| 376 | Setting &values = root.add( Setting::TypeArray ); |
| 377 | |
| 378 | // Build matrix row-wise |
| 379 | for( int i=0; i<matrix.rows(); i++ ) |
| 380 | for( int j=0; j<matrix.cols(); j++) |
| 381 | { |
| 382 | Setting &newField = values.add(Setting::TypeFloat); |
| 383 | newField = matrix(i,j); |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | //! This methods tries to build a new integer vector |
| 388 | static bool FromSetting( ivec &vec, const Setting &root ) |
| 389 | { |
| 390 | ASSERT_UITYPE(root,TypeArray); |
| 391 | |
| 392 | int len = root.getLength(); |
| 393 | vec.set_length( len ); |
| 394 | if( len == 0 ) return true; |
| 395 | ASSERT_UITYPE(root[0],TypeInt); |
| 396 | |
| 397 | for( int i=0; i < len; i++ ) |
| 398 | vec(i) = root[i]; |
| 399 | |
| 400 | return true; |
| 401 | } |
| 402 | |
| 403 | //! This methods tries to save an integer vector |
| 404 | static void ToSetting( ivec &vec, Setting &root ) |
| 405 | { |
| 406 | for( int i=0; i<vec.length(); i++ ) |
| 407 | { |
| 408 | Setting &newField = root.add(Setting::TypeInt); |
| 409 | newField = vec(i); |
| 410 | } |
| 411 | } |
| 412 | |
| 413 | //! This methods tries to build a new array of strings |
| 414 | static bool FromSetting( Array<string> &string_array, const Setting &root) |
| 415 | { |
| 416 | ASSERT_UITYPE(root,TypeArray); |
| 417 | |
| 418 | int len = root.getLength(); |
| 419 | string_array.set_length( len ); |
| 420 | if( len == 0 ) return true; |
| 421 | ASSERT_UITYPE(root[0],TypeString); |
| 422 | |
| 423 | for( int i=0; i < len; i++ ) |
| 424 | string_array(i) = (string)root[i]; |
| 425 | |
| 426 | return true; |
| 427 | } |
| 428 | |
| 429 | //! This methods tries to save an array of strings |
| 430 | static void ToSetting( Array<string> &string_array, Setting &root ) |
| 431 | { |
| 432 | for( int i=0; i<string_array.length(); i++ ) |
| 433 | { |
| 434 | Setting &newField = root.add(Setting::TypeString); |
| 435 | newField = string_array(i); |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | public: |
| 440 | |
| 441 | //! This methods tries to build a new instance of type T (or some of its descendant types) |
| 442 | //! according to a data stored in a DOMNode named className within a child nodes of the passed element. |
| 443 | //! If an error occurs, it returns a NULL pointer. |
| 444 | |
| 445 | //! Prototype of a UI builder. Return value is by the second argument since it type checking via \c dynamic_cast. |
| 446 | template<class T> static T* Build( Setting &element, const int index ) |
| 447 | { |
| 448 | return FromSetting<T>( ToChildSetting( element, index ) ); |
| 449 | } |
| 450 | |
| 451 | template<class T> static T* Build( Setting &element, const string &name ) |
| 452 | { |
| 453 | return FromSetting<T>( ToChildSetting( element, name ) ); |
| 454 | } |
| 455 | |
| 456 | //! This methods tries to save an instance of type T (or some of its descendant types) |
| 457 | //! and build DOM tree accordingly. Then, it creates a new DOMNode named according className |
| 458 | //! and connecti it to the passed Setting as a new child node. |
| 459 | template<class T> static void Save( T &instance, Setting &element ) |
| 460 | { |
| 461 | Setting &root = element.add( Setting::TypeGroup ); |
| 462 | ToSetting( instance, root ); |
| 463 | } |
| 464 | |
| 465 | //! This methods tries to save an instance of type T (or some of its descendant types) |
| 466 | //! and build DOM tree accordingly. Then, it creates a new DOMNode named according className |
| 467 | //! and connecti it to the passed Setting as a new child node. |
| 468 | template<class T> static void Save( T &instance, Setting &element, const string &name ) |
| 469 | { |
| 470 | Setting &root = element.add( name, Setting::TypeGroup ); |
| 471 | ToSetting( instance, root ); |
| 472 | } |
| 473 | |
| 474 | //! This methods tries to build a new double matrix |
| 475 | static bool Get( mat& matrix, const Setting &element, const string &name ) |
| 476 | { |
| 477 | const Setting *root = ToChildSetting( element, name ); |
| 478 | if( !root ) return false; |
| 479 | return FromSetting( matrix, *root ); |
| 480 | } |
| 481 | |
| 482 | //! This methods tries to build a new double matrix |
| 483 | static bool Get( mat& matrix, const Setting &element, const int index ) |
| 484 | { |
| 485 | const Setting *root = ToChildSetting( element, index ); |
| 486 | if( !root ) return false; |
| 487 | return FromSetting( matrix, *root ); |
| 488 | } |
| 489 | |
| 490 | //! This methods tries to save a double matrix |
| 491 | static void Save( mat &matrix, Setting &element, const string &name ) |
| 492 | { |
| 493 | Setting &root = element.add( name, Setting::TypeList ); |
| 494 | ToSetting( matrix, root ); |
| 495 | } |
| 496 | |
| 497 | //! This methods tries to save a double matrix |
| 498 | static void Save( mat &matrix, Setting &element ) |
| 499 | { |
| 500 | Setting &root = element.add( Setting::TypeList ); |
| 501 | ToSetting( matrix, root ); |
| 502 | } |
| 503 | |
| 504 | |
| 505 | //! This methods tries to build a new double vec |
| 506 | static bool Get( ivec& vec, const Setting &element, const string &name ) |
| 507 | { |
| 508 | const Setting *root = ToChildSetting( element, name ); |
| 509 | if( !root ) return false; |
| 510 | return FromSetting( vec, *root ); |
| 511 | } |
| 512 | |
| 513 | //! This methods tries to build a new double vec |
| 514 | static bool Get( ivec& vec, const Setting &element, const int index ) |
| 515 | { |
| 516 | const Setting *root = ToChildSetting( element, index ); |
| 517 | if( !root ) return false; |
| 518 | return FromSetting( vec, *root ); |
| 519 | } |
| 520 | |
| 521 | //! This methods tries to save a double vec |
| 522 | static void Save( ivec &vec, Setting &element, const string &name ) |
| 523 | { |
| 524 | Setting &root = element.add( name, Setting::TypeArray ); |
| 525 | ToSetting( vec, root ); |
| 526 | } |
| 527 | |
| 528 | //! This methods tries to save a double vec |
| 529 | static void Save( ivec &vec, Setting &element) |
| 530 | { |
| 531 | Setting &root = element.add( Setting::TypeArray ); |
| 532 | ToSetting( vec, root ); |
| 533 | } |
| 534 | |
| 535 | |
| 536 | //! This methods tries to build a new double string_array |
| 537 | static bool Get( Array<string> &string_array, const Setting &element, const string &name ) |
| 538 | { |
| 539 | const Setting *root = ToChildSetting( element, name ); |
| 540 | if( !root ) return false; |
| 541 | return FromSetting( string_array, *root ); |
| 542 | } |
| 543 | |
| 544 | //! This methods tries to build a new double string_array |
| 545 | static bool Get( Array<string> &string_array, const Setting &element, const int index ) |
| 546 | { |
| 547 | const Setting *root = ToChildSetting( element, index ); |
| 548 | if( !root ) return false; |
| 549 | return FromSetting( string_array, *root ); |
| 550 | } |
| 551 | |
| 552 | //! This methods tries to save a double string_array |
| 553 | static void Save( Array<string> &string_array, Setting &element, const string &name ) |
| 554 | { |
| 555 | Setting &root = element.add( name, Setting::TypeArray ); |
| 556 | ToSetting( string_array, root ); |
| 557 | } |
| 558 | |
| 559 | //! This methods tries to save a double string_array |
| 560 | static void Save( Array<string> &string_array, Setting &element ) |
| 561 | { |
| 562 | Setting &root = element.add( Setting::TypeArray ); |
| 563 | ToSetting( string_array, root ); |
| 564 | } |
| 565 | |
| 566 | |