Skip to content
Permalink
Browse files
Integrate node editor from the old node tool
When right-clicking on a feature, a popup menu will be shown
and it is possible to open node editor dock widget for that particular
feature to edit coordinates numerically or to delete vertices.
  • Loading branch information
wonder-sk committed Apr 6, 2017
1 parent 61ace1c commit d1f23e97b7b0310a56c52752dd66a5738282ad36
Showing with 109 additions and 1 deletion.
  1. +94 −0 src/app/nodetool/qgsnodetool2.cpp
  2. +15 −1 src/app/nodetool/qgsnodetool2.h
@@ -29,8 +29,15 @@
#include "qgsvectorlayer.h"
#include "qgsvertexmarker.h"

#include "qgisapp.h"
#include "qgsselectedfeature.h"
#include "qgsnodeeditor.h"
#include "qgsvertexentry.h"

#include <QMenu>
#include <QRubberBand>


uint qHash( const Vertex &v )
{
return qHash( v.layer ) ^ qHash( v.fid ) ^ qHash( v.vertexId );
@@ -225,6 +232,7 @@ void QgsNodeTool2::deactivate()
{
setHighlightedNodes( QList<Vertex>() );
removeTemporaryRubberBands();
cleanupNodeEditor();
QgsMapToolAdvancedDigitizing::deactivate();
}

@@ -300,6 +308,8 @@ void QgsNodeTool2::clearDragBands()

void QgsNodeTool2::cadCanvasPressEvent( QgsMapMouseEvent *e )
{
cleanupNodeEditor();

if ( !mDraggingVertex && !mSelectedNodes.isEmpty() )
{
// only remove highlight if not clicked on one of highlighted nodes
@@ -339,6 +349,20 @@ void QgsNodeTool2::cadCanvasPressEvent( QgsMapMouseEvent *e )
if ( !mDraggingVertex && !mDraggingEdge )
mSelectionRectStartPos.reset( new QPoint( e->pos() ) );
}

if ( e->button() == Qt::RightButton )
{
if ( !mSelectionRect && !mDraggingVertex && !mDraggingEdge )
{
// show popup menu - if we are on top of a feature
if ( mLastMouseMoveMatch.isValid() && mLastMouseMoveMatch.layer() )
{
QMenu menu;
menu.addAction( "Node editor", this, &QgsNodeTool2::showNodeEditor );
menu.exec( mCanvas->mapToGlobal( e->pos() ) );
}
}
}
}

void QgsNodeTool2::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
@@ -645,6 +669,8 @@ void QgsNodeTool2::mouseMoveNotDragging( QgsMapMouseEvent *e )
// do not use snap from mouse event, use our own with any editable layer
QgsPointLocator::Match m = snapToEditableLayer( e );

mLastMouseMoveMatch = m;

// possibility to move a node
if ( m.type() == QgsPointLocator::Vertex )
{
@@ -827,6 +853,74 @@ void QgsNodeTool2::onCachedGeometryDeleted( QgsFeatureId fid )
layerCache.remove( fid );
}


void QgsNodeTool2::showNodeEditor()
{
QgsPointLocator::Match m = mLastMouseMoveMatch;
if ( !m.isValid() || !m.layer() )
return;

mSelectedFeature.reset( new QgsSelectedFeature( m.featureId(), m.layer(), mCanvas ) );
mNodeEditor.reset( new QgsNodeEditor( m.layer(), mSelectedFeature.get(), mCanvas ) );
QgisApp::instance()->addDockWidget( Qt::LeftDockWidgetArea, mNodeEditor.get() );
connect( mNodeEditor.get(), &QgsNodeEditor::deleteSelectedRequested, this, &QgsNodeTool2::deleteNodeEditorSelection );
}

void QgsNodeTool2::cleanupNodeEditor()
{
mSelectedFeature.reset();
mNodeEditor.reset();
}

static int _firstSelectedVertex( QgsSelectedFeature &selectedFeature )
{
QList<QgsVertexEntry *> &vertexMap = selectedFeature.vertexMap();
for ( int i = 0, n = vertexMap.size(); i < n; ++i )
{
if ( vertexMap[i]->isSelected() )
{
return i;
}
}
return -1;
}

static void _safeSelectVertex( QgsSelectedFeature &selectedFeature, int vertexNr )
{
int n = selectedFeature.vertexMap().size();
selectedFeature.selectVertex( ( vertexNr + n ) % n );
}

void QgsNodeTool2::deleteNodeEditorSelection()
{
if ( !mSelectedFeature )
return;

int firstSelectedIndex = _firstSelectedVertex( *mSelectedFeature );
if ( firstSelectedIndex == -1 )
return;

mSelectedFeature->deleteSelectedVertexes();

if ( mSelectedFeature->geometry()->isNull() )
{
emit messageEmitted( tr( "Geometry has been cleared. Use the add part tool to set geometry for this feature." ) );
}
else
{
int nextVertexToSelect = firstSelectedIndex;
if ( mSelectedFeature->geometry()->type() == QgsWkbTypes::LineGeometry )
{
// for lines we don't wrap around vertex selection when deleting nodes from end of line
nextVertexToSelect = qMin( nextVertexToSelect, mSelectedFeature->geometry()->geometry()->nCoordinates() - 1 );
}

_safeSelectVertex( *mSelectedFeature, nextVertexToSelect );
}
mSelectedFeature->vlayer()->triggerRepaint();
}


void QgsNodeTool2::startDragging( QgsMapMouseEvent *e )
{
QgsPoint mapPoint = toMapCoordinates( e->pos() );
@@ -23,9 +23,10 @@

class QRubberBand;

class QgsNodeEditor;
class QgsSelectedFeature;
class QgsVertexMarker;


//! helper structure for a vertex being dragged
struct Vertex
{
@@ -83,6 +84,9 @@ class APP_EXPORT QgsNodeTool2 : public QgsMapToolAdvancedDigitizing

void onCachedGeometryDeleted( QgsFeatureId fid );

void showNodeEditor();

void deleteNodeEditorSelection();

private:

@@ -172,6 +176,7 @@ class APP_EXPORT QgsNodeTool2 : public QgsMapToolAdvancedDigitizing
//! center of the edge and whether we are close enough to the center
bool matchEdgeCenterTest( const QgsPointLocator::Match &m, const QgsPoint &mapPoint, QgsPoint *edgeCenterPtr = nullptr );

void cleanupNodeEditor();

private:

@@ -291,6 +296,15 @@ class APP_EXPORT QgsNodeTool2 : public QgsMapToolAdvancedDigitizing

//! Geometry cache for fast access to geometries
QHash<const QgsVectorLayer *, QHash<QgsFeatureId, QgsGeometry> > mCache;

// support for node editor

//! most recent match when moving mouse
QgsPointLocator::Match mLastMouseMoveMatch;
//! Selected feature for the node editor
std::unique_ptr<QgsSelectedFeature> mSelectedFeature;
//! Dock widget which allows editing vertices
std::unique_ptr<QgsNodeEditor> mNodeEditor;
};


0 comments on commit d1f23e9

Please sign in to comment.