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

Revision 540, 11.1 kB (checked in by vbarta, 15 years ago)

split UIException into 3

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