/** * @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 #include #include // Qt #include #include //---------------------------------------------------------------------------- namespace SituationMap { // forward class Map; using FactoryMapKey = std::type_index; using FactoryMapData = QSharedPointer; using FactoryMap = QMap; /** * @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) * * Example: * * \code // Pre-condition : // Initialize objectFactory: SituationMap::ObjectFactory::registerMe(typeid(SituationMap::Participant), new SituationMap::GenericObjectFactory() ); // : Pre-condition ... SituationMap::ObjectFactory& objFac = d->m_map->objectFactory(); // use an LOGICAL layer (not basemap) QString layername("ParticipantLayerName"); SituationMap::RefPointer objPtr; objPtr = objFac.create("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); //@} /** * @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 RefPointer 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(); } if (logicalLayerName.isEmpty()) { FATAL_LOG(m_logger) << LOGFUNCTION << " create failed" << ", logicalLayerName is empty" << ", debugInfo='" << debugInfo << "'"; return RefPointer(); } 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 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(); } FATAL_LOG(m_logger) << LOGFUNCTION << " create failed, name= '" << name << "'" << ", factoryMap.size() = " << MapSingleton::getFactoryMap().count(); return RefPointer(); } /** * @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 RefPointer create(const QString &logicalLayerName, // external: via type const QString &debugInfo = QString()) { return create(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 not 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 regarding the type. * @param uniqueMapId to lookup. * @return Returns true if container contains an occurrence; otherwise returns false. */ template 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 getAllKeys() const; /** * @brief Get all Objects. * @return Container with all objects. */ QList < RefPointer > getAllObjects() const; /** * @brief Get access the object. * @param uniqueId to lookup. * @return Pointer to AbstractMapObject (Base class). */ RefPointer get(const UniqueMapId &uniqueMapId) const; /** * @brief Get access to object regarding the type. * @param uniqueId to lookup. * @return Pointer to object (adaquate type). */ template RefPointer get(const UniqueMapId &uniqueMapId) const { TRACE_LOG(m_logger) << LOGFUNCTION << " get requested for uniqueMapId=" << uniqueMapId; // lookup in internal container: RefPointer mapObj = get(uniqueMapId); return RefPointer(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 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 m_objectContainer; bool isMapReady() const; }; //---------------------------------------------------------------------------- // Option for registration //---------------------------------------------------------------------------- /** * @brief The RegisterFactory class for registering the types to be created by ObjectFactory. */ template 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; 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 s_factory( typeid(interfaceType) ); \ }; }; } // namespace SituationMap