Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/Map/object_factory.h
T
2026-08-13 18:33:10 +02:00

407 lines
12 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @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