407 lines
12 KiB
C++
Executable File
407 lines
12 KiB
C++
Executable File
/**
|
||
* @RDE_HEADER@
|
||
* Construction of MapObjects
|
||
* $Id$
|
||
* $HeadURL$
|
||
* $Author$
|
||
*/
|
||
|
||
#pragma once
|
||
|
||
|
||
// Own
|
||
#include "generic_object_factory.h"
|
||
#include "object_container.h"
|
||
#include "abstract_map_object.h"
|
||
#include "situation_map_utils.h"
|
||
#include <Common/ref_pointer.h>
|
||
#include <situation_map_export.h>
|
||
#include <Common/situation_map_logging.h>
|
||
|
||
|
||
// Qt
|
||
#include <QMap>
|
||
|
||
#include <typeindex>
|
||
|
||
//----------------------------------------------------------------------------
|
||
namespace SituationMap
|
||
{
|
||
|
||
// forward
|
||
class Map;
|
||
|
||
|
||
using FactoryMapKey = std::type_index;
|
||
using FactoryMapData = QSharedPointer<GenericObjectFactoryBase>;
|
||
using FactoryMap = QMap<FactoryMapKey, FactoryMapData>;
|
||
|
||
|
||
/**
|
||
* @brief The MapSingleton struct maps between
|
||
* INTERFACE (type_index) and GenericObjectFactory
|
||
* It´s a singleton. Therefore this map has to be set only once per process until it is cleared.
|
||
*/
|
||
struct SITUATIONMAP_EXPORT MapSingleton
|
||
{
|
||
static FactoryMap &getFactoryMap();
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief The ObjectFactory class is basically responsible for creation of all objects of type AbstractMapObject.
|
||
* The complete range of tasks includes:
|
||
* - creates objects of type AbstractMapObject and deriving classes
|
||
* - initialize (call init() ofAbstractMapObject) and
|
||
* - store them (within ObjectContainer)
|
||
* - stores an ObjectContainer (with its IdGenerator)
|
||
*
|
||
* <b>Example:
|
||
*
|
||
* \code
|
||
// Pre-condition :
|
||
// Initialize objectFactory:
|
||
SituationMap::ObjectFactory::registerMe(typeid(SituationMap::Participant),
|
||
new SituationMap::GenericObjectFactory<SituationMap::ParticipantImpl>() );
|
||
// : Pre-condition
|
||
|
||
...
|
||
|
||
SituationMap::ObjectFactory& objFac = d->m_map->objectFactory();
|
||
|
||
// use an LOGICAL layer (not basemap)
|
||
QString layername("ParticipantLayerName");
|
||
|
||
SituationMap::RefPointer<SituationMap::Participant> objPtr;
|
||
objPtr = objFac.create<SituationMap::Participant>("ParticipantLayerName", // use an LOGICAL layer (not basemap)
|
||
"ParticipantId1" // debugInfo (may contain SimId)
|
||
);
|
||
* \endcode
|
||
*
|
||
* \sa Map
|
||
*/
|
||
class SITUATIONMAP_EXPORT ObjectFactory
|
||
{
|
||
public:
|
||
/*! \name Construction, Destruction */
|
||
//@{
|
||
/**
|
||
* @brief Contructor.
|
||
* @param map to be used..
|
||
*/
|
||
explicit ObjectFactory(Map *map)
|
||
: m_logger(getLogger("ObjectFactory"))
|
||
, m_map(map) {}
|
||
virtual ~ObjectFactory() = default; ///< Destructor
|
||
|
||
ObjectFactory(const ObjectFactory &other) = delete;
|
||
ObjectFactory &operator=(ObjectFactory &other) = delete;
|
||
|
||
/**
|
||
* @brief Set the ObjectContainer to be used.
|
||
* @param objectContainer to be used.
|
||
*/
|
||
void setObjectContainer(const QSharedPointer<ObjectContainer> &objectContainer);
|
||
//@}
|
||
|
||
/**
|
||
* @brief Translate uniqueMapId to native AbstractMapObject.
|
||
* @param uniqueId to get.
|
||
* @return AbstractMapObject if found, otherwise null.
|
||
*/
|
||
AbstractMapObject *idToMapObject(const UniqueMapId &uniqueId) const;
|
||
|
||
Map* map() { return m_map; }
|
||
|
||
|
||
protected:
|
||
/**
|
||
* @brief Initialize MapObject.
|
||
* @param obj MapObject to be initialized.
|
||
* @param map Map to which the mapObject belongs to.
|
||
* @param logicalLayerName (logical) layer on which the object should be created.
|
||
* @return True on success; otherwise false.
|
||
*/
|
||
bool initMapObject(AbstractMapObject *obj, Map *map, UniqueMapId uid, const QString &logicalLayerName);
|
||
|
||
friend class MapImpl; // to support MapImpl::doClickMapObject
|
||
|
||
/**
|
||
* @brief Translate type_index of
|
||
* the interface class to the corresponding type_index of implementation class.
|
||
* @param interface_IN Type to be translated.
|
||
* @param bOk true is found, otherwise false.
|
||
* @return requested type_index of implementation class.
|
||
*/
|
||
std::type_index interfaceToImplementation(const std::type_index &interface_IN, bool *bOk = nullptr);
|
||
|
||
public:
|
||
|
||
//----------------------------------------------------------------------------
|
||
// create by (interface) type
|
||
//----------------------------------------------------------------------------
|
||
|
||
/*! \name Create */
|
||
//@{
|
||
|
||
/**
|
||
* @brief Create MapObject of required type.
|
||
* @param uniqueMapId Define the uniqueId of MapObject, be careful to use a valid and unused id
|
||
* @param logicalLayerName (logical) layer on which the object should be created.
|
||
* @param debugInfo Set debugInfo
|
||
* @return MapObject of required type on success; otherwise null.
|
||
*/
|
||
template<typename INTERFACE_TYPE>
|
||
RefPointer<INTERFACE_TYPE> create(const UniqueMapId &uniqueMapId,
|
||
const QString &logicalLayerName, // external: via type
|
||
const QString &debugInfo = QString())
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " create requested for ..."
|
||
<< ", debugInfo='" << debugInfo << "'"
|
||
<< ", logicalLayerName='" << logicalLayerName << "'";
|
||
|
||
if (!isMapReady())
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " create failed"
|
||
<< ", map not ready yet"
|
||
<< ", debugInfo='" << debugInfo << "'";
|
||
return RefPointer<INTERFACE_TYPE>();
|
||
}
|
||
|
||
|
||
if (logicalLayerName.isEmpty())
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " create failed"
|
||
<< ", logicalLayerName is empty"
|
||
<< ", debugInfo='" << debugInfo << "'";
|
||
return RefPointer<INTERFACE_TYPE>();
|
||
}
|
||
|
||
|
||
std::type_index key(typeid(INTERFACE_TYPE));
|
||
const QString &name = QString::fromLatin1(key.name());
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " create requested for ... name='" << name << "'"
|
||
<< ", debugInfo='" << debugInfo << "'";
|
||
|
||
if (MapSingleton::getFactoryMap().contains(key))
|
||
{
|
||
RefPointer<INTERFACE_TYPE> obj(MapSingleton::getFactoryMap().value(key)->makeObj(debugInfo));
|
||
if (obj.valid() && initMapObject(obj.get(), m_map, uniqueMapId, logicalLayerName))
|
||
{
|
||
return obj; // the caller will receive the requested type :-)
|
||
}
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " init failed, name='" << name << "'";
|
||
obj->removeMySelf(); // cleanup
|
||
return RefPointer<INTERFACE_TYPE>();
|
||
}
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " create failed, name= '" << name << "'"
|
||
<< ", factoryMap.size() = " << MapSingleton::getFactoryMap().count();
|
||
return RefPointer<INTERFACE_TYPE>();
|
||
}
|
||
|
||
/**
|
||
* @brief Create MapObject of required type.
|
||
* @param logicalLayerName (logical) layer on which the object should be created.
|
||
* @param debugInfo Set debugInfo
|
||
* @return MapObject of required type on success; otherwise null.
|
||
*/
|
||
template<typename INTERFACE_TYPE>
|
||
RefPointer<INTERFACE_TYPE> create(const QString &logicalLayerName, // external: via type
|
||
const QString &debugInfo = QString())
|
||
{
|
||
return create<INTERFACE_TYPE>(SituationMap::INVALID_MAP_ID, logicalLayerName, debugInfo);
|
||
}
|
||
|
||
//@}
|
||
|
||
|
||
/*! \name Count */
|
||
//@{
|
||
/**
|
||
* @brief Number of objects.
|
||
* @return Current number of objects.
|
||
*/
|
||
qint32 count() const;
|
||
//@}
|
||
|
||
/*! \name Check */
|
||
//@{
|
||
/**
|
||
* @brief Check uniqueMapId.
|
||
* @param uniqueMapId to be checked.
|
||
* @return Returns true if uniqueId is valid; otherwise returns false.
|
||
* @note Prefer SituationMap::isUniqueMapIdValid() due to runtime aspects.
|
||
*/
|
||
static bool isUniqueIdValid(const UniqueMapId &uniqueMapId);
|
||
|
||
|
||
/**
|
||
* @brief Check the existence <B>not</B> regarding the type.
|
||
* @param uniqueId to lookup.
|
||
* @return Returns true if container contains an occurrence; otherwise returns false.
|
||
*/
|
||
bool contains(const UniqueMapId &uniqueMapId) const;
|
||
|
||
|
||
/**
|
||
* @brief Check the existence <B>regarding</B> the type.
|
||
* @param uniqueMapId to lookup.
|
||
* @return Returns true if container contains an occurrence; otherwise returns false.
|
||
*/
|
||
template<typename INTERFACE_TYPE>
|
||
bool contains(const UniqueMapId &uniqueMapId)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " contains requested for uniqueMapId=" << uniqueMapId;
|
||
|
||
bool containsId = contains(uniqueMapId);
|
||
|
||
if (containsId)
|
||
{
|
||
// 1 typeid Interface to typeid Impl:
|
||
bool bOk = false;
|
||
std::type_index keyRequestedImpl = interfaceToImplementation(typeid(INTERFACE_TYPE), &bOk);
|
||
if (bOk)
|
||
{
|
||
// 2. retrieve out of internal container:
|
||
AbstractMapObject *mapObj = idToMapObject(uniqueMapId);
|
||
|
||
if (!mapObj)
|
||
return false;
|
||
|
||
// 3. compare retrieved objectTYPE with requested (IMPL)TYPE:
|
||
// std::type_index(typeid(*baseClass)) == std::type_index(typeid(*subClass))
|
||
containsId = std::type_index(typeid(*mapObj)) == keyRequestedImpl;
|
||
}
|
||
else
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " contains failed, name= '" << typeid(INTERFACE_TYPE).name() << "'"
|
||
<< " factoryMap.size() = " << MapSingleton::getFactoryMap().count();
|
||
}
|
||
}
|
||
return containsId;
|
||
|
||
} // ObjectFactory::contains
|
||
//@}
|
||
|
||
|
||
/*! \name Access */
|
||
//@{
|
||
|
||
/**
|
||
* @brief Get all UniqueIds.
|
||
* @return All UniqueIds.
|
||
*/
|
||
QList<UniqueMapId> getAllKeys() const;
|
||
|
||
/**
|
||
* @brief Get all Objects.
|
||
* @return Container with all objects.
|
||
*/
|
||
QList < RefPointer<AbstractMapObject> > getAllObjects() const;
|
||
|
||
|
||
/**
|
||
* @brief Get access the object.
|
||
* @param uniqueId to lookup.
|
||
* @return Pointer to AbstractMapObject (Base class).
|
||
*/
|
||
RefPointer<AbstractMapObject> get(const UniqueMapId &uniqueMapId) const;
|
||
|
||
|
||
/**
|
||
* @brief Get access to object <B>regarding</B> the type.
|
||
* @param uniqueId to lookup.
|
||
* @return Pointer to object (adaquate type).
|
||
*/
|
||
template<typename INTERFACE_TYPE>
|
||
RefPointer<INTERFACE_TYPE> get(const UniqueMapId &uniqueMapId) const
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " get requested for uniqueMapId=" << uniqueMapId;
|
||
|
||
// lookup in internal container:
|
||
RefPointer<AbstractMapObject> mapObj = get(uniqueMapId);
|
||
|
||
return RefPointer<INTERFACE_TYPE>(mapObj); // implicit dynamic_cast
|
||
}
|
||
|
||
/*! \name Clear */
|
||
//@{
|
||
/**
|
||
* @brief Clear all objects within associated ObjectContainer
|
||
*/
|
||
void clearObjects();
|
||
|
||
/**
|
||
* @brief Clear static register of GenericObjectFactory
|
||
* (created using registerMe())
|
||
*/
|
||
static void clearRegister();
|
||
//@}
|
||
|
||
/*! \name Register */
|
||
//@{
|
||
|
||
template <typename IMPL_TYPE>
|
||
friend class RegisterFactory; // to support 'REGISTER_TYPE'
|
||
static void registerMe(const std::type_index &key, GenericObjectFactoryBase *factory)
|
||
{
|
||
LOGGER_T logger = getLogger("ObjectFactory");
|
||
DEBUG_LOG(logger) << LOGFUNCTION
|
||
<< " IF '" << key.name() << "'"
|
||
<< " to IMPL '" << factory->getTypeIndexOfImplementation().name() << "')";
|
||
MapSingleton::getFactoryMap()[key] = FactoryMapData(factory);
|
||
|
||
}
|
||
//@}
|
||
|
||
|
||
private:
|
||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||
|
||
Map *m_map = nullptr;
|
||
QSharedPointer<ObjectContainer> m_objectContainer;
|
||
|
||
bool isMapReady() const;
|
||
|
||
};
|
||
|
||
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
// Option for registration
|
||
//----------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief The RegisterFactory class for registering the types to be created by ObjectFactory.
|
||
*/
|
||
template <typename IMPL_TYPE>
|
||
class SITUATIONMAP_EXPORT RegisterFactory final
|
||
{
|
||
public:
|
||
/**
|
||
* @brief Constructor.
|
||
* @param key type_index to be registered
|
||
*/
|
||
explicit RegisterFactory(const std::type_index &key)
|
||
{
|
||
GenericObjectFactoryBase *genericFactory = new GenericObjectFactory<IMPL_TYPE>;
|
||
ObjectFactory::registerMe(key, genericFactory);
|
||
}
|
||
|
||
~RegisterFactory() = default;
|
||
|
||
// create by (interface) type
|
||
// can be used to register by put that macro at the end of the implementation (cpp)
|
||
#define REGISTER_TYPE(interfaceType, implType) \
|
||
namespace { \
|
||
static RegisterFactory<implType> s_factory( typeid(interfaceType) ); \
|
||
};
|
||
|
||
};
|
||
|
||
|
||
|
||
} // namespace SituationMap
|
||
|