Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pch/src/core/XMLPort.h @ 3149

Last change on this file since 3149 was 3149, checked in by rgrieder, 15 years ago

Extracted OrxAssert from Exception.h to OrxAssert.h since it doesn't really have anything to do with exceptions.

  • Property svn:eol-style set to native
File size: 39.5 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 <tinyxml/ticpp.h>
47#include "util/Debug.h"
48#include "util/Exception.h"
49#include "util/OrxAssert.h"
50#include "util/MultiType.h"
51#include "XMLIncludes.h"
52#include "Executor.h"
53#include "CoreIncludes.h"
54#include "BaseObject.h"
55
56// ------------
57// XMLPortParam
58
59/**
60    @brief Declares an XML attribute with a name, which will be set through load- and savefunctions.
61    @param classname The name of the class owning this param
62    @param paramname The name of the attribute
63    @param loadfunction A function to set the param in the object with a given value (~a set-function)
64    @param savefunction A function to get the value of the param from the object (~a get-function)
65    @param xmlelement The XMLElement, you get this from the XMLPort function
66    @param mode The mode (load or save), you get this from the XMLPort function
67
68    In the XML file, a param or attribute will be set like this:
69    <classname paramname="value" />
70
71    The macro will then call loadfunction(value) to set the given value (or call savefunction() to
72    write an existing value to an XML file).
73*/
74#define XMLPortParam(classname, paramname, loadfunction, savefunction, xmlelement, mode) \
75    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
76    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
77    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, classname, this, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode)
78
79/**
80    @brief Declares an XML attribute with a name, which will be set through a variable.
81    @param classname The name of the class owning this param
82    @param paramname The name of the attribute
83    @param variable Name of the variable used to save and load the value
84    @param xmlelement The XMLElement, you get this from the XMLPort function
85    @param mode The mode (load or save), you get this from the XMLPort function
86
87    In the XML file, a param or attribute will be set like this:
88    <classname paramname="value" />
89
90    The macro will then store "value" in the variable or read it when saving.
91*/
92#define XMLPortParamVariable(classname, paramname, variable, xmlelement, mode) \
93    XMLPortVariableHelperClass xmlcontainer##variable##dummy((void*)&variable); \
94    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")); \
95    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" )); \
96    XMLPortParamGeneric(xmlcontainer##variable, classname, orxonox::XMLPortVariableHelperClass, &xmlcontainer##variable##dummy, paramname, xmlcontainer##variable##loadexecutor, xmlcontainer##variable##saveexecutor, xmlelement, mode)
97
98/**
99    @brief This is the same as XMLPortParam, but you can set the template arguments needed to store the loadfunction.
100
101    Sometimes the name of the loadfunction is ambiguous (example: setPosition(Vector3) or
102    setPosition(float, float, float)). In this case, you can choose the right function by
103    telling the types of the functionparams. In our example, this would be either
104    > XMLPortParamTemplate(classname, paramname, loadfunction, savefunction, xmlelement, mode, Vector3);
105    or
106    > XMLPortParamTemplate(classname, paramname, loadfunction, savefunction, xmlelement, mode, float, float, float);
107    You don't have to use this, if there exist only one function with the given name.
108*/
109#define XMLPortParamTemplate(classname, paramname, loadfunction, savefunction, xmlelement, mode, ...) \
110    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
111    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
112    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, classname, this, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode)
113
114// --------------------
115// XMLPortParamLoadOnly
116
117/**
118    @brief Declares an XML attribute with a name, which can be set through a loadfunction.
119
120    This is the same as XMLPortParam, but you don't need a savefunction (get-function). Therefore,
121    this param won't be saved in an XML file, but you can add the attribute manually an it will be
122    loaded.
123
124    This might be helpful in cases, when you have several options to set a value, for example the
125    rotation. You can set the rotation with a quaternion, but you could also use three angles.
126    When saving the object, only one of both options has to be saved; this is, where this macro helps.
127*/
128#define XMLPortParamLoadOnly(classname, paramname, loadfunction, xmlelement, mode) \
129    static ExecutorMember<classname>* xmlcontainer##loadfunction##0##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
130    XMLPortParamGeneric(xmlcontainer##loadfunction##0, classname, classname, this, paramname, xmlcontainer##loadfunction##0##loadexecutor, 0, xmlelement, mode)
131/**
132    @brief This is the same as XMLPortParamTemplate, but for load-only attributes (see XMLPortParamLoadOnly).
133*/
134#define XMLPortParamLoadOnlyTemplate(classname, paramname, loadfunction, xmlelement, mode, ...) \
135    static ExecutorMember<classname>* xmlcontainer##loadfunction##0##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
136    XMLPortParamGeneric(xmlcontainer##loadfunction##0, classname, classname, this, paramname, xmlcontainer##loadfunction##0##loadexecutor, 0, xmlelement, mode)
137
138// ------------------
139// XMLPortParamExtern
140
141/**
142    @brief This is the same as XMLPortParam, but for attributes in an extern class.
143    @param classname The name of the class owning the object owning the attribute
144    @param externclass The name of the extern class (the objects class)
145    @param object The name of the object of the extern class (a member of the main class)
146    @param paramname The name of the attribute
147    @param loadfunction The function to set the attribute inside of the member object.
148    @param loadfunction The function to get the attribute from the member object
149
150    Sometimes you'll have a member object in your class, which has it's own load- and savefunctions.
151    With this macro, you can simply use them instead of writing your own functions.
152
153    @example
154    Your class is called SpaceShip and this class has an object (myPilot_) of class Pilot. Pilot has a name
155    and two functions, setName(name) and getName(). Now you want an attribute "pilotname" in your
156    SpaceShip class. Instead of writing wrapper functions, you can simply use the XMLPortParamExtern
157    macro:
158    > XMLPortParamExtern(SpaceShip, Pilot, myPilot_, "pilotname", setName, getName, xmlelement, mode);
159*/
160#define XMLPortParamExtern(classname, externclass, object, paramname, loadfunction, savefunction, xmlelement, mode) \
161    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&externclass::loadfunction), std::string( #externclass ) + "::" + #loadfunction); \
162    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&externclass::savefunction), std::string( #externclass ) + "::" + #savefunction); \
163    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, externclass, object, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode);
164/**
165    @brief This is the same as XMLPortParamTemplate, but for extern attributes (see XMLPortParamExtern).
166*/
167#define XMLPortParamExternTemplate(classname, externclass, object, paramname, loadfunction, savefunction, xmlelement, mode, ...) \
168    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<externclass, __VA_ARGS__ >(&externclass::loadfunction), std::string( #externclass ) + "::" + #loadfunction); \
169    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&externclass::savefunction), std::string( #externclass ) + "::" + #savefunction); \
170    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, externclass, object, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode);
171
172// -------------------
173// XMLPortParamGeneric
174
175/**
176    @brief This is the generic XMLPort param macro, which is used by all six specialized macros above.
177*/
178#define XMLPortParamGeneric(containername, classname, objectclass, object, paramname, loadexecutor, saveexecutor, xmlelement, mode) \
179    orxonox::XMLPortClassParamContainer<objectclass>* containername = (orxonox::XMLPortClassParamContainer<objectclass>*)(ClassIdentifier<classname>::getIdentifier()->getXMLPortParamContainer(paramname)); \
180    if (!containername) \
181    { \
182        containername = new orxonox::XMLPortClassParamContainer<objectclass>(std::string(paramname), ClassIdentifier<classname>::getIdentifier(), loadexecutor, saveexecutor); \
183        ClassIdentifier<classname>::getIdentifier()->addXMLPortParamContainer(paramname, containername); \
184    } \
185    containername->port(static_cast<BaseObject*>(this), object, xmlelement, mode)
186
187// --------------------
188// XMLPortObjectExtended
189
190/**
191    @brief Declares a possible sub-object that can be added in the XML file.
192    @param classname The name of the class that uses this macro
193    @param objectclass The baseclass of objects that can be added
194    @param sectionname The name of the subsection in the XML file that encloses the sub-objects ("" means no subsection)
195    @param loadfunction The function to add a new object to the class
196    @param loadfunction The function to get all added objects from the class
197    @param xmlelement The XMLElement (recieved through the XMLPort function)
198    @param mode The mode (load/save) (received through the XMLPort function)
199    @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)
200    @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)
201
202    bApplyLoaderMask is usually false for the following reason:
203    If the loaders mask says, for example, "load only SpaceShips" and you added weapons to the
204    SpaceShips, then the Weapons will still be loaded (which is most probably what you want).
205    Of course, if there are "standalone" weapons in the level, they wont be loaded.
206
207    If bLoadBefore is true, an added object already has all attributes set (like it's name). This is most
208    likely the best option, so this is usually true.
209
210    @note
211    The load- and savefunctions have to follow an exactly defined protocol.
212    Loadfunction:
213      The loadfunction gets a pointer to the object.
214      > void loadfunction(objectclass* pointer);
215
216    Savefunction:
217      The savefunction gets an index, starting with 0. For every returnvalue != 0, the savefunction
218      gets called again, but with index + 1. It's the functions responsibility to do something smart
219      with the index and to return 0 if all objects were returned.
220      > objectclass* savefunction(unsigned int index) const;
221
222      Possible implementation:
223        objectclass* savefunction(unsigned int index) const
224        {
225          if (index < number_of_added_objects_)
226            return my_added_objects[index];
227          else
228            return 0;
229        }
230
231    @example
232    Possible usage of the macro:
233    > XMLPortObject(SpaceShip, Weapon, "weapons", addWeapon, getWeapon, xmlelement, mode, false, true);
234
235    Now you can add weapons through the XML file:
236    <SpaceShip someattribute="..." ...>
237      <weapons>
238        <Weapon someattribute="..." ... />
239        <Weapon someattribute="..." ... />
240        <Weapon someattribute="..." ... />
241      </weapons>
242    </SpaceShip>
243
244    Note that "weapons" is the subsection. This allows you to add more types of sub-objects. In our example,
245    you could add pilots, blinking lights or other stuff. If you don't want a subsection, just use "" (an
246    empty string). Then you can add sub-objects directly into the mainclass.
247*/
248#define XMLPortObjectExtended(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, bApplyLoaderMask, bLoadBefore) \
249    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
250    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
251    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, bApplyLoaderMask, bLoadBefore)
252/**
253    @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.
254*/
255#define XMLPortObjectExtendedTemplate(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, bApplyLoaderMask, bLoadBefore, ...) \
256    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
257    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
258    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, bApplyLoaderMask, bLoadBefore)
259
260// -------------
261// XMLPortObject
262
263/**
264    @brief This is the same as XMLPortObjectExtended, but bApplyLoaderMask is false and bLoadBefore is true by default.
265*/
266#define XMLPortObject(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode) \
267    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
268    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
269    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, false, true)
270/**
271    @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.
272*/
273#define XMLPortObjectTemplate(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, ...) \
274    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
275    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
276    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, false, true)
277
278// --------------------
279// XMLPortObjectGeneric
280
281/**
282    @brief Generic XMLPortObject macro, that gets called by all other XMLPortObject macros above.
283*/
284#define XMLPortObjectGeneric(containername, classname, objectclass, sectionname, loadexecutor, saveexecutor, xmlelement, mode, bApplyLoaderMask, bLoadBefore) \
285    orxonox::XMLPortClassObjectContainer<classname, objectclass>* containername = (orxonox::XMLPortClassObjectContainer<classname, objectclass>*)(ClassIdentifier<classname>::getIdentifier()->getXMLPortObjectContainer(sectionname)); \
286    if (!containername) \
287    { \
288        containername = new orxonox::XMLPortClassObjectContainer<classname, objectclass>(std::string(sectionname), ClassIdentifier<classname>::getIdentifier(), loadexecutor, saveexecutor, bApplyLoaderMask, bLoadBefore); \
289        ClassIdentifier<classname>::getIdentifier()->addXMLPortObjectContainer(sectionname, containername); \
290    } \
291    containername->port(this, xmlelement, mode)
292
293
294namespace orxonox
295{
296    // ###############################
297    // ###  XMLPortParamContainer  ###
298    // ###############################
299    class _CoreExport XMLPortParamContainer
300    {
301    public:
302        enum ParseResult
303        {
304            PR_not_started,
305            PR_finished,
306            PR_waiting_for_default_values
307        };
308
309        public:
310            XMLPortParamContainer()
311                { this->parseResult_ = PR_not_started; }
312            virtual ~XMLPortParamContainer() {}
313
314            inline const std::string& getName() const
315                { return this->paramname_; }
316
317            virtual XMLPortParamContainer& description(const std::string description) = 0;
318            virtual const std::string& getDescription() = 0;
319
320            virtual XMLPortParamContainer& defaultValue(unsigned int index, const MultiType& param) = 0;
321            virtual XMLPortParamContainer& defaultValues(const MultiType& param1) = 0;
322            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2) = 0;
323            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3) = 0;
324            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4) = 0;
325            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5) = 0;
326
327        protected:
328            std::string paramname_;
329            ParseResult parseResult_;
330            Identifier* identifier_;
331            BaseObject* owner_;
332    };
333
334    template <class T>
335    class XMLPortClassParamContainer : public XMLPortParamContainer
336    {
337        struct ParseParams
338        {
339            T* object;
340            Element* xmlelement;
341            XMLPort::Mode mode;
342        };
343
344        public:
345            XMLPortClassParamContainer(const std::string paramname, Identifier* identifier, ExecutorMember<T>* loadexecutor, ExecutorMember<T>* saveexecutor)
346            {
347                this->paramname_ = paramname;
348                this->identifier_ = identifier;
349                this->loadexecutor_ = loadexecutor;
350                this->saveexecutor_ = saveexecutor;
351            }
352
353            ~XMLPortClassParamContainer()
354            {
355                assert(this->loadexecutor_);
356                delete this->loadexecutor_;
357                if (this->saveexecutor_)
358                    delete this->saveexecutor_;
359            }
360
361            XMLPortParamContainer& port(BaseObject* owner, T* object, Element& xmlelement, XMLPort::Mode mode)
362            {
363                OrxAssert(owner, "XMLPortParamContainer must have a BaseObject as owner.");
364                this->owner_ = owner;
365                this->parseParams_.object = object;
366                this->parseParams_.xmlelement = &xmlelement;
367                this->parseParams_.mode = mode;
368
369                if ((mode == XMLPort::LoadObject) || (mode == XMLPort::ExpandObject))
370                {
371                    try
372                    {
373                        if (this->owner_->lastLoadedXMLElement_ != &xmlelement)
374                        {
375                            this->owner_->xmlAttributes_.clear();
376                            // Iterate through the attributes manually in order to make them case insensitive
377                            Attribute* attribute = xmlelement.FirstAttribute(false);
378                            while (attribute != 0)
379                            {
380                                this->owner_->xmlAttributes_[getLowercase(attribute->Name())] = attribute->Value();
381                                attribute = attribute->Next(false);
382                            }
383                            this->owner_->lastLoadedXMLElement_ = &xmlelement;
384                        }
385                        std::map<std::string, std::string>::const_iterator it = this->owner_->xmlAttributes_.find(getLowercase(this->paramname_));
386                        std::string attributeValue("");
387                        if (it != this->owner_->xmlAttributes_.end())
388                            attributeValue = it->second;
389
390                        // TODO: Checking the iterator would be better since then we can have strings with value "" as well.
391                        //       Unfortunately this does not seem to work with the Executor parser yet.
392                        if ((!attributeValue.empty()) || ((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, attributeValue, ",") || (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) << object->getLoaderIndentation() << "fabricating " << child->Value() << "..." << std::endl;
560
561                                                    BaseObject* newObject = identifier->fabricate((BaseObject*)object);
562                                                    assert(newObject);
563                                                    newObject->setLoaderIndentation(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) << 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) << object->getLoaderIndentation() << "assigning " << child->Value() << " (object not yet loaded) to " << this->identifier_->getName() << " (objectname " << ((BaseObject*)object)->getName() << ")" << std::endl;
576                                                    }
577
578                                                    COUT(5) << object->getLoaderIndentation();
579                                                    (*this->loadexecutor_)(object, castedObject);
580
581                                                    if (!this->bLoadBefore_)
582                                                        newObject->XMLPort(*child, XMLPort::LoadObject);
583
584                                                    COUT(5) << 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) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not loadable." << std::endl;
605                                        }
606                                    }
607                                    else
608                                    {
609                                        COUT(2) << 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: " << 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.