Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy/src/core/XMLPort.h @ 2082

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