446 lines
14 KiB
C++
Executable File
446 lines
14 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* Interface for JumpPointWidget
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
|
|
// Own
|
|
#include "jump_point_widget.h"
|
|
#include "jump_point_custom_view.h"
|
|
#include <Map/map.h>
|
|
#include <Map/object_factory.h>
|
|
#include <Map/situation_map_utils.h>
|
|
#include <MapImpl/layer_factory_impl.h>
|
|
#include <MapImpl/jump_point_namer.h>
|
|
#include <MapImpl/coord_translation_functor_impl.h>
|
|
#include <GraphicalObjects/graphical_object_picture_marker.h>
|
|
#include <Rubberbands/rubberband_factory.h>
|
|
|
|
#include <MapObjects/geo_image.h>
|
|
|
|
#include <LtsDataView/lts_data_view.h>
|
|
|
|
|
|
// Qt
|
|
#include <QCoreApplication>
|
|
#include <QHBoxLayout>
|
|
#include <QPushButton>
|
|
#include <QMenu>
|
|
#include <QAction>
|
|
#include <QFocusEvent>
|
|
|
|
|
|
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<GeoImage> 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<JPData> JumpPointWidget::jumpPoints()
|
|
{
|
|
if (!d->m_jumpPointModel)
|
|
return QVector<JPData>();
|
|
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<RB::RubberbandPointFeature>(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<SituationMap::GeoImage>(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
|