Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy2/src/core/XMLPort.h @ 2639

Last change on this file since 2639 was 2344, checked in by rgrieder, 16 years ago

Completed destruction of static elements like XMLPort, Identifier, etc.
Of initially about 250 memory leaks (not in the actual meaning but the memory was never freed anyway) only 1 remains in TinyCpp.

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