/** * @RDE_HEADER@ * Interface of AbstractMapObject * $Id$ * $HeadURL$ * $Author$ */ // Own #include "overlay_handler_impl.h" #include #include #include #include #include #include #include #include "geometry_model_renderer_esri.h" #include //---------------------------------------------------------------------------- namespace SituationMap { OverlayHandler *OverlayHandler::create(Map *map) { return new OverlayHandlerImpl(map); } static const QLatin1String s_verlayLayerPrefix = QLatin1String("OverlayLayer_"); class OverlayData { public: ~OverlayData() { // graceful cleanup, destroy associated MapObject (adequate signal will be emitted) if (m_geoModel) m_geoModel->clearModel(); m_geoModelRenderer.clear(); m_geoModel.clear(); // : graceful cleanup } int m_key = -1; QString m_logicalLayerName; QString m_technicalLayerName; // just for debugging purpose QSharedPointer m_geoModel; QSharedPointer m_geoModelRenderer; bool init(Map *map) { if (m_logicalLayerName.isEmpty()) return false; m_geoModel = QSharedPointer(SituationMap::GeometryModelFactory::singleton()->create()); m_geoModelRenderer = QSharedPointer(map->createGeometryModelRenderer(m_logicalLayerName, m_geoModel.data())); m_geoModelRenderer->setNodesPickable(false); // we just want to display the overlay, no picking return !m_geoModelRenderer.isNull(); } QString toString() const { QString str; str.append(QStringLiteral("m_key=%1").arg(m_key)); str.append(QStringLiteral(" m_logicalLayerName='%1'").arg(m_logicalLayerName)); str.append(QStringLiteral(" m_technicalLayerName='%1'").arg(m_technicalLayerName)); return str; } }; //----------------------------------------------------------------------------- class OverlayHandlerImpl::Private { public: Private() = default; ~Private() = default; // ESRI data: // Own data: Map *m_map = nullptr; private: QMap> m_overlayCont; public: QSharedPointer &getOverlayData(int key) { if (m_overlayCont[key].isNull()) m_overlayCont[key] = QSharedPointer(new OverlayData()); return m_overlayCont[key]; } int remove(int key) { return m_overlayCont.remove(key); } void clear() { m_overlayCont.clear(); } int size() { return m_overlayCont.size(); } QList keys() { return m_overlayCont.keys(); } bool contains(int key) { return m_overlayCont.contains(key); } QMutableMapIterator> mutableIterator() { return QMutableMapIterator> (m_overlayCont); } }; // class OverlayHandlerImpl::Private //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- OverlayHandlerImpl::OverlayHandlerImpl(Map *map) : BaseClass() , m_logger(getLogger("OverlayHandlerImpl")) , d(new Private) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; d->m_map = map; if (! d->m_map) ERROR_LOG(m_logger) << LOGFUNCTION << " error no Map "; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } OverlayHandlerImpl::~OverlayHandlerImpl() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; delete d; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } QString OverlayHandlerImpl::toString() const { QString str(QLatin1String("OverlayHandlerImpl")); str.append(QStringLiteral(" m_overlayCont.size=%1").arg(d->size())); return str; } bool OverlayHandlerImpl::setOverlay(int key, const QString &name, const QByteArray &overlayContent, bool isSnapshot) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key << " name='" << name << "'" << " overlayContent.size()='" << overlayContent.size() << " isSnapshot=" << isSnapshot; if (! d->m_map) { ERROR_LOG(m_logger) << LOGFUNCTION << " error, no Map " << " key=" << key; return false; } const bool contains = d->contains(key); // data: QSharedPointer overlayData; // create or update? if (contains) { DEBUG_LOG(m_logger) << LOGFUNCTION << " Current11 SnaphotOverlay" << d->m_map->layerFactory().layerParameter(QStringLiteral("SnaphotOverlay")); overlayData = d->getOverlayData(key); // already created, but update displayname: if (! d->m_map->layerFactory().addOverlayLayer(overlayData->m_logicalLayerName, name, isSnapshot)) { ERROR_LOG(m_logger) << LOGFUNCTION << " error on addOverlayLayer" << " key=" << key; TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key; return false; } } else { DEBUG_LOG(m_logger) << " CurrentAA SnaphotOverlay" << d->m_map->layerFactory().layerParameter(QStringLiteral("SnaphotOverlay")); overlayData = QSharedPointer(new OverlayData()); // case 'create' -> create layer: overlayData->m_key = key; if (isSnapshot) overlayData->m_logicalLayerName = d->m_map->layerFactory().snapshotOverlayLayername(); else overlayData->m_logicalLayerName = QString(s_verlayLayerPrefix) + QString::number(key); if (! d->m_map->layerFactory().addOverlayLayer(overlayData->m_logicalLayerName, name, isSnapshot)) { ERROR_LOG(m_logger) << LOGFUNCTION << " error on addOverlayLayer" << " key=" << key; TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key; return false; } // LayerFactory will make sure the technical layer is created. DEBUG_LOG(m_logger) << LOGFUNCTION << " key=" << key << " overlayData init..."; if (! overlayData->init(d->m_map)) { ERROR_LOG(m_logger) << LOGFUNCTION << " error on init" << " key=" << key; d->m_map->layerFactory().removeOverlayLayer(overlayData->m_logicalLayerName); TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key; return false; } } // if (contains) bool success = false; if (overlayContent.isEmpty()) { // in case of restoring the OperatorMapSettings / toggle 2D<->3D) // prepare layer WITHOUNT content DEBUG_LOG(m_logger) << LOGFUNCTION << " END, overlayContent is empty, so just be prepared" << ", key=" << key << ", isSnapshot=" << isSnapshot; success = true; } else { if (overlayData->m_geoModel && overlayData->m_geoModelRenderer) { if (!overlayData->m_geoModel->fromByteArray(overlayContent)) { // overlayContent string is not a valid geoModel -> abort ERROR_LOG(m_logger) << LOGFUNCTION << " error on fromString," << " key=" << key; if (!d->m_map->layerFactory().removeOverlayLayer(overlayData->m_logicalLayerName)) { ERROR_LOG(m_logger) << LOGFUNCTION << " removeOverlayLayer failed," << " key=" << key; } TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key; return false; } // overlayData->m_geoModel->cleanModel(true); has been done in GeometryModel::fromString DEBUG_LOG(m_logger) << LOGFUNCTION << " key=" << key << " render..."; if (overlayData->m_geoModelRenderer->render()) { success = true; } else { ERROR_LOG(m_logger) << LOGFUNCTION << " error on render" << " key=" << key; } } } // if (overlayContent.isEmpty()) if (success) { // add temporary data to internal map: if (!contains) d->getOverlayData(key) = overlayData; //INFO_LOG(m_logger) << LOGFUNCTION << " olData=" << d->getOverlayData(key).data()->toString(); } else { INFO_LOG(m_logger) << LOGFUNCTION << " removeOverlayLayer" << " key=" << key << ", m_logicalLayerName " << overlayData->m_logicalLayerName; d->m_map->layerFactory().removeOverlayLayer(overlayData->m_logicalLayerName); } // const QString &strRef = overlayData->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes).toString(); const QVector &ptbdCont = SituationMap::PixelTextBoxData::pixelTextBoxContainerFromJsonStr(strRef); PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = d->m_map->pixelBasedTextBoxHandler(); // cleanup: const int parentId = key; // key == fileId pixelBasedTextBoxHandler.removeAllTextBoxesOfParent(parentId); for (const SituationMap::PixelTextBoxData &ptbd : qAsConst(ptbdCont)) { // create WITHIN loop, since it will be modified by createUpdateTextBox: PBTB_ID pbtbId; pbtbId.m_parentId = parentId; QTextEdit *newTextEdit = pixelBasedTextBoxHandler.createTextBox(pbtbId, ptbd, false); if (newTextEdit) DEBUG_LOG(m_logger) << LOGFUNCTION << " new TextBox created: newTextEdit = " << newTextEdit << ", pbtbId=" << pbtbId << ", ptbd=" << ptbd; else ERROR_LOG(m_logger) << LOGFUNCTION << " createUpdateTextBox failed" << ", pbtbId=" << pbtbId << ", ptbd=" << ptbd; } // for TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key << ", size=" << d->size(); return success; } QByteArray OverlayHandlerImpl::content(int key) const { if (!d->contains(key)) { ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown"; return QByteArray(); } QSharedPointer overlayData = d->getOverlayData(key); return overlayData->m_geoModel->toByteArray(); } bool OverlayHandlerImpl::reorderOverlays(const QVector &orderOfIds) { QStringList layerOrder = d->m_map->layerFactory().layernames(); // Change the logical layer names in layerOrder list at all positions where a logical layer name has been map to an id ... int idIndex = 0; for (QStringList::iterator iter = layerOrder.begin(); layerOrder.end() != iter; ++iter) { QVector::const_iterator orderIter = orderOfIds.cbegin(); // looking for the current logicalLayername in list of orderOfIds while (orderOfIds.cend() != orderIter) { if (*iter == d->getOverlayData(*orderIter)->m_logicalLayerName) { // layer exists in orderOfIds lets change the order *iter = d->getOverlayData(orderOfIds[idIndex])->m_logicalLayerName; // set new layername for this position ++idIndex; break; // logical layer name is existing only once and we have changed the order hat this position, so we can leaf the while loop here } ++orderIter; } } // ready now give the new layer order to layer factory if (!d->m_map->layerFactory().orderLayerTo(layerOrder)) { ERROR_LOG(m_logger) << LOGFUNCTION << " orderLayerTo failed."; return false; } return true; } // void OverlayHandlerImpl::reorderOverlays( const QVector & orderOfIds ) double OverlayHandlerImpl::minScale(int key) const { if (! d->contains(key)) { ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown"; return -1.0; } QSharedPointer overlayData = d->getOverlayData(key); const QString &logicalLayername = overlayData->m_logicalLayerName; LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername); return lp.minScale; } bool OverlayHandlerImpl::setMinScale(int key, double minScale) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key << " minScale=" << minScale; if (! d->contains(key)) { ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown"; return false; } QSharedPointer overlayData = d->getOverlayData(key); const QString &logicalLayername = overlayData->m_logicalLayerName; // get LayerParameter, update data and set: LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername); lp.minScale = minScale; if (! d->m_map->layerFactory().setLayerParameter(logicalLayername, lp)) { ERROR_LOG(m_logger) << LOGFUNCTION << " error updating LayerParameter, key=" << key; return false; } TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key << " minScale=" << minScale; return true; } double OverlayHandlerImpl::maxScale(int key) const { if (! d->contains(key)) { ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown"; return -1.0; } QSharedPointer overlayData = d->getOverlayData(key); const QString &logicalLayername = overlayData->m_logicalLayerName; LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername); return lp.maxScale; } bool OverlayHandlerImpl::setMaxScale(int key, double maxScale) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key << " maxScale=" << maxScale; if (! d->contains(key)) { ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown"; return false; } QSharedPointer overlayData = d->getOverlayData(key); const QString &logicalLayername = overlayData->m_logicalLayerName; // get LayerParameter, update data and set: LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername); lp.maxScale = maxScale; if (! d->m_map->layerFactory().setLayerParameter(logicalLayername, lp)) { ERROR_LOG(m_logger) << LOGFUNCTION << " error updating LayerParameter, key=" << key; return false; } TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key << " maxScale=" << maxScale; return true; } double OverlayHandlerImpl::opacity(int key) const { if (! d->contains(key)) { ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown"; return 0.0; } QSharedPointer overlayData = d->getOverlayData(key); const QString &logicalLayername = overlayData->m_logicalLayerName; // get LayerParameter, update data and set: LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername); return double(lp.opacity) / 100.0; } bool OverlayHandlerImpl::setOpacity(int key, double opacity) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key << " opacity=" << opacity; if (! d->contains(key)) { ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown"; return false; } opacity = (opacity < 0.0) ? 0.0 : ((opacity > 1.0) ? 1.0 : opacity); QSharedPointer overlayData = d->getOverlayData(key); const QString &logicalLayername = overlayData->m_logicalLayerName; // get LayerParameter, update data and set: LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername); lp.opacity = int(opacity * 100); if (! d->m_map->layerFactory().setLayerParameter(logicalLayername, lp)) { ERROR_LOG(m_logger) << LOGFUNCTION << " error on setLayerParameter" << " key=" << key; return false; } TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key << " opacity=" << opacity; return true; } bool OverlayHandlerImpl::setOverlayVisibility(int key, bool visibility) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key << " visibility=" << visibility; // Lookup: QSharedPointer overlayData = d->getOverlayData(key); const QString &logicalLayername = overlayData->m_logicalLayerName; INFO_LOG(m_logger) << LOGFUNCTION << " visibility of layer='" << logicalLayername << "'" << " key=" << key << " -> " << visibility; if (logicalLayername.isEmpty()) { ERROR_LOG(m_logger) << LOGFUNCTION << " layername is empty, key=" << key << " unknown"; return false; } // Technical/Esri: // get LayerParameter, update data and set: LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername); lp.visible = visibility; if (! d->m_map->layerFactory().setLayerParameter(logicalLayername, lp)) { ERROR_LOG(m_logger) << LOGFUNCTION << " error on setLayerParameter" << " key=" << key; return false; } TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key << " visibility=" << visibility; return true; } bool OverlayHandlerImpl::overlayVisibility(int key) const { QSharedPointer overlayData = d->getOverlayData(key); const QString &logicalLayername = overlayData->m_logicalLayerName; if (logicalLayername.isEmpty()) { ERROR_LOG(m_logger) << LOGFUNCTION << " layername is empty, key=" << key << " unknown"; return false; } LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername); return lp.visible; } // bool OverlayHandlerImpl::overlayVisibility(const int &key) bool OverlayHandlerImpl::removeOverlay(int key) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key; if (! d->m_map) { ERROR_LOG(m_logger) << LOGFUNCTION << " error no Map " << " key=" << key; return false; } if (! d->contains(key)) { ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown"; return false; } // Lookup: QSharedPointer overlayData = d->getOverlayData(key); QString logicalLayername = overlayData->m_logicalLayerName; // create a copy here DEBUG_LOG(m_logger) << LOGFUNCTION << " remove layer='" << logicalLayername << "'" << " key=" << key; if (logicalLayername.isEmpty()) { ERROR_LOG(m_logger) << LOGFUNCTION << " layername is empty, key=" << key; return false; } // Own data management: // // FIRST: // // Remove own MapObject BEFORE the layer d->remove(key); overlayData.clear(); // to decrease QSharedPointer <----- important // // SECOND: // // Technical/Esri: if (!d->m_map->layerFactory().removeOverlayLayer(logicalLayername)) { WARNING_LOG(m_logger) << LOGFUNCTION << " remove layer='" << logicalLayername << "'" << " key=" << key; return false; } // // Pixel-based TextBoxes: // PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = d->m_map->pixelBasedTextBoxHandler(); const int parentId = key; // key == fileId pixelBasedTextBoxHandler.removeAllTextBoxesOfParent(parentId); TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key; return true; } int OverlayHandlerImpl::removeAllOverlays() { TRACE_LOG(m_logger) << LOGFUNCTION << " START, current size = " << d->size(); int removed = 0; const QList ¤tKeys = d->keys(); for (int key : currentKeys) { if (removeOverlay(key)) ++removed; } TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " removed = " << removed << " size now = " << d->size(); return removed; } int OverlayHandlerImpl::overlayCount() const { return d->size(); } QList OverlayHandlerImpl::overlays() const { return d->keys(); } bool OverlayHandlerImpl::containsOverlay(int key) const { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; return d->contains(key); } //----------------------------------------------------------------------------- // output operator: //----------------------------------------------------------------------------- std::ostream &operator<< (std::ostream &stream, const OverlayHandlerImpl &value) { stream << value.toString(); return stream; } } // namespace SituationMap