Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/core/XMLPort.h @ 2485

Last change on this file since 2485 was 2485, checked in by landauf, 15 years ago

Merged objecthierarchy2 into presentation branch

Couln't merge 2 lines in Gamestate.cc and a whole block of code in GSDedicated.cc (it seems like oli implemented in both branches something like a network-tick-limiter but with different approaches)

Not yet tested in network mode and with bots
The SpaceShips movement is also not yet fully adopted to the new physics (see Engine class)

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