Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/physics/src/core/XMLPort.h @ 2519

Last change on this file since 2519 was 2373, checked in by rgrieder, 16 years ago

Finished work on new XMLport macro (XMLPortParamVariable).

  • Property svn:eol-style set to native
File size: 37.9 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file XMLPort.h
31    @brief Declaration of the XMLPort helper classes and macros.
32
33    XMLPort is a virtual function of every BaseObject. Every object can change this function.
34    The XMLPort function gets called with an XMLElement, containing all attributes and
35    subclasses the object gets from the levelfile.
36
37    This file declares classes and macros to simplify XML-parsing.
38*/
39
40#ifndef _XMLPort_H__
41#define _XMLPort_H__
42
43#include "CorePrereqs.h"
44
45#include "util/Debug.h"
46#include "util/MultiType.h"
47#include "tinyxml/ticpp.h"
48#include "XMLIncludes.h"
49#include "Executor.h"
50#include "CoreIncludes.h"
51#include "BaseObject.h"
52
53// ------------
54// XMLPortParam
55
56/**
57    @brief Declares an XML attribute with a name, which will be set through load- and savefunctions.
58    @param classname The name of the class owning this param
59    @param paramname The name of the attribute
60    @param loadfunction A function to set the param in the object with a given value (~a set-function)
61    @param savefunction A function to get the value of the param from the object (~a get-function)
62    @param xmlelement The XMLElement, you get this from the XMLPort function
63    @param mode The mode (load or save), you get this from the XMLPort function
64
65    In the XML file, a param or attribute will be set like this:
66    <classname paramname="value" />
67
68    The macro will then call loadfunction(value) to set the given value (or call savefunction() to
69    write an existing value to an XML file).
70*/
71#define XMLPortParam(classname, paramname, loadfunction, savefunction, xmlelement, mode) \
72    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
73    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
74    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, classname, this, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode)
75
76/**
77    @brief Declares an XML attribute with a name, which will be set through a variable.
78    @param classname The name of the class owning this param
79    @param paramname The name of the attribute
80    @param variable Name of the variable used to save and load the value
81    @param xmlelement The XMLElement, you get this from the XMLPort function
82    @param mode The mode (load or save), you get this from the XMLPort function
83
84    In the XML file, a param or attribute will be set like this:
85    <classname paramname="value" />
86
87    The macro will then store "value" in the variable or read it when saving.
88*/
89#define XMLPortParamVariable(classname, paramname, variable, xmlelement, mode) \
90    static XMLPortVariableHelperClass xmlcontainer##variable##dummy((void*)&variable); \
91    static ExecutorMember<orxonox::XMLPortVariableHelperClass>* xmlcontainer##variable##loadexecutor = static_cast<ExecutorMember<orxonox::XMLPortVariableHelperClass>*>(&(orxonox::createExecutor(orxonox::createFunctor(orxonox::XMLPortVariableHelperClass::getLoader(variable)), std::string( #classname ) + "::" + #variable + "loader"))); \
92    static ExecutorMember<orxonox::XMLPortVariableHelperClass>* xmlcontainer##variable##saveexecutor = static_cast<ExecutorMember<orxonox::XMLPortVariableHelperClass>*>(&(orxonox::createExecutor(orxonox::createFunctor(orxonox::XMLPortVariableHelperClass::getSaver (variable)), std::string( #classname ) + "::" + #variable + "saver" ))); \
93    XMLPortParamGeneric(xmlcontainer##variable, classname, orxonox::XMLPortVariableHelperClass, &xmlcontainer##variable##dummy, paramname, xmlcontainer##variable##loadexecutor, xmlcontainer##variable##saveexecutor, xmlelement, mode)
94
95/**
96    @brief Declares an XML attribute with a name, which will be set through a variable and gotten from a function.
97    @param classname The name of the class owning this param
98    @param paramname The name of the attribute
99    @param variable Name of the variable used to save the value
100    @param savefunction A function to get the value of the param from the object (~a get-function)
101    @param xmlelement The XMLElement, you get this from the XMLPort function
102    @param mode The mode (load or save), you get this from the XMLPort function
103
104    In the XML file, a param or attribute will be set like this:
105    <classname paramname="value" />
106
107    The macro will then store "value" in the variable or read it when saving.
108*/
109#define XMLPortParamVariableOnLoad(classname, paramname, variable, savefunction, xmlelement, mode) \
110    static XMLPortVariableHelperClass xmlcontainer##variable##dummy((void*)&variable); \
111    static ExecutorMember<orxonox::XMLPortVariableHelperClass>* xmlcontainer##variable##loadexecutor = static_cast<ExecutorMember<orxonox::XMLPortVariableHelperClass>*>(&(orxonox::createExecutor(orxonox::createFunctor(orxonox::XMLPortVariableHelperClass::getLoader(variable)), std::string( #classname ) + "::" + #variable + "loader"))); \
112    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
113    XMLPortParamGeneric(xmlcontainer##variable, classname, orxonox::XMLPortVariableHelperClass, &xmlcontainer##variable##dummy, paramname, xmlcontainer##variable##loadexecutor, xmlcontainer##variable##saveexecutor, xmlelement, mode)
114
115/**
116    @brief This is the same as XMLPortParam, but you can set the template arguments needed to store the loadfunction.
117
118    Sometimes the name of the loadfunction is ambiguous (example: setPosition(Vector3) or
119    setPosition(float, float, float)). In this case, you can choose the right function by
120    telling the types of the functionparams. In our example, this would be either
121    > XMLPortParamTemplate(classname, paramname, loadfunction, savefunction, xmlelement, mode, Vector3);
122    or
123    > XMLPortParamTemplate(classname, paramname, loadfunction, savefunction, xmlelement, mode, float, float, float);
124    You don't have to use this, if there exist only one function with the given name.
125*/
126#define XMLPortParamTemplate(classname, paramname, loadfunction, savefunction, xmlelement, mode, ...) \
127    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
128    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
129    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, classname, this, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode)
130
131// --------------------
132// XMLPortParamLoadOnly
133
134/**
135    @brief Declares an XML attribute with a name, which can be set through a loadfunction.
136
137    This is the same as XMLPortParam, but you don't need a savefunction (get-function). Therefore,
138    this param won't be saved in an XML file, but you can add the attribute manually an it will be
139    loaded.
140
141    This might be helpful in cases, when you have several options to set a value, for example the
142    rotation. You can set the rotation with a quaternion, but you could also use three angles.
143    When saving the object, only one of both options has to be saved; this is, where this macro helps.
144*/
145#define XMLPortParamLoadOnly(classname, paramname, loadfunction, xmlelement, mode) \
146    static ExecutorMember<classname>* xmlcontainer##loadfunction##0##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
147    XMLPortParamGeneric(xmlcontainer##loadfunction##0, classname, classname, this, paramname, xmlcontainer##loadfunction##0##loadexecutor, 0, xmlelement, mode)
148/**
149    @brief This is the same as XMLPortParamTemplate, but for load-only attributes (see XMLPortParamLoadOnly).
150*/
151#define XMLPortParamLoadOnlyTemplate(classname, paramname, loadfunction, xmlelement, mode, ...) \
152    static ExecutorMember<classname>* xmlcontainer##loadfunction##0##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
153    XMLPortParamGeneric(xmlcontainer##loadfunction##0, classname, classname, this, paramname, xmlcontainer##loadfunction##0##loadexecutor, 0, xmlelement, mode)
154
155// ------------------
156// XMLPortParamExtern
157
158/**
159    @brief This is the same as XMLPortParam, but for attributes in an extern class.
160    @param classname The name of the class owning the object owning the attribute
161    @param externclass The name of the extern class (the objects class)
162    @param object The name of the object of the extern class (a member of the main class)
163    @param paramname The name of the attribute
164    @param loadfunction The function to set the attribute inside of the member object.
165    @param loadfunction The function to get the attribute from the member object
166
167    Sometimes you'll have a member object in your class, which has it's own load- and savefunctions.
168    With this macro, you can simply use them instead of writing your own functions.
169
170    @example
171    Your class is called SpaceShip and this class has an object (myPilot_) of class Pilot. Pilot has a name
172    and two functions, setName(name) and getName(). Now you want an attribute "pilotname" in your
173    SpaceShip class. Instead of writing wrapper functions, you can simply use the XMLPortParamExtern
174    macro:
175    > XMLPortParamExtern(SpaceShip, Pilot, myPilot_, "pilotname", setName, getName, xmlelement, mode);
176*/
177#define XMLPortParamExtern(classname, externclass, object, paramname, loadfunction, savefunction, xmlelement, mode) \
178    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&externclass::loadfunction), std::string( #externclass ) + "::" + #loadfunction); \
179    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&externclass::savefunction), std::string( #externclass ) + "::" + #savefunction); \
180    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, externclass, object, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode);
181/**
182    @brief This is the same as XMLPortParamTemplate, but for extern attributes (see XMLPortParamExtern).
183*/
184#define XMLPortParamExternTemplate(classname, externclass, object, paramname, loadfunction, savefunction, xmlelement, mode, ...) \
185    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<externclass, __VA_ARGS__ >(&externclass::loadfunction), std::string( #externclass ) + "::" + #loadfunction); \
186    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&externclass::savefunction), std::string( #externclass ) + "::" + #savefunction); \
187    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, externclass, object, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode);
188
189// -------------------
190// XMLPortParamGeneric
191
192/**
193    @brief This is the generic XMLPort param macro, which is used by all six specialized macros above.
194*/
195#define XMLPortParamGeneric(containername, classname, objectclass, object, paramname, loadexecutor, saveexecutor, xmlelement, mode) \
196    orxonox::XMLPortClassParamContainer<objectclass>* containername = (orxonox::XMLPortClassParamContainer<objectclass>*)(ClassIdentifier<classname>::getIdentifier()->getXMLPortParamContainer(paramname)); \
197    if (!containername) \
198    { \
199        containername = new orxonox::XMLPortClassParamContainer<objectclass>(std::string(paramname), ClassIdentifier<classname>::getIdentifier(), loadexecutor, saveexecutor); \
200        ClassIdentifier<classname>::getIdentifier()->addXMLPortParamContainer(paramname, containername); \
201    } \
202    containername->port((BaseObject*)this, object, xmlelement, mode)
203
204// --------------------
205// XMLPortObjectExtended
206
207/**
208    @brief Declares a possible sub-object that can be added in the XML file.
209    @param classname The name of the class that uses this macro
210    @param objectclass The baseclass of objects that can be added
211    @param sectionname The name of the subsection in the XML file that encloses the sub-objects ("" means no subsection)
212    @param loadfunction The function to add a new object to the class
213    @param loadfunction The function to get all added objects from the class
214    @param xmlelement The XMLElement (recieved through the XMLPort function)
215    @param mode The mode (load/save) (received through the XMLPort function)
216    @param bApplyLoaderMask If this is true, an added sub-object gets loaded only if it's class is included in the Loaders ClassTreeMask (this is usually false)
217    @param bLoadBefore If this is true, the sub-object gets loaded (through XMLPort) BEFORE it gets added to the main class (this is usually true)
218
219    bApplyLoaderMask is usually false for the following reason:
220    If the loaders mask says, for example, "load only SpaceShips" and you added weapons to the
221    SpaceShips, then the Weapons will still be loaded (which is most probably what you want).
222    Of course, if there are "standalone" weapons in the level, they wont be loaded.
223
224    If bLoadBefore is true, an added object already has all attributes set (like it's name). This is most
225    likely the best option, so this is usually true.
226
227    @note
228    The load- and savefunctions have to follow an exactly defined protocol.
229    Loadfunction:
230      The loadfunction gets a pointer to the object.
231      > void loadfunction(objectclass* pointer);
232
233    Savefunction:
234      The savefunction gets an index, starting with 0. For every returnvalue != 0, the savefunction
235      gets called again, but with index + 1. It's the functions responsibility to do something smart
236      with the index and to return 0 if all objects were returned.
237      > objectclass* savefunction(unsigned int index) const;
238
239      Possible implementation:
240        objectclass* savefunction(unsigned int index) const
241        {
242          if (index < number_of_added_objects_)
243            return my_added_objects[index];
244          else
245            return 0;
246        }
247
248    @example
249    Possible usage of the macro:
250    > XMLPortObject(SpaceShip, Weapon, "weapons", addWeapon, getWeapon, xmlelement, mode, false, true);
251
252    Now you can add weapons through the XML file:
253    <SpaceShip someattribute="..." ...>
254      <weapons>
255        <Weapon someattribute="..." ... />
256        <Weapon someattribute="..." ... />
257        <Weapon someattribute="..." ... />
258      </weapons>
259    </SpaceShip>
260
261    Note that "weapons" is the subsection. This allows you to add more types of sub-objects. In our example,
262    you could add pilots, blinking lights or other stuff. If you don't want a subsection, just use "" (an
263    empty string). Then you can add sub-objects directly into the mainclass.
264*/
265#define XMLPortObjectExtended(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, bApplyLoaderMask, bLoadBefore) \
266    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
267    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
268    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, bApplyLoaderMask, bLoadBefore)
269/**
270    @brief This is the same as XMLPortObjectExtended, but you can specify the loadfunction by adding the param types. See XMLPortParamTemplate for more details about the types.
271*/
272#define XMLPortObjectExtendedTemplate(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, bApplyLoaderMask, bLoadBefore, ...) \
273    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
274    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
275    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, bApplyLoaderMask, bLoadBefore)
276
277// -------------
278// XMLPortObject
279
280/**
281    @brief This is the same as XMLPortObjectExtended, but bApplyLoaderMask is false and bLoadBefore is true by default.
282*/
283#define XMLPortObject(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode) \
284    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
285    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
286    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, false, true)
287/**
288    @brief This is the same as XMLPortObject, but you can specify the loadfunction by adding the param types. See XMLPortParamTemplate for more details about the types.
289*/
290#define XMLPortObjectTemplate(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, ...) \
291    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
292    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
293    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, false, true)
294
295// --------------------
296// XMLPortObjectGeneric
297
298/**
299    @brief Generic XMLPortObject macro, that gets called by all other XMLPortObject macros above.
300*/
301#define XMLPortObjectGeneric(containername, classname, objectclass, sectionname, loadexecutor, saveexecutor, xmlelement, mode, bApplyLoaderMask, bLoadBefore) \
302    orxonox::XMLPortClassObjectContainer<classname, objectclass>* containername = (orxonox::XMLPortClassObjectContainer<classname, objectclass>*)(ClassIdentifier<classname>::getIdentifier()->getXMLPortObjectContainer(sectionname)); \
303    if (!containername) \
304    { \
305        containername = new orxonox::XMLPortClassObjectContainer<classname, objectclass>(std::string(sectionname), ClassIdentifier<classname>::getIdentifier(), loadexecutor, saveexecutor, bApplyLoaderMask, bLoadBefore); \
306        ClassIdentifier<classname>::getIdentifier()->addXMLPortObjectContainer(sectionname, containername); \
307    } \
308    containername->port(this, xmlelement, mode)
309
310
311namespace orxonox
312{
313    // ###############################
314    // ###  XMLPortParamContainer  ###
315    // ###############################
316    class _CoreExport XMLPortParamContainer
317    {
318    public:
319        enum ParseResult
320        {
321            PR_not_started,
322            PR_finished,
323            PR_waiting_for_default_values
324        };
325
326        public:
327            XMLPortParamContainer()
328                { this->parseResult_ = PR_not_started; }
329            virtual ~XMLPortParamContainer() {}
330
331            inline const std::string& getName() const
332                { return this->paramname_; }
333
334            virtual XMLPortParamContainer& description(const std::string description) = 0;
335            virtual const std::string& getDescription() = 0;
336
337            virtual XMLPortParamContainer& defaultValue(unsigned int index, const MultiType& param) = 0;
338            virtual XMLPortParamContainer& defaultValues(const MultiType& param1) = 0;
339            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2) = 0;
340            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3) = 0;
341            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4) = 0;
342            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5) = 0;
343
344        protected:
345            std::string paramname_;
346            ParseResult parseResult_;
347            Identifier* identifier_;
348            BaseObject* owner_;
349    };
350
351    template <class T>
352    class XMLPortClassParamContainer : public XMLPortParamContainer
353    {
354        struct ParseParams
355        {
356            T* object;
357            Element* xmlelement;
358            XMLPort::Mode mode;
359        };
360
361        public:
362            XMLPortClassParamContainer(const std::string paramname, Identifier* identifier, ExecutorMember<T>* loadexecutor, ExecutorMember<T>* saveexecutor)
363            {
364                this->paramname_ = paramname;
365                this->identifier_ = identifier;
366                this->loadexecutor_ = loadexecutor;
367                this->saveexecutor_ = saveexecutor;
368            }
369
370            XMLPortParamContainer& port(BaseObject* owner, T* object, Element& xmlelement, XMLPort::Mode mode)
371            {
372                this->owner_ = owner;
373                this->parseParams_.object = object;
374                this->parseParams_.xmlelement = &xmlelement;
375                this->parseParams_.mode = mode;
376
377                if (mode == XMLPort::LoadObject)
378                {
379                    try
380                    {
381                        std::string attribute = xmlelement.GetAttribute(this->paramname_);
382                        if ((attribute.size() > 0) || (this->loadexecutor_->allDefaultValuesSet()))
383                        {
384                            COUT(5) << this->owner_->getLoaderIndentation() << "Loading parameter " << this->paramname_ << " in " << this->identifier_->getName() << " (objectname " << this->owner_->getName() << ")." << std::endl << this->owner_->getLoaderIndentation();
385                            if (this->loadexecutor_->parse(object, attribute, ","))
386                                this->parseResult_ = PR_finished;
387                            else
388                                this->parseResult_ = PR_waiting_for_default_values;
389                        }
390                        else
391                            this->parseResult_ = PR_waiting_for_default_values;
392                    }
393                    catch (ticpp::Exception& ex)
394                    {
395                        COUT(1) << std::endl;
396                        COUT(1) << "An error occurred in XMLPort.h while loading attribute '" << this->paramname_ << "' of '" << this->identifier_->getName() << "' (objectname: " << this->owner_->getName() << ") in " << this->owner_->getFilename() << ":" << std::endl;
397                        COUT(1) << ex.what() << std::endl;
398                    }
399                }
400                else
401                {
402                    if (this->saveexecutor_)
403                    {
404//                        xmlelement.SetAttribute(this->paramname_, "...");
405                    }
406                }
407
408                return (*this);
409            }
410
411            XMLPortParamContainer& port(BaseObject* owner, const ParseParams& parseParams)
412            {
413                return this->port(owner, parseParams.object, *parseParams.xmlelement, parseParams.mode);
414            }
415
416            XMLPortParamContainer& portIfWaitingForDefaultValues(const ParseResult& result, const ParseParams& params)
417            {
418                if (result == PR_waiting_for_default_values)
419                    return this->port(this->owner_, params);
420                else
421                    return (*this);
422            }
423
424            virtual XMLPortParamContainer& description(const std::string description)
425                { this->loadexecutor_->setDescription(description); return (*this); }
426            virtual const std::string& getDescription()
427                { return this->loadexecutor_->getDescription(); }
428
429            virtual XMLPortParamContainer& defaultValue(unsigned int index, const MultiType& param)
430            {
431                if (!this->loadexecutor_->defaultValueSet(index))
432                    this->loadexecutor_->setDefaultValue(index, param);
433                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
434            }
435            virtual XMLPortParamContainer& defaultValues(const MultiType& param1)
436            {
437                if (!this->loadexecutor_->defaultValueSet(0))
438                    this->loadexecutor_->setDefaultValues(param1);
439                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
440            }
441            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2)
442            {
443                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)))
444                    this->loadexecutor_->setDefaultValues(param1, param2);
445                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
446            }
447            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3)
448            {
449                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)))
450                    this->loadexecutor_->setDefaultValues(param1, param2, param3);
451                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
452            }
453            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4)
454            {
455                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)) || (!this->loadexecutor_->defaultValueSet(3)))
456                    this->loadexecutor_->setDefaultValues(param1, param2, param3, param4);
457                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
458            }
459            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5)
460            {
461                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)) || (!this->loadexecutor_->defaultValueSet(3)) || (!this->loadexecutor_->defaultValueSet(4)))
462                    this->loadexecutor_->setDefaultValues(param1, param2, param3, param4, param5);
463                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
464            }
465
466        private:
467            ExecutorMember<T>* loadexecutor_;
468            ExecutorMember<T>* saveexecutor_;
469            ParseParams parseParams_;
470    };
471
472
473    // ################################
474    // ###  XMLPortObjectContainer  ###
475    // ################################
476    class _CoreExport XMLPortObjectContainer
477    {
478        public:
479            XMLPortObjectContainer()
480                { this->bApplyLoaderMask_ = false; }
481            virtual ~XMLPortObjectContainer() {}
482
483            inline const std::string& getName() const
484                { return this->sectionname_; }
485
486            virtual XMLPortObjectContainer& description(const std::string description) = 0;
487            virtual const std::string& getDescription() = 0;
488
489            bool identifierIsIncludedInLoaderMask(const Identifier* identifier);
490
491        protected:
492            std::string sectionname_;
493            bool bApplyLoaderMask_;
494            bool bLoadBefore_;
495            Identifier* identifier_;
496    };
497
498    template <class T, class O>
499    class XMLPortClassObjectContainer : public XMLPortObjectContainer
500    {
501        public:
502            XMLPortClassObjectContainer(const std::string sectionname, Identifier* identifier, ExecutorMember<T>* loadexecutor, ExecutorMember<T>* saveexecutor, bool bApplyLoaderMask, bool bLoadBefore)
503            {
504                this->sectionname_ = sectionname;
505                this->identifier_ = identifier;
506                this->loadexecutor_ = loadexecutor;
507                this->saveexecutor_ = saveexecutor;
508                this->bApplyLoaderMask_ = bApplyLoaderMask;
509                this->bLoadBefore_ = bLoadBefore;
510            }
511
512            XMLPortObjectContainer& port(T* object, Element& xmlelement, XMLPort::Mode mode)
513            {
514                if (mode == XMLPort::LoadObject)
515                {
516                    try
517                    {
518                        Element* xmlsubelement;
519                        if ((this->sectionname_ != "") && (this->sectionname_.size() > 0))
520                            xmlsubelement = xmlelement.FirstChildElement(this->sectionname_, false);
521                        else
522                            xmlsubelement = &xmlelement;
523
524                        if (xmlsubelement)
525                        {
526                            for (ticpp::Iterator<ticpp::Element> child = xmlsubelement->FirstChildElement(false); child != child.end(); child++)
527                            {
528                                Identifier* identifier = ClassByString(child->Value());
529                                if (identifier)
530                                {
531                                    if (identifier->isA(Class(O)))
532                                    {
533                                        if (identifier->isLoadable())
534                                        {
535                                            if (this->identifierIsIncludedInLoaderMask(identifier))
536                                            {
537                                                COUT(4) << ((BaseObject*)object)->getLoaderIndentation() << "fabricating " << child->Value() << "..." << std::endl;
538
539                                                BaseObject* newObject = identifier->fabricate((BaseObject*)object);
540                                                assert(newObject);
541                                                newObject->setLoaderIndentation(((BaseObject*)object)->getLoaderIndentation() + "  ");
542
543                                                O* castedObject = dynamic_cast<O*>(newObject);
544                                                assert(castedObject);
545
546                                                if (this->bLoadBefore_)
547                                                {
548                                                    newObject->XMLPort(*child, XMLPort::LoadObject);
549                                                    COUT(4) << ((BaseObject*)object)->getLoaderIndentation() << "assigning " << child->Value() << " (objectname " << newObject->getName() << ") to " << this->identifier_->getName() << " (objectname " << ((BaseObject*)object)->getName() << ")" << std::endl;
550                                                }
551                                                else
552                                                {
553                                                    COUT(4) << ((BaseObject*)object)->getLoaderIndentation() << "assigning " << child->Value() << " (object not yet loaded) to " << this->identifier_->getName() << " (objectname " << ((BaseObject*)object)->getName() << ")" << std::endl;
554                                                }
555
556                                                COUT(5) << ((BaseObject*)object)->getLoaderIndentation();
557                                                (*this->loadexecutor_)(object, castedObject);
558
559                                                if (!this->bLoadBefore_)
560                                                    newObject->XMLPort(*child, XMLPort::LoadObject);
561
562                                                COUT(5) << ((BaseObject*)object)->getLoaderIndentation() << "...fabricated " << child->Value() << " (objectname " << newObject->getName() << ")." << std::endl;
563                                            }
564                                        }
565                                        else
566                                        {
567                                            COUT(2) << ((BaseObject*)object)->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not loadable." << std::endl;
568                                        }
569                                    }
570                                    else
571                                    {
572                                        COUT(2) << ((BaseObject*)object)->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a '" << Class(O)->getName() << "'." << std::endl;
573                                    }
574                                }
575                                else
576                                {
577                                    if (this->sectionname_ != "")
578                                    {
579                                        COUT(2) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a valid classname." << std::endl;
580                                    }
581                                    else
582                                    {
583                                        // It's probably just another subsection
584                                    }
585                                }
586                            }
587                        }
588                    }
589                    catch (ticpp::Exception& ex)
590                    {
591                        COUT(1) << std::endl;
592                        COUT(1) << "An error occurred in XMLPort.h while loading a '" << Class(O)->getName() << "' in '" << this->sectionname_ << "' of '" << this->identifier_->getName() << "' (objectname: " << ((BaseObject*)object)->getName() << ") in " << object->getFilename() << ":" << std::endl;
593                        COUT(1) << ex.what() << std::endl;
594                    }
595                }
596                else
597                {
598                }
599
600                return (*this);
601            }
602
603            virtual XMLPortObjectContainer& description(const std::string description)
604                { this->loadexecutor_->setDescription(description); return (*this); }
605            virtual const std::string& getDescription()
606                { return this->loadexecutor_->getDescription(); }
607
608        private:
609            ExecutorMember<T>* loadexecutor_;
610            ExecutorMember<T>* saveexecutor_;
611    };
612
613
614    // ####################################
615    // ###  XMLPortVariableHelperClass  ###
616    // ####################################
617    /**
618    @brief
619        Helper class to load and save simple variables with XMLPort.
620
621        getLoader and getSaver were necessary to get the type T with
622        the help of template function type deduction (const T& is unused).
623        These functions return the adress of save<T> or load<T>.
624    */
625    class XMLPortVariableHelperClass
626    {
627        public:
628            XMLPortVariableHelperClass(void* var)
629                : variable_(var)
630                { }
631
632            template <class T>
633            void load(const T& value)
634                { *((T*)this->variable_) = value; }
635
636            template <class T>
637            const T& save()
638                { return *((T*)this->variable_); }
639
640            template <class T>
641            static void (XMLPortVariableHelperClass::*getLoader(const T& var))(const T& value)
642                { return &XMLPortVariableHelperClass::load<T>; }
643
644            template <class T>
645            static const T& (XMLPortVariableHelperClass::*getSaver(const T& var))()
646                { return &XMLPortVariableHelperClass::save<T>; }
647
648        private:
649            void* variable_;
650    };
651}
652
653#endif /* _XMLPort_H__ */
Note: See TracBrowser for help on using the repository browser.