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

Revision 477, 10.6 kB (checked in by mido, 15 years ago)

panove, vite, jak jsem peclivej na upravu kodu.. snad se vam bude libit:) konfigurace je v souboru /system/astylerc

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