Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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