Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/Rubberbands/rubberband_state_select.cpp
T
2026-08-13 18:33:10 +02:00

573 lines
19 KiB
C++
Executable File

/**
**
** @RDE_HEADER@
** Implementation of rubberband class to edit states of point objects
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 19.10.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_state_select.h"
#include "rubberband_point_handle.h"
#include "rubberband_drawable.h"
#include "rubberband_handle_proxy.h"
#include "rubberband_factory.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
#include <arcgis/Map.h>
#include <arcgis/MapGraphicsView.h>
#include <QtGui/QCursor>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QMenu>
#include "polygon.xpm"
namespace SituationMap { namespace RB
{
struct RubberbandStateSelect::InternalData
{
Q_DISABLE_COPY(InternalData)
InternalData() : _logger(getLogger("RubberbandStateSelect"))
{}
~InternalData()
{
delete _stateMenu;
}
QVector<State> _states;
QVector<StateItem> _items;
QList<SituationMap::RefPointer<RubberbandHandle>> _stateMenuSelectedHandleList;
LOGGER_T _logger;
const State * getStateFromValue( int stateValue ) const
{
for (const State &state : _states)
{
if (state.value() == stateValue) return &state;
}
return nullptr;
} /* getStateFromValue */
const State * getStateFromItem( const StateItem & item ) const { return getStateFromValue(item.stateValue()); }
static QPixmap * _polygonIcon;
QPushButton * _polygonButton = nullptr;
QMenu * _stateMenu = nullptr;
bool _stateMenuIsActive = false;
}; /* RubberbandMultiPointFeature::InternalData */
QPixmap * RubberbandStateSelect::InternalData::_polygonIcon = nullptr;
void RubberbandStateSelect::setIconPolygon(const QPixmap & icon)
{
if (InternalData::_polygonIcon == nullptr) InternalData::_polygonIcon = new QPixmap(icon);
else *InternalData::_polygonIcon = icon;
} /* RubberbandStateSelect::setIconPolygon */
RubberbandStateSelect::RubberbandStateSelect( SituationMap::Map * map, QObject * parent )
: Rubberband(map,parent), _internal(new InternalData())
{
delete RubberbandBase::_baseInternal->_undoButton;
RubberbandBase::_baseInternal->_undoButton = nullptr;
_internal->_polygonButton = new QPushButton( (InternalData::_polygonIcon) ? *InternalData::_polygonIcon : QPixmap(polygon_xpm), QString(), RubberbandBase::_baseInternal->_buttonBox );
RubberbandBase::_baseInternal->_buttonLayout->insertWidget( 0, _internal->_polygonButton );
connect( _internal->_polygonButton, &QPushButton::clicked, this, &RubberbandStateSelect::onDo_areaSelectionBegin );
// Check Quartz
connect( Rubberband::_internal->_mapView.data(), &Esri::ArcGISRuntime::MapGraphicsView::viewpointChanged,
this, &RubberbandStateSelect::onDo_updateButtonFixCoordinates );
connect( Rubberband::_internal->_mapView.data(), &Esri::ArcGISRuntime::MapGraphicsView::rectChanged ,
this, &RubberbandStateSelect::onDo_updateButtonFixCoordinates );
setFixedButtonBoxPosition(QPoint(5,5));
} /* RubberbandStateSelect::RubberbandStateSelect */
bool RubberbandStateSelect::setStateItems( const QVector<State> & stateVector
, const QVector<StateItem> & itemVector
, CoordinateSystem cs )
{
if (stateVector.size() < 2) return false;
if (itemVector.isEmpty()) return false;
// check for all states are valid
for (const State & state : qAsConst(_internal->_states))
{
if (!state.isValid())
return false;
}
bool ok = true;
_internal -> _states = stateVector;
_internal -> _items = itemVector;
for (QVector<StateItem>::iterator it = _internal->_items.begin(); it != _internal->_items.end(); ++it)
{
if (it->isValid())
{
const State * statePtr = _internal->getStateFromItem( *it );
if (statePtr == nullptr)
{
ok = false;
statePtr = & _internal->_states.first();
}
const QPointF &mapPos = projectCoordinateToMap( cs, it->coordinate() );
Esri::ArcGISRuntime::Point mapCoordinate( mapPos.x(), mapPos.y(), Rubberband::_internal->_mapView->map()->spatialReference() );
RubberbandPointHandle * handlePtr = new RubberbandPointHandle( Rubberband::_internal->_mapView
, Rubberband::_internal->_mapScene
, mapCoordinate
, statePtr->icon() );
if (handlePtr)
{
handlePtr->setSelection(false);
handlePtr->setUserData( &(*it) );
Rubberband::_internal->_handleList.append( SituationMap::RefPointer<RubberbandHandle>(handlePtr) );
}
}
else ok = false;
}
update();
activateButtons();
buildStateMenu();
return ok;
} /* RubberbandStateSelect::setStateItems */
const QVector<RubberbandStateSelect::StateItem> & RubberbandStateSelect::stateItems() const
{
return _internal->_items;
} /* RubberbandStateSelect::stateItems */
void RubberbandStateSelect::activateButtons()
{
_baseInternal->_hasUndoButton = false;
_baseInternal->_applyIsPossible = (!Rubberband::_internal->_handleList.isEmpty());
_baseInternal->_undoIsPossible = false;
Rubberband::activateButtons();
} /* RubberbandStateSelect::activateButton */
void RubberbandStateSelect::toggleState( RubberbandPointHandle * handlePtr )
{
if (_internal->_states.size() < 2) return;
if (handlePtr == nullptr) return;
StateItem * itemPtr = static_cast<StateItem*>(handlePtr->userData());
if (itemPtr == nullptr) return;
if (_internal->_states.size() == 2)
{
const State * statePtr = _internal -> getStateFromItem( *itemPtr );
if (statePtr != nullptr)
{
if (statePtr == &_internal->_states.first()) statePtr = &_internal->_states.last();
else statePtr = &_internal->_states.first();
}
else statePtr = &_internal->_states.first();
itemPtr->_stateValue = statePtr->value();
handlePtr->setIcon( statePtr->icon() );
}
} /* RubberbandStateSelect::toggleState */
void RubberbandStateSelect::setState( RubberbandPointHandle * handlePtr, int stateValue )
{
if (handlePtr == nullptr) return;
const State * statePtr = _internal -> getStateFromValue(stateValue);
StateItem * itemPtr = static_cast<StateItem*>(handlePtr->userData());
if (itemPtr == nullptr) return;
if (statePtr == nullptr) return;
itemPtr->_stateValue = stateValue;
handlePtr->setIcon( statePtr->icon() );
} /* RubberbandStateSelect::setState */
void RubberbandStateSelect::buildStateMenu()
{
if (_internal->_states.isEmpty()) return;
_internal->_stateMenu = new QMenu();
for (const State & state : qAsConst(_internal->_states))
{
QAction * action = _internal->_stateMenu->addAction( state.icon(), state.description() );
action -> setData( state.value() );
connect( action, &QAction::triggered, this, &RubberbandStateSelect::onDo_setState );
}
connect( _internal->_stateMenu, &QMenu::aboutToShow, this, [this]()
{
this->_internal->_stateMenuSelectedHandleList.clear();
_baseInternal->_buttonBox->setDisabled(true);
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
if (handle->isSelected())
{
this->_internal->_stateMenuSelectedHandleList << handle;
}
}
} );
connect( _internal->_stateMenu, &QMenu::aboutToHide, this, [this]()
{
_baseInternal->_buttonBox->setEnabled(true);
deSelectHandles();
} );
} /* RubberbandStateSelect::buildStateMenu */
void RubberbandStateSelect::onDo_setState(bool)
{
QAction * action = (QAction*) sender();
if (action == nullptr) return;
int stateValue = action->data().toInt();
for (auto handle : qAsConst(_internal->_stateMenuSelectedHandleList))
setState( dynamic_cast<RubberbandPointHandle*>(handle.get()), stateValue );
_internal -> _stateMenuSelectedHandleList.clear();
_internal -> _stateMenuIsActive = false;
update();
} /* RubberbandStateSelect::onDo_setState */
void RubberbandStateSelect::chooseStateMenu()
{
// popup a window with states the user can choose
_internal->_stateMenu->popup( QCursor::pos() );
_internal -> _stateMenuIsActive = true;
} /* RubberbandStateSelect::chooseStateMenu */
bool RubberbandStateSelect::selectAction( AbstractEventDispatcher*, int x, int y )
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
_internal->_stateMenuSelectedHandleList.clear();
if (rubberbandIsAlive())
{
if (_internal->_stateMenuIsActive) return true;
QPointF scenePos(pixel2ScenePosition(x,y));
if (_baseInternal->buttonProxyActive(scenePos)) return false;
RubberbandHandle * handlePtr = pickHandle(x,y);
if (handlePtr)
{
handlePtr->setSelection();
enableSelectedState();
update();
deactivateButtons();
return true;
}
}
return false;
} /* RubberbandStateSelect::selectAction */
bool RubberbandStateSelect::multiSelectActionPress(AbstractEventDispatcher*, int x, int y)
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
if (rubberbandIsAlive())
{
if (_internal -> _stateMenuIsActive) return true;
RubberbandHandle * handlePtr = pickHandle(x,y);
if (handlePtr)
{
handlePtr->setSelection();
enableSelectedState();
enableMultiSelectedState();
update();
deactivateButtons();
return true;
}
}
return false;
} /* RubberbandStateSelect::multiSelectActionPress */
bool RubberbandStateSelect::multiSelectActionRelease( AbstractEventDispatcher*, int, int )
{
return false;
} /* RubberbandStateSelect::multiSelectActionRelease */
bool RubberbandStateSelect::setCoordinateAction( AbstractEventDispatcher * causer, int x, int y )
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
if (rubberbandIsAlive())
{
Rubberband::_internal->_lastClickPosition = pixel2ScenePosition(x,y);
if (_internal->_stateMenuIsActive)
{
_internal -> _stateMenuIsActive = false;
disenableSelectedState();
disenableMultiSelectedState();
activateButtons();
return true;
}
if (isEnabledSelectedState())
{
bool handlePicked = (pickHandle(x,y) != nullptr);
bool toggleMode = (_internal->_states.size() == 2);
bool eventHandled = false;
if (!toggleMode)
{
disenableSelectedState();
disenableMultiSelectedState();
chooseStateMenu();
return true;
}
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if ((handlePointPtr) && (handlePointPtr->isSelected()))
{
handlePointPtr->setSelection(false);
if ((handlePicked) && (toggleMode)) toggleState( handlePointPtr );
eventHandled = true;
}
}
disenableSelectedState();
disenableMultiSelectedState();
activateButtons();
return eventHandled;
}
else Rubberband::setCoordinateAction(causer,x,y);
}
return false;
} /* RubberbandStateSelect::setCoordinateAction */
bool RubberbandStateSelect::moveAction(AbstractEventDispatcher*, int x, int y)
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
if (rubberbandIsAlive())
{
if (_internal -> _stateMenuIsActive) return false;
bool eventHandled = false;
QPointF scenePosition(pixel2ScenePosition(x,y));
if (_baseInternal->buttonProxyActive(scenePosition)) return false;
if (Rubberband::_internal->_mapView != nullptr)
{
if (!isEnabledMultiSelectedState()) deSelectHandles();
RubberbandHandle * handlePtr = pickHandle(x,y);
if (handlePtr != nullptr)
{
handlePtr->setSelection();
eventHandled = true;
}
}
if (eventHandled) update();
}
return false;
} /* RubberbandStateSelect::moveAction */
bool RubberbandStateSelect::movePickedAction(AbstractEventDispatcher * causer, int x, int y )
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
Rubberband::movePickedAction(causer,x,y);
return false; // isEnabledSelectedState() || _internal->_stateMenuIsActive;
} /* RubberbandStateSelect::movePickedAction */
bool RubberbandStateSelect::contextMenuAction( AbstractEventDispatcher*, int, int )
{
if (!_internal -> _stateMenuIsActive) chooseStateMenu();
return true;
} /* RubberbandStateSelect::contextMenuAction */
void RubberbandStateSelect::onDo_areaSelectionBegin()
{
bool mRbands = _baseInternal->_map->rubberbandFactory().allowMultipleRubberbands();
_baseInternal->_map->rubberbandFactory().allowMultipleRubberbands(true);
{
RB::RubberbandMultiPointFeature * selectionRB = _baseInternal->_map->rubberbandFactory().create<RB::RubberbandMultiPointFeature>(this);
if (selectionRB == nullptr)
{
qWarning() << LOGFUNCTION << "Creating rubberband multi points feature failed";
}
else
{
selectionRB->setAutoDelete(true); // when finished rubberband will commit suicide
selectionRB->setDrawColor( QColor(255,0,0,255) );
selectionRB->setFillColor( QColor( 0,0,0,100) );
selectionRB -> enableClosed( true );
selectionRB -> enableFinishAfterConstruction( true );
selectionRB -> setFixedButtonBoxPosition(QPoint(15,15));
QObject::connect( selectionRB, &RB::Rubberband::apply, this, &RubberbandStateSelect::onDo_areaSelectionApply );
QObject::connect( selectionRB, &RB::Rubberband::abort, this, &RubberbandStateSelect::onDo_areaSelectionAbort );
RubberbandBase::_baseInternal->_buttonBox->setDisabled(true);
}
}
_baseInternal->_map->rubberbandFactory().allowMultipleRubberbands( mRbands );
} /* RubberbandStateSelect::onDo_areaSelectionBegin */
void RubberbandStateSelect::onDo_areaSelectionApply( RubberbandBase * selectionRB )
{
RubberbandBase::_baseInternal->_buttonBox->setEnabled(true);
if (selectionRB)
{
QVector<QPointF> polygonVertexList = selectionRB->coordinateVector( CoordinateSystem::Map );
// Looking for all handle which are inside polygon and select
unsigned int hitCounter = 0;
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if (handlePointPtr)
{
const Esri::ArcGISRuntime::Point &v = handlePointPtr->getCoordinate()._mapCoordinate;
bool inside = false;
int nvert = polygonVertexList.size();
for (int i = 0, j = nvert-1; i < nvert; j = i++)
{
const QPointF & vertex_i = polygonVertexList[i];
const QPointF & vertex_j = polygonVertexList[j];
if ((vertex_i.y()>v.y()) != (vertex_j.y()>v.y()))
{
if (v.x() < (vertex_j.x() - vertex_i.x()) * (v.y() - vertex_i.y()) / (vertex_j.y() - vertex_i.y()) + vertex_i.x())
{
inside = !inside;
}
}
}
if (inside)
{
hitCounter++;
handlePointPtr->setSelection();
}
}
}
if (hitCounter > 0)
{
if (_internal->_states.size() == 2)
{
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
if (!handle->isSelected()) continue;
handle->setSelection(false);
toggleState( dynamic_cast<RubberbandPointHandle*>(handle.get()) );
}
}
else
{
chooseStateMenu();
// ????? enableMultiSelectedState();
}
}
}
} /* RubberbandStateSelect::onDo_areaSelectionApply */
void RubberbandStateSelect::onDo_areaSelectionAbort( RubberbandBase * )
{
_baseInternal->_buttonBox->setEnabled(true);
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Really nothing else to do here?
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
} /* RubberbandStateSelect::onDo_areaSelectionAbort */
void RubberbandStateSelect::update()
{
Rubberband::update();
onDo_updateButtonFixCoordinates();
} /* RubberbandPointCluster::update */
} } /* namespace SituationMap::RB */