Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix offset curve: allow input in spinbox by switching to click-click …
…mode
  • Loading branch information
3nids committed May 6, 2015
1 parent a7a29ca commit 254af20
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 107 deletions.
206 changes: 109 additions & 97 deletions src/app/qgsmaptooloffsetcurve.cpp
Expand Up @@ -13,14 +13,15 @@
* *
***************************************************************************/

#include "qgsdoublespinbox.h"
#include "qgsmaptooloffsetcurve.h"
#include "qgsmapcanvas.h"
#include "qgsmaplayerregistry.h"
#include "qgsrubberband.h"
#include "qgssnappingutils.h"
#include "qgsvectorlayer.h"
#include "qgsvertexmarker.h"
#include <QDoubleSpinBox>

#include <QGraphicsProxyWidget>
#include <QMouseEvent>
#include "qgisapp.h"
Expand All @@ -31,8 +32,7 @@ QgsMapToolOffsetCurve::QgsMapToolOffsetCurve( QgsMapCanvas* canvas )
, mOriginalGeometry( 0 )
, mModifiedFeature( -1 )
, mGeometryModified( false )
, mDistanceItem( 0 )
, mDistanceSpinBox( 0 )
, mDistanceWidget( 0 )
, mSnapVertexMarker( 0 )
, mForceCopy( false )
, mMultiPartGeometry( false )
Expand All @@ -42,84 +42,105 @@ QgsMapToolOffsetCurve::QgsMapToolOffsetCurve( QgsMapCanvas* canvas )
QgsMapToolOffsetCurve::~QgsMapToolOffsetCurve()
{
deleteRubberBandAndGeometry();
deleteDistanceItem();
deleteDistanceWidget();
delete mSnapVertexMarker;
}

void QgsMapToolOffsetCurve::canvasPressEvent( QMouseEvent* e )
{
deleteRubberBandAndGeometry();
mGeometryModified = false;
mForceCopy = false;

void QgsMapToolOffsetCurve::canvasReleaseEvent( QMouseEvent * e )
{
if ( !mCanvas )
{
return;
}

//get selected features or snap to nearest feature if no selection
QgsVectorLayer* layer = currentVectorLayer();
if ( !layer )
{
deleteRubberBandAndGeometry();
notifyNotVectorLayer();
return;
}

QgsSnappingUtils* snapping = mCanvas->snappingUtils();
if ( e->button() == Qt::RightButton )
{
deleteRubberBandAndGeometry();
deleteDistanceWidget();
return;
}

if ( !mOriginalGeometry )
{
deleteRubberBandAndGeometry();
mGeometryModified = false;
mForceCopy = false;

// store previous settings
int oldType;
double oldSearchRadius;
QgsTolerance::UnitType oldSearchRadiusUnit;
QgsSnappingUtils::SnapToMapMode oldMode = snapping->snapToMapMode();
snapping->defaultSettings( oldType, oldSearchRadius, oldSearchRadiusUnit );
if ( e->button() == Qt::RightButton )
{
return;
}

// setup new settings (temporary)
QSettings settings;
snapping->setSnapToMapMode( QgsSnappingUtils::SnapAllLayers );
snapping->setDefaultSettings( QgsPointLocator::Edge,
settings.value( "/qgis/digitizing/search_radius_vertex_edit", 10 ).toDouble(),
( QgsTolerance::UnitType ) settings.value( "/qgis/digitizing/search_radius_vertex_edit_unit", QgsTolerance::Pixels ).toInt() );
QgsSnappingUtils* snapping = mCanvas->snappingUtils();

QgsPointLocator::Match match = snapping->snapToMap( e->pos() );
// store previous settings
int oldType;
double oldSearchRadius;
QgsTolerance::UnitType oldSearchRadiusUnit;
QgsSnappingUtils::SnapToMapMode oldMode = snapping->snapToMapMode();
snapping->defaultSettings( oldType, oldSearchRadius, oldSearchRadiusUnit );

// restore old settings
snapping->setSnapToMapMode( oldMode );
snapping->setDefaultSettings( oldType, oldSearchRadius, oldSearchRadiusUnit );
// setup new settings (temporary)
QSettings settings;
snapping->setSnapToMapMode( QgsSnappingUtils::SnapAllLayers );
snapping->setDefaultSettings( QgsPointLocator::Edge,
settings.value( "/qgis/digitizing/search_radius_vertex_edit", 10 ).toDouble(),
( QgsTolerance::UnitType ) settings.value( "/qgis/digitizing/search_radius_vertex_edit_unit", QgsTolerance::Pixels ).toInt() );

if ( match.hasEdge() && match.layer() )
{
mSourceLayerId = match.layer()->id();
QgsFeature fet;
if ( match.layer()->getFeatures( QgsFeatureRequest( match.featureId() ) ).nextFeature( fet ) )
QgsPointLocator::Match match = snapping->snapToMap( e->pos() );

// restore old settings
snapping->setSnapToMapMode( oldMode );
snapping->setDefaultSettings( oldType, oldSearchRadius, oldSearchRadiusUnit );

if ( match.hasEdge() && match.layer() )
{
mForceCopy = ( e->modifiers() & Qt::ControlModifier ); //no geometry modification if ctrl is pressed
mOriginalGeometry = createOriginGeometry( match.layer(), match, fet );
mRubberBand = createRubberBand();
if ( mRubberBand )
mSourceLayerId = match.layer()->id();
QgsFeature fet;
if ( match.layer()->getFeatures( QgsFeatureRequest( match.featureId() ) ).nextFeature( fet ) )
{
mRubberBand->setToGeometry( mOriginalGeometry, layer );
mForceCopy = ( e->modifiers() & Qt::ControlModifier ); //no geometry modification if ctrl is pressed
mOriginalGeometry = createOriginGeometry( match.layer(), match, fet );
mRubberBand = createRubberBand();
if ( mRubberBand )
{
mRubberBand->setToGeometry( mOriginalGeometry, layer );
}
mModifiedFeature = fet.id();
createDistanceWidget();
}
mModifiedFeature = fet.id();
createDistanceItem();
}
return;
}

applyOffset();
}

void QgsMapToolOffsetCurve::canvasReleaseEvent( QMouseEvent * e )
void QgsMapToolOffsetCurve::applyOffset()
{
Q_UNUSED( e );
QgsVectorLayer* vlayer = currentVectorLayer();
if ( !vlayer )
QgsVectorLayer* layer = currentVectorLayer();
if ( !layer )
{
deleteRubberBandAndGeometry();
notifyNotVectorLayer();
return;
}

// no modification
if ( !mGeometryModified )
{
deleteRubberBandAndGeometry();
vlayer->destroyEditCommand();
layer->destroyEditCommand();
deleteDistanceWidget();
return;
}

Expand All @@ -128,40 +149,40 @@ void QgsMapToolOffsetCurve::canvasReleaseEvent( QMouseEvent * e )
mModifiedGeometry.convertToMultiType();
}

vlayer->beginEditCommand( tr( "Offset curve" ) );
layer->beginEditCommand( tr( "Offset curve" ) );

bool editOk;
if ( mSourceLayerId == vlayer->id() && !mForceCopy )
if ( mSourceLayerId == layer->id() && !mForceCopy )
{
editOk = vlayer->changeGeometry( mModifiedFeature, &mModifiedGeometry );
editOk = layer->changeGeometry( mModifiedFeature, &mModifiedGeometry );
}
else
{
QgsFeature f;
f.setGeometry( mModifiedGeometry );

//add empty values for all fields (allows inserting attribute values via the feature form in the same session)
QgsAttributes attrs( vlayer->pendingFields().count() );
const QgsFields& fields = vlayer->pendingFields();
QgsAttributes attrs( layer->pendingFields().count() );
const QgsFields& fields = layer->pendingFields();
for ( int idx = 0; idx < fields.count(); ++idx )
{
attrs[idx] = QVariant();
}
f.setAttributes( attrs );
editOk = vlayer->addFeature( f );
editOk = layer->addFeature( f );
}

if ( editOk )
{
vlayer->endEditCommand();
layer->endEditCommand();
}
else
{
vlayer->destroyEditCommand();
layer->destroyEditCommand();
}

deleteRubberBandAndGeometry();
deleteDistanceItem();
deleteDistanceWidget();
delete mSnapVertexMarker; mSnapVertexMarker = 0;
mForceCopy = false;
mCanvas->refresh();
Expand All @@ -180,7 +201,7 @@ void QgsMapToolOffsetCurve::placeOffsetCurveToValue()
int beforeVertex;
mOriginalGeometry->closestSegmentWithContext( *firstPoint, minDistPoint, beforeVertex, &leftOf );
}
setOffsetForRubberBand( mDistanceSpinBox->value(), leftOf < 0 );
setOffsetForRubberBand( mDistanceWidget->value() );
}
}

Expand All @@ -200,11 +221,6 @@ void QgsMapToolOffsetCurve::canvasMoveEvent( QMouseEvent * e )
return;
}

if ( mDistanceItem )
{
mDistanceItem->show();
mDistanceItem->setPos( e->posF() + QPointF( 10, 10 ) );
}

mGeometryModified = true;

Expand Down Expand Up @@ -235,12 +251,17 @@ void QgsMapToolOffsetCurve::canvasMoveEvent( QMouseEvent * e )
return;
}

//create offset geometry using geos
setOffsetForRubberBand( offset, leftOf < 0 );

if ( mDistanceSpinBox )

if ( mDistanceWidget )
{
mDistanceWidget->setValue( leftOf < 0 ? offset : -offset );
mDistanceWidget->setFocus( Qt::TabFocusReason );
}
else
{
mDistanceSpinBox->setValue( offset );
//create offset geometry using geos
setOffsetForRubberBand( leftOf < 0 ? offset : -offset );
}
}

Expand Down Expand Up @@ -301,46 +322,38 @@ QgsGeometry* QgsMapToolOffsetCurve::createOriginGeometry( QgsVectorLayer* vl, co
}
}

void QgsMapToolOffsetCurve::createDistanceItem()
void QgsMapToolOffsetCurve::createDistanceWidget()
{
if ( !mCanvas )
{
return;
}

deleteDistanceItem();

mDistanceSpinBox = new QDoubleSpinBox();
mDistanceSpinBox->setMaximum( 99999999 );
mDistanceSpinBox->setDecimals( 2 );
mDistanceSpinBox->setPrefix( tr( "Offset: " ) );
#ifndef Q_OS_UNIX
mDistanceItem = new QGraphicsProxyWidget();
mDistanceItem->setWidget( mDistanceSpinBox );
mCanvas->scene()->addItem( mDistanceItem );
mDistanceItem->hide();
#else
mDistanceItem = 0;
QgisApp::instance()->statusBar()->addWidget( mDistanceSpinBox );
#endif
mDistanceSpinBox->setFocus( Qt::TabFocusReason );

QObject::connect( mDistanceSpinBox, SIGNAL( editingFinished() ), this, SLOT( placeOffsetCurveToValue() ) );
deleteDistanceWidget();

mDistanceWidget = new QgsDoubleSpinBox();
mDistanceWidget->setMinimum( -99999999 );
mDistanceWidget->setMaximum( 99999999 );
mDistanceWidget->setDecimals( 2 );
mDistanceWidget->setPrefix( tr( "Offset: " ) );
QgisApp::instance()->addUserInputWidget( mDistanceWidget );

mDistanceWidget->setFocus( Qt::TabFocusReason );

QObject::connect( mDistanceWidget, SIGNAL( valueChanged( double ) ), this, SLOT( placeOffsetCurveToValue() ) );
QObject::connect( mDistanceWidget, SIGNAL( editingFinished() ), this, SLOT( applyOffset() ) );
}

void QgsMapToolOffsetCurve::deleteDistanceItem()
void QgsMapToolOffsetCurve::deleteDistanceWidget()
{
if ( mDistanceSpinBox )
if ( mDistanceWidget )
{
mDistanceSpinBox->releaseKeyboard();
QObject::disconnect( mDistanceWidget, SIGNAL( valueChanged( double ) ), this, SLOT( placeOffsetCurveToValue() ) );
QObject::disconnect( mDistanceWidget, SIGNAL( editingFinished() ), this, SLOT( applyOffset() ) );
mDistanceWidget->releaseKeyboard();
mDistanceWidget->deleteLater();
}
delete mDistanceItem;
mDistanceItem = 0;
#ifdef Q_OS_UNIX
QgisApp::instance()->statusBar()->removeWidget( mDistanceSpinBox );
delete mDistanceSpinBox;
#endif
mDistanceSpinBox = 0;
mDistanceWidget = 0;
}

void QgsMapToolOffsetCurve::deleteRubberBandAndGeometry()
Expand All @@ -351,7 +364,7 @@ void QgsMapToolOffsetCurve::deleteRubberBandAndGeometry()
mOriginalGeometry = 0;
}

void QgsMapToolOffsetCurve::setOffsetForRubberBand( double offset, bool leftSide )
void QgsMapToolOffsetCurve::setOffsetForRubberBand( double offset )
{
// need at least geos 3.3 for OffsetCurve tool
#if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \
Expand All @@ -376,15 +389,15 @@ void QgsMapToolOffsetCurve::setOffsetForRubberBand( double offset, bool leftSide
int quadSegments = s.value( "/qgis/digitizing/offset_quad_seg", 8 ).toInt();
double mitreLimit = s.value( "/qgis/digitizing/offset_miter_limit", 5.0 ).toDouble();

GEOSGeometry* offsetGeom = GEOSOffsetCurve_r( QgsGeometry::getGEOSHandler(), geosGeom, leftSide ? offset : -offset, quadSegments, joinStyle, mitreLimit );
GEOSGeometry* offsetGeom = GEOSOffsetCurve_r( QgsGeometry::getGEOSHandler(), geosGeom, offset, quadSegments, joinStyle, mitreLimit );
if ( !offsetGeom )
{
deleteRubberBandAndGeometry();
deleteDistanceItem();
deleteDistanceWidget();
delete mSnapVertexMarker; mSnapVertexMarker = 0;
mForceCopy = false;
mGeometryModified = false;
deleteDistanceItem();
deleteDistanceWidget();
emit messageEmitted( tr( "Creating offset geometry failed" ), QgsMessageBar::CRITICAL );
return;
}
Expand All @@ -397,7 +410,6 @@ void QgsMapToolOffsetCurve::setOffsetForRubberBand( double offset, bool leftSide
}
#else //GEOS_VERSION>=3.3
Q_UNUSED( offset );
Q_UNUSED( leftSide );
#endif //GEOS_VERSION>=3.3
}

Expand Down

0 comments on commit 254af20

Please sign in to comment.