/** * @RDE_HEADER@ * Interface for JumpPointWidget * $Id$ * $HeadURL$ * $Author$ */ // Own #include "jump_point_widget.h" #include "jump_point_custom_view.h" #include #include #include #include #include #include #include #include #include #include // Qt #include #include #include #include #include #include namespace SituationMap { //----------------------------------------------------------------------------- // class JumpPointWidget::Private //----------------------------------------------------------------------------- class JumpPointWidget::Private { public: Private() = default; // OWN data: SituationMap::Map *m_map = nullptr; // Use INTERFACE QString m_layername; QString m_debugInfo; RefPointer m_uniqueMarker; QGridLayout *m_layout = nullptr; JumpPointModel *m_jumpPointModel = nullptr; LtsDataView::LtsDataView *m_jumpPointView = nullptr; QMenu *m_actionMenu = nullptr; QAction *m_removeAction = nullptr; QModelIndex m_contextModelIndex; }; // class JumpPointWidget::Private //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // class JumpPointWidget //----------------------------------------------------------------------------- JumpPointWidget::JumpPointWidget(const QString &layername, Map *map, const QString &debugInfo) : BaseClass() , d(new Private) , m_logger(getLogger("JumpPointWidget")) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " debugInfo='" << debugInfo << "'"; d->m_jumpPointModel = new JumpPointModel(this); if (map) { d->m_map = map; d->m_layername = layername; d->m_debugInfo = debugInfo; connect(d->m_map, &Map::beginDestroy, this, &JumpPointWidget::cleanup); d->m_jumpPointModel->setMap(d->m_map); QVBoxLayout *vBox = new QVBoxLayout(); this->setLayout(vBox); QHBoxLayout *hBox = new QHBoxLayout(); vBox->addLayout(hBox); hBox->addWidget(new QLabel(tr("Jump Points:"))); QPushButton *pbPosition = new QPushButton(QIcon(QLatin1String("icon:position.svg")), tr("Position")); hBox->addWidget(pbPosition); connect(pbPosition, &QPushButton::clicked, this, &JumpPointWidget::onGetPosition); pbPosition->setEnabled(d->m_map->mode() == Mode::Mode_2D); d->m_jumpPointView = new LtsDataView::LtsDataView(this); vBox->addWidget(d->m_jumpPointView); d->m_jumpPointView->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); d->m_jumpPointView->selectCustomView(); d->m_jumpPointView->seamless(); d->m_jumpPointView->setModel(d->m_jumpPointModel, [this]() { return new JumpPointCustomView(this); }); // connect signals of TableView: connect(d->m_jumpPointView, &LtsDataView::LtsDataView::signalEntered, this, &JumpPointWidget::onTableViewClicked); connect(d->m_jumpPointView, &LtsDataView::LtsDataView::clicked, this, &JumpPointWidget::onTableViewSelectionChanged); d->m_jumpPointView->hideColumn(JumpPointModel::Columns::ORIGIN_GEO); // do not "print" d->m_jumpPointView->hideColumn(JumpPointModel::Columns::ICON); // do not "print" } else ERROR_LOG(m_logger) << LOGFUNCTION << " no map"; // context menue: d->m_jumpPointView->setContextMenuPolicyPerView(LtsDataView::LtsDataView::CUSTOM, Qt::CustomContextMenu); connect(d->m_jumpPointView, &LtsDataView::LtsDataView::signalContextMenuRequested, this, &JumpPointWidget::onCustomContextMenuRequested); d->m_actionMenu = new QMenu(this); d->m_removeAction = new QAction(tr("Remove Jump Point"), this); d->m_actionMenu->addAction(d->m_removeAction); connect(d->m_removeAction, &QAction::triggered, this, &JumpPointWidget::onRemoveAction); TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " END"; } JumpPointWidget::~JumpPointWidget() { TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " START"; this->cleanup(); TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " END"; delete d; } QStringList JumpPointWidget::names() { if (!d->m_jumpPointModel) return QStringList(); return d->m_jumpPointModel->names(); } QVector JumpPointWidget::jumpPoints() { if (!d->m_jumpPointModel) return QVector(); return d->m_jumpPointModel->jumpPoints(); } int JumpPointWidget::count() const { if (!d->m_jumpPointModel) return 0; return d->m_jumpPointModel->rowCount(); } bool JumpPointWidget::contains(const QString &name) { if (!d->m_jumpPointModel) return false; return d->m_jumpPointModel->contains(name); } bool JumpPointWidget::removeJumpPoint(const QString &name) { return d->m_jumpPointModel->removeItem(name); } void JumpPointWidget::onGetPosition() { TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " START"; if (!d->m_map) return; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Workaround to make sure that cursor setting of rubberband will work. Don't know why this * is necessary. ToDo find the reason why changing cursor failed and fix the underlying cause. * * JT 2017/05/04 */ d->m_map->sideBar()->hide(); // QCoreApplication::process Events(); // 2017.11.03, N.Thoden, not necessary /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // remove any pending/active rubberbands of our map: SituationMap::RB::Rubberband::deleteAllActiveRubberbands(d->m_map); // create rb RB::RubberbandPointFeature *rb = d->m_map->rubberbandFactory().create(this); if (!rb || !rb->rubberbandIsAlive()) { if (rb) rb->deleteMySelf(); FATAL_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " create Rubberband failed!"; return; } rb->setAutoDelete(true); connect(rb, &RB::Rubberband::apply, this, &JumpPointWidget::onRubberbandApply); } void JumpPointWidget::onRubberbandApply(RB::RubberbandBase *rb) { QPolygonF coordGeo = rb->coordinateVector(); if (coordGeo.size() != 1) return; connect(this, &JumpPointWidget::newName, this, &JumpPointWidget::onName); askUserForName(coordGeo.front()); } void JumpPointWidget::askUserForName(const QPointF &coordGeo) { JumpPointNamer *namer = new JumpPointNamer(this->count(), coordGeo, this); namer->setAttribute(Qt::WA_DeleteOnClose); namer->connect(namer, &JumpPointNamer::newName, this, &JumpPointWidget::newName); namer->show(); } void JumpPointWidget::onName(const QString &name, const QPointF & coordGeo) { disconnect(this, &JumpPointWidget::newName, this, &JumpPointWidget::onName); const double scale = d->m_map->scale(); addJumpPoint(name, coordGeo, scale); } void JumpPointWidget::onJumpPointHovered(const QString &name, bool enter) { setJumpPointSelected(name, enter); } void JumpPointWidget::onTableViewClicked(const QModelIndex &index) { if (!d->m_jumpPointModel) return; JPData *jumpPoint = d->m_jumpPointModel->getItemPtr(index); if (!jumpPoint) { ERROR_LOG(m_logger) << LOGFUNCTION << " not found"; return; } removeJumpPointSelections(); onJumpPointHovered(jumpPoint->m_name, true); } void JumpPointWidget::onTableViewSelectionChanged(const QModelIndex &index) { if (!d->m_jumpPointModel) return; JPData *jumpPoint = d->m_jumpPointModel->getItemPtr(index); if (!jumpPoint) { ERROR_LOG(m_logger) << LOGFUNCTION << " not found"; return; } centerMapToJumpPoint(jumpPoint->m_name); } bool JumpPointWidget::addJumpPoint(const QString &name, const QPointF &originGeo, double mapScale) { return addJumpPoint(name, Point3D::fromQPointF(originGeo), mapScale); } bool JumpPointWidget::addJumpPoint(const QString &name, const Point3D &originGeo, double mapScale) { TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " START" << " name='" << name << "'" << " originGeo=" << originGeo << " mapScale=" << mapScale; if (d->m_layername.isEmpty()) { ERROR_LOG(m_logger) << LOGFUNCTION << " no layername"; return false; } { JPData jpData(name, originGeo, mapScale); jpData.m_image = QImage(QLatin1String(":/situationMap/pushPinRedClipArt.png")).scaled(30, 30, Qt::KeepAspectRatio, Qt::SmoothTransformation); d->m_jumpPointModel->addUpdateItem(jpData); } JPData *jumpPoint = d->m_jumpPointModel->getItemPtr(name); if (!jumpPoint) { ERROR_LOG(m_logger) << LOGFUNCTION << " not found"; return false; } if (! jumpPoint->hasMarker()) { QString debugInfo = QStringLiteral("%1_JumpPoint(%2)").arg(d->m_debugInfo, name); jumpPoint->m_marker = d->m_map->objectFactory().create(d->m_layername, debugInfo); if (! jumpPoint->m_marker.valid()) { ERROR_LOG(m_logger) << LOGFUNCTION << " create GeoImage failed, debugInfo='" << d->m_debugInfo << "'"; return false; } jumpPoint->m_marker->setProxyMarker(MarkerSymbolType::PushPin2D); jumpPoint->m_marker->setPickable(false); } jumpPoint->m_mapScale = mapScale; jumpPoint->m_originGeo = originGeo; jumpPoint->m_marker->setOrigin(originGeo); jumpPoint->m_marker->setIdentifier(name); this->setJumpPointSelected(name, false); bool success = jumpPoint->m_marker->updateView(); if (! success) ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed, debugInfo='" << d->m_debugInfo << "'"; TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " END" << " name='" << name << "'" << " originGeo=" << originGeo << " mapScale=" << mapScale; return success; } bool JumpPointWidget::centerMapToJumpPoint(const QString &name) { TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " START" << " name='" << name << "'"; JPData *jumpPoint = d->m_jumpPointModel->getItemPtr(name); if (!jumpPoint) { ERROR_LOG(m_logger) << LOGFUNCTION << " not found"; return false; } const Point3D &originGeo = jumpPoint->m_originGeo; const double mapScale = jumpPoint->m_mapScale; d->m_map->setCenterPoint(originGeo.toPointF(), mapScale); TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " END"; return true; } void JumpPointWidget::removeJumpPointSelections() { TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " START"; if (!d->m_jumpPointModel) return; const QStringList &sl = d->m_jumpPointModel->names(); for (const auto &name : sl) setJumpPointSelected(name, false); TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " END"; } bool JumpPointWidget::setJumpPointSelected(const QString &name, bool selected) { TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " START" << " name='" << name << "'" << " selected='" << selected; JPData *jumpPoint = d->m_jumpPointModel->getItemPtr(name); if (!jumpPoint) { ERROR_LOG(m_logger) << LOGFUNCTION << " not found"; return false; } if (! jumpPoint->hasMarker()) return false; // jumpPoint->m_marker->setSelected(selected); // jumpPoint->m_marker->setScale((selected) ? 1.5 : 1.0); jumpPoint->m_marker->setProxyMarkerSize((selected) ? 30 : 20); jumpPoint->m_marker->setDrawOrder((selected) ? 2 : 1); // selected should be above the other jumpPoint->m_marker->rTextStyle().setSize((selected) ? 20 : 10); bool success = jumpPoint->m_marker->updateView(); if (! success) ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed, debugInfo='" << d->m_debugInfo << "'"; TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " END" << " name='" << name << "'" << " selected='" << selected; return success; } void JumpPointWidget::onCustomContextMenuRequested(const QPoint &globalPos, const QModelIndex &indexSrc) { d->m_contextModelIndex = indexSrc; if (!d->m_contextModelIndex.isValid()) return; d->m_actionMenu->exec(globalPos); } void JumpPointWidget::onRemoveAction() { if (!d->m_contextModelIndex.isValid()) return; d->m_jumpPointModel->removeRow(d->m_contextModelIndex.row()); } void JumpPointWidget::cleanup() { TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " START"; d->m_jumpPointModel->clear(); TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " END"; } bool JumpPointWidget::event(QEvent *event) { TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " START" << " type " << event->type(); if (event->type() == QEvent::Type::Hide) { TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << d->m_debugInfo << "'" << " hide Event -> removeJumpPointSelections..."; this->removeJumpPointSelections(); } return BaseClass::event(event); } } // namespace SituationMap