From 254af203cc4acf868af69318510d863c73571a9e Mon Sep 17 00:00:00 2001 From: Denis Rouzaud Date: Mon, 27 Apr 2015 08:52:17 +0200 Subject: [PATCH] fix offset curve: allow input in spinbox by switching to click-click mode --- src/app/qgsmaptooloffsetcurve.cpp | 206 ++++++++++++++++-------------- src/app/qgsmaptooloffsetcurve.h | 19 ++- 2 files changed, 118 insertions(+), 107 deletions(-) diff --git a/src/app/qgsmaptooloffsetcurve.cpp b/src/app/qgsmaptooloffsetcurve.cpp index afc44581b56d..4309ae801c5b 100644 --- a/src/app/qgsmaptooloffsetcurve.cpp +++ b/src/app/qgsmaptooloffsetcurve.cpp @@ -13,6 +13,7 @@ * * ***************************************************************************/ +#include "qgsdoublespinbox.h" #include "qgsmaptooloffsetcurve.h" #include "qgsmapcanvas.h" #include "qgsmaplayerregistry.h" @@ -20,7 +21,7 @@ #include "qgssnappingutils.h" #include "qgsvectorlayer.h" #include "qgsvertexmarker.h" -#include + #include #include #include "qgisapp.h" @@ -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 ) @@ -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; } @@ -128,12 +149,12 @@ 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 { @@ -141,27 +162,27 @@ void QgsMapToolOffsetCurve::canvasReleaseEvent( QMouseEvent * e ) 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(); @@ -180,7 +201,7 @@ void QgsMapToolOffsetCurve::placeOffsetCurveToValue() int beforeVertex; mOriginalGeometry->closestSegmentWithContext( *firstPoint, minDistPoint, beforeVertex, &leftOf ); } - setOffsetForRubberBand( mDistanceSpinBox->value(), leftOf < 0 ); + setOffsetForRubberBand( mDistanceWidget->value() ); } } @@ -200,11 +221,6 @@ void QgsMapToolOffsetCurve::canvasMoveEvent( QMouseEvent * e ) return; } - if ( mDistanceItem ) - { - mDistanceItem->show(); - mDistanceItem->setPos( e->posF() + QPointF( 10, 10 ) ); - } mGeometryModified = true; @@ -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 ); } } @@ -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() @@ -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) && \ @@ -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; } @@ -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 } diff --git a/src/app/qgsmaptooloffsetcurve.h b/src/app/qgsmaptooloffsetcurve.h index f039f5fc863b..1a45d68e5c0c 100644 --- a/src/app/qgsmaptooloffsetcurve.h +++ b/src/app/qgsmaptooloffsetcurve.h @@ -21,7 +21,7 @@ #include "qgspointlocator.h" class QgsVertexMarker; -class QDoubleSpinBox; +class QgsDoubleSpinBox; class QGraphicsProxyWidget; class APP_EXPORT QgsMapToolOffsetCurve: public QgsMapToolEdit @@ -31,16 +31,17 @@ class APP_EXPORT QgsMapToolOffsetCurve: public QgsMapToolEdit QgsMapToolOffsetCurve( QgsMapCanvas* canvas ); ~QgsMapToolOffsetCurve(); - void canvasPressEvent( QMouseEvent * e ) override; void canvasReleaseEvent( QMouseEvent * e ) override; void canvasMoveEvent( QMouseEvent * e ) override; private slots: - /**Places curve offset to value entered in the spin box*/ + /** Places curve offset to value entered in the spin box*/ void placeOffsetCurveToValue(); - private: + /** Apply the offset either from the spin box or from the mouse event */ + void applyOffset(); + private: /**Rubberband that shows the position of the offset curve*/ QgsRubberBand* mRubberBand; /**Geometry to manipulate*/ @@ -53,10 +54,8 @@ class APP_EXPORT QgsMapToolOffsetCurve: public QgsMapToolEdit QString mSourceLayerId; /**Internal flag to distinguish move from click*/ bool mGeometryModified; - /**Embedded item widget for distance spinbox*/ - QGraphicsProxyWidget* mDistanceItem; /**Shows current distance value and allows numerical editing*/ - QDoubleSpinBox* mDistanceSpinBox; + QgsDoubleSpinBox* mDistanceWidget; /**Marker to show the cursor was snapped to another location*/ QgsVertexMarker* mSnapVertexMarker; /**Forces geometry copy (no modification of geometry in current layer)*/ @@ -66,9 +65,9 @@ class APP_EXPORT QgsMapToolOffsetCurve: public QgsMapToolEdit void deleteRubberBandAndGeometry(); QgsGeometry* createOriginGeometry( QgsVectorLayer* vl, const QgsPointLocator::Match& match, QgsFeature& snappedFeature ); - void createDistanceItem(); - void deleteDistanceItem(); - void setOffsetForRubberBand( double offset, bool leftSide ); + void createDistanceWidget(); + void deleteDistanceWidget(); + void setOffsetForRubberBand( double offset ); /**Creates a linestring from the polygon ring containing the snapped vertex. Caller takes ownership of the created object*/ QgsGeometry* linestringFromPolygon( QgsGeometry* featureGeom, int vertex ); /**Returns a single line from a multiline (or does nothing if geometry is already a single line). Deletes the input geometry*/