root/library/bdm/base/user_info.cpp @ 471

Revision 471, 11.1 kB (checked in by mido, 15 years ago)

1) ad UserInfo?: UI::get a UI::build predelany tak, ze vraci fals / NULL v pripade neexistence pozadovaneho Settingu, pridana enumericky typ UI::SettingPresence?, predelany stavajici UI implementace, dodelana UI dokumentace
2) dokoncena konfigurace ASTYLERU, brzy bude aplikovan
3) doxygen nastaven tak, ze vytvari soubor doxy_warnings.txt

  • Property svn:eol-style set to native
Line 
1//
2// C++ Implementation: user_info.cpp
3//
4// Description: UI (user info) class for loading/saving objects from/to configuration files.
5//
6//
7// Author: smidl <smidl@utia.cas.cz>, (C) 2009
8//
9// Copyright: See COPYING file that comes with this distribution
10//
11//
12
13#include "user_info.h"
14
15namespace bdm
16{
17///////////////////////////// Class UIFile /////////////////////////////////////////////
18
19UIFile::UIFile()
20{
21}
22
23UIFile::UIFile ( const string &file_name )
24{
25    try
26    {
27        readFile( file_name.c_str()  );
28                // this flag has to be set AFTER each file load, that is why it is right here
29                setAutoConvert( true );
30    }
31    catch ( FileIOException f )
32    {
33        it_error ( "UI error: file " + file_name + " not found." );
34    }
35    catch ( ParseException& P )
36    {
37        stringstream msg;
38        msg << "UI error: parsing error """ << P.getError() << """ in file " << file_name << " on line " <<  P.getLine() << ".";
39        it_error ( msg.str() );
40    }
41}
42
43
44void UIFile::save(const string &file_name )
45{
46    try
47    {
48        writeFile ( file_name.c_str()  );
49    }
50    catch ( FileIOException f )
51    {
52        it_error( "UI error: file " + file_name + " is inacessible." );
53    }
54}
55
56UIFile::operator Setting&()
57{
58    return getRoot();
59}
60
61///////////////////////////// Class UI::MappedUI /////////////////////////////////////////////
62
63UI::MappedUI::StringToUIMap& UI::MappedUI::mapped_strings()
64{
65        // this way it is ensured that there is only one instance of StringTpUIMap, and
66        // what is more, this declaration leaves its allocation/deallocation on the compiler
67    static StringToUIMap var;
68    return var;
69}
70
71UI::MappedUI::TypeInfoToStringMap& UI::MappedUI::mapped_type_infos()
72{
73        // this way it is ensured that there is only one instance of TypeInfoToStringMap, and
74        // what is more, this declaration leaves its allocation/deallocation on the compiler
75    static TypeInfoToStringMap var;
76    return var;
77}
78
79void UI::MappedUI::add_class( const string &class_name, const type_info * const class_type_info, const UI* const ui )
80{
81    pair< const string, const UI* const > new_pair = make_pair( class_name, ui );
82    mapped_strings().insert( new_pair );
83    mapped_type_infos().insert( make_pair( class_type_info, new_pair.first ) );
84}
85
86void UI::MappedUI::unregistered_class_error( const string &unregistered_class_name )
87{
88        stringstream msg;
89    msg << "UI error: class " + unregistered_class_name + " was not properly registered. Use the macro ""UIREGISTER([class name]);"" within your code." << endl;
90
91        if( mapped_strings().size() )
92        {
93            StringToUIMap::const_iterator iter = mapped_strings().begin();
94                msg << "These classes are already registered: " << iter->first;
95                for(iter++; iter != mapped_strings().end(); iter++)
96                        msg << ", " << iter->first;
97                msg << "." << endl;
98        }                       
99        else
100                msg << "There is not any registered class yet!" << endl;
101       
102    it_error ( msg.str() );             
103}
104
105const UI& UI::MappedUI::retrieve_ui( const string &class_name )
106{
107    StringToUIMap::const_iterator iter = mapped_strings().find( class_name );
108    if ( iter == mapped_strings().end())
109                unregistered_class_error( class_name );
110           
111        return *iter->second;
112}
113
114const string& UI::MappedUI::retrieve_class_name( const type_info * const class_type_info )
115{
116    TypeInfoToStringMap::const_iterator iter = mapped_type_infos().find( class_type_info );
117    if ( iter == mapped_type_infos().end())
118                unregistered_class_error( "with RTTI name " + string(class_type_info->name()) );
119    return iter->second;
120}
121
122///////////////////////////// Class SettingResolver /////////////////////////////////////////////
123
124SettingResolver::SettingResolver( const Setting &potential_link )
125        : result( initialize_reference( file, potential_link ) )
126{
127}
128
129const Setting& SettingResolver::initialize_reference(UIFile *&file, const Setting &potential_link)
130{
131        file = NULL;
132
133    if ( potential_link.getType() !=  Setting::TypeString )
134            return potential_link;
135       
136        string link = (const char*) potential_link;
137    size_t aerobase = link.find('@');
138
139        const Setting *result;
140    if ( aerobase != string::npos )
141    {
142        string file_name = link.substr( aerobase + 1, link.length() );
143        file = new UIFile( file_name );
144        result = &(Setting&)(*file);
145        link = link.substr( 0, aerobase );
146    }
147    else
148        {
149                result = &potential_link;
150        while ( !result->isRoot() )
151            result = &result->getParent();
152        }
153
154    if ( !result->exists( link ) )
155        throw UIException( "linked setting was not found", potential_link );
156
157    return (*result)[link];
158}
159
160SettingResolver::~SettingResolver()
161{
162    if ( file ) delete file;
163}
164
165///////////////////////////// Class UI /////////////////////////////////////////////
166
167void UI::assert_type( const Setting &element, Setting::Type type )
168{
169        if( element.getType()!=type)
170                throw UIException("wrong setting type", element);
171}
172
173const Setting& UI::to_child_setting( const Setting &element, const int index )
174{
175    if ( !element.isList())
176        throw UIException( "only TypeList elements could be indexed by integers", element );
177
178    return element[index];
179}
180
181const Setting& UI::to_child_setting( const Setting &element, const string &name )
182{
183    if ( !element.isGroup())
184        throw UIException( "only TypeGroup elements could be indexed by strings", element );
185
186    return element[name];
187}
188
189void UI::save( const int &integer, Setting &element, const string &name)
190{
191    Setting &set = (name == "") ? element.add( Setting::TypeInt )
192                                            : element.add( name, Setting::TypeInt );
193    set = integer;
194}
195
196void UI::save( const double &real, Setting &element, const string &name)
197{
198    Setting &set = (name == "") ? element.add( Setting::TypeFloat )
199                                            : element.add( name, Setting::TypeFloat );
200    set = real;
201}
202
203void UI::save( const string &str, Setting &element, const string &name)
204{
205    Setting &set = (name == "") ? element.add( Setting::TypeString )
206                                            : element.add( name, Setting::TypeString );
207    set = str;
208}
209
210void UI::save( const mat &matrix, Setting &element, const string &name)
211{
212    Setting &set = (name == "") ? element.add( Setting::TypeList )
213                                            : element.add( name, Setting::TypeList );
214
215    Setting &cols = set.add( Setting::TypeInt );
216    cols = matrix.cols();
217
218    Setting &rows = set.add( Setting::TypeInt );
219    rows = matrix.rows();
220
221    Setting &elements = set.add( Setting::TypeArray );
222
223    // build matrix row-wise
224    for ( int i=0; i<matrix.rows(); i++ )
225        for ( int j=0; j<matrix.cols(); j++)
226        {
227            Setting &new_field = elements.add(Setting::TypeFloat);
228            new_field = matrix(i,j);
229        }
230}
231
232void UI::save( const ivec &vector, Setting &element, const string &name)
233{
234    Setting &set = (name == "") ? element.add( Setting::TypeArray )
235                    : element.add( name, Setting::TypeArray );
236    for ( int i=0; i<vector.length(); i++ )
237    {
238        Setting &new_field = set.add(Setting::TypeInt);
239        new_field = vector(i);
240    }
241}
242
243void UI::save( const vec &vector, Setting &element, const string &name)
244{
245    Setting &set = (name == "") ? element.add( Setting::TypeArray )
246                    : element.add( name, Setting::TypeArray );
247    for ( int i=0; i<vector.length(); i++ )
248    {
249                Setting &new_field = set.add(Setting::TypeFloat);
250        new_field = vector(i);
251    }
252}
253
254void UI::from_setting( mat& matrix, const Setting &element )
255{
256    const SettingResolver link( element );
257
258    if ( link.result.isNumber() )
259    {
260        matrix.set_size( 1, 1 );
261        matrix(0,0) = link.result;
262        return;
263    }
264
265    if ( link.result.isList() )
266    {
267                int data_offset;
268
269                if ( link.result.getLength() == 3 )
270                        data_offset = 0;
271                else if ( link.result.getLength() == 4 )
272                {
273                assert_type(link.result[0],Setting::TypeString);
274                        const char* elem1=(const char*)link.result[0];
275                        if( (strcmp(elem1, "matrix") ))
276                                throw UIException( "the setting supposed to represent a matrix element has wrong syntax", link.result );
277
278                        data_offset = 1;
279                }
280                else
281                        throw UIException( "the setting supposed to represent a matrix element has wrong syntax", link.result );
282
283        Setting &rows_setting = link.result[0 + data_offset];
284        Setting &cols_setting = link.result[1 + data_offset];
285        Setting &elements = link.result[2 + data_offset];
286
287        assert_type(cols_setting,Setting::TypeInt);
288        assert_type(rows_setting,Setting::TypeInt);
289        assert_type(elements,Setting::TypeArray);
290
291        int cols = cols_setting;
292        int rows = rows_setting;
293
294        if ( cols < 0 || rows < 0 )
295            throw UIException( "the dimensions of a matrix has to be non-negative", link.result );
296
297        if ( elements.getLength() != cols * rows )
298            throw UIException( "the count of the matrix elements is incompatible with matrix dimension", elements );
299
300        matrix.set_size( rows, cols );
301
302        if ( cols == 0 || rows == 0 )
303            return;
304
305        if ( !elements[0].isNumber() )
306            throw UIException( "matrix elements have to be numbers", elements[0] );
307
308        // build matrix row-wise
309        int k = 0;
310        for ( int i=0; i<rows; i++ )
311            for ( int j=0; j<cols; j++)
312                matrix(i,j) = elements[k++];
313        return;
314    }
315
316    throw UIException( "only numeric types or TypeList are supported as matrix values", link.result );
317}
318
319void UI::from_setting( vec &vector, const Setting &element )
320{
321    const SettingResolver link( element );
322
323    if ( link.result.isNumber() )
324    {
325        vector.set_length( 1 );
326        vector(0) = link.result;
327        return;
328    }
329
330    if ( link.result.isList() )
331    {
332                mat matrix;
333                from_setting( matrix, link.result );
334
335        if ( matrix.cols() != 1 && matrix.rows() !=1)
336                        throw UIException( "the vector length is invalid, it seems to be rather a matrix", link.result );
337
338        int len = matrix.rows() * matrix.cols();
339        vector.set_length ( len );
340        if ( len == 0 ) return;
341
342        if ( matrix.cols() == 1 )
343                        for ( int i=0; i<len; i++ )
344                                vector(i) = matrix(i,0);
345                else
346                        for ( int i=0; i<len; i++ )
347                                vector(i) = matrix(0,i);
348        return;
349    }
350
351    if ( link.result.isArray() )
352    {
353        int len = link.result.getLength();
354        vector.set_length( len );
355        if ( len == 0 ) return;
356
357        if ( !link.result[0].isNumber())
358            throw UIException("a vector element has to be a number", link.result[0]);
359
360        for ( int i=0; i < len; i++ ) 
361            vector(i) = link.result[i];
362
363                return;
364    }
365
366    throw UIException( "only numeric types, TypeArray or TypeList are supported as vector values", link.result );
367}
368
369void UI::from_setting( ivec &vector, const Setting &element )
370{
371        vec double_vector;
372        from_setting( double_vector, element ); 
373    int len = double_vector.length();
374    vector.set_length ( len );
375        for( int i = 0; i< len; i++ )
376                vector(i) = (int) double_vector(i);
377}
378
379void UI::from_setting( string &str, const Setting &element )
380{
381    assert_type(element,Setting::TypeString);
382    str = (const char*) element;
383}
384
385void UI::from_setting( int &integer, const Setting &element )
386{
387    assert_type(element,Setting::TypeInt);
388    integer = element;
389}
390
391void UI::from_setting( double &real, const Setting &element )
392{
393    assert_type(element,Setting::TypeFloat);
394    real = element;
395}
396
397}
Note: See TracBrowser for help on using the browser.