Skip to content

Commit

Permalink
[FEATURE] add multiple features at once (implements #2710)
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.osgeo.org/qgis/trunk@13505 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
jef committed May 16, 2010
1 parent bd021cc commit e03e5a1
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 77 deletions.
15 changes: 15 additions & 0 deletions python/gui/qgsrubberband.sip
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,24 @@ class QgsRubberBand: QgsMapCanvasItem
@param render the maprender object (used for coord transformation)*/
void setToGeometry(QgsGeometry* geom, QgsVectorLayer* layer);

/**Add the geometry of an existing feature to the rubberband.
This is useful for multi feature highlighting.
@param geom the geometry object
@param layer the layer containing the feature, used for coord transformation to map
crs. In case of 0 pointer, the coordinates are not going to be transformed.
@param render the maprender object (used for coord transformation)
@added in 1.5
*/
void addGeometry(QgsGeometry* geom, QgsVectorLayer* layer);

/**Adds translation to original coordinates (all in map coordinates)*/
void setTranslationOffset(double dx, double dy);

/**Return number of geometries
@added in 1.5
*/
int size();

/**Returns count of vertices in all lists of mPoint*/
int numberOfVertices() const;

Expand Down
27 changes: 12 additions & 15 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,9 +754,9 @@ void QgisApp::createActions()
connect( mActionCapturePolygon, SIGNAL( triggered() ), this, SLOT( capturePolygon() ) );
mActionCapturePolygon->setEnabled( false );

mActionMoveFeature = new QAction( getThemeIcon( "mActionMoveFeature.png" ), tr( "Move Feature" ), this );
mActionMoveFeature = new QAction( getThemeIcon( "mActionMoveFeature.png" ), tr( "Move Feature(s)" ), this );
shortcuts->registerAction( mActionMoveFeature );
mActionMoveFeature->setStatusTip( tr( "Move Feature" ) );
mActionMoveFeature->setStatusTip( tr( "Move Feature(s)" ) );
connect( mActionMoveFeature, SIGNAL( triggered() ), this, SLOT( moveFeature() ) );
mActionMoveFeature->setEnabled( false );

Expand Down Expand Up @@ -4645,24 +4645,21 @@ void QgisApp::layerSubsetString()

bool QgisApp::toggleEditing( QgsMapLayer *layer, bool allowCancel )
{
if ( !layer )
{
return false;
}

QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
if ( !vlayer )
{
return false;
}

bool res = true;

if ( !vlayer->isEditable() )
{
vlayer->startEditing();
if ( !( vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::EditingCapabilities ) )
{
QMessageBox::information( 0, tr( "Start editing failed" ), tr( "Provider cannot be opened for editing" ) );
return false;
res = false;
}
}
else if ( vlayer->isModified() )
Expand All @@ -4677,8 +4674,8 @@ bool QgisApp::toggleEditing( QgsMapLayer *layer, bool allowCancel )
buttons ) )
{
case QMessageBox::Cancel:
mActionToggleEditing->setChecked( vlayer->isEditable() );
return false;
res = false;
break;

case QMessageBox::Save:
if ( !vlayer->commitChanges() )
Expand All @@ -4691,15 +4688,15 @@ bool QgisApp::toggleEditing( QgsMapLayer *layer, bool allowCancel )
// Leave the in-memory editing state alone,
// to give the user a chance to enter different values
// and try the commit again later
return false;
res = false;
}
break;

case QMessageBox::Discard:
if ( !vlayer->rollBack() )
{
QMessageBox::information( 0, tr( "Error" ), tr( "Problems during roll back" ) );
return false;
res = false;
}
break;

Expand All @@ -4710,17 +4707,17 @@ bool QgisApp::toggleEditing( QgsMapLayer *layer, bool allowCancel )
else //layer not modified
{
vlayer->rollBack();
res = true;
}

if ( layer == activeLayer() )
{
activateDeactivateLayerRelatedActions( layer );
}

//ensure the toolbar icon state is consistent with the layer editing state
mActionToggleEditing->setChecked( vlayer->isEditable() );
vlayer->triggerRepaint();
return true;

return res;
}

void QgisApp::showMouseCoordinate( const QgsPoint & p )
Expand Down
72 changes: 46 additions & 26 deletions src/app/qgsmaptoolmovefeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ void QgsMapToolMoveFeature::canvasMoveEvent( QMouseEvent * e )
double offsetX = pointCanvasCoords.x() - mStartPointMapCoords.x();
double offsetY = pointCanvasCoords.y() - mStartPointMapCoords.y();
mRubberBand->setTranslationOffset( offsetX, offsetY );
//QgsDebugMsg("move Rubber band by: " + QString::number(e->x() - mLastPointPixelCoords.x()) + " // " + QString::number(e->y() - mLastPointPixelCoords.y()));
mRubberBand->updatePosition();
mRubberBand->update();
}
Expand Down Expand Up @@ -76,46 +75,64 @@ void QgsMapToolMoveFeature::canvasPressEvent( QMouseEvent * e )
QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius,
layerCoords.x() + searchRadius, layerCoords.y() + searchRadius );

vlayer->select( QgsAttributeList(), selectRect, true );

//find the closest feature
QgsGeometry* pointGeometry = QgsGeometry::fromPoint( layerCoords );
if ( !pointGeometry )
if ( vlayer->selectedFeatureCount() == 0 )
{
return;
}
vlayer->select( QgsAttributeList(), selectRect, true );

double minDistance = std::numeric_limits<double>::max();
//find the closest feature
QgsGeometry* pointGeometry = QgsGeometry::fromPoint( layerCoords );
if ( !pointGeometry )
{
return;
}

QgsFeature cf;
QgsFeature f;
while ( vlayer->nextFeature( f ) )
{
if ( f.geometry() )
double minDistance = std::numeric_limits<double>::max();

QgsFeature cf;
QgsFeature f;
while ( vlayer->nextFeature( f ) )
{
double currentDistance = pointGeometry->distance( *f.geometry() );
if ( currentDistance < minDistance )
if ( f.geometry() )
{
minDistance = currentDistance;
cf = f;
double currentDistance = pointGeometry->distance( *f.geometry() );
if ( currentDistance < minDistance )
{
minDistance = currentDistance;
cf = f;
}
}

}
}

if ( minDistance == std::numeric_limits<double>::max() )
delete pointGeometry;

if ( minDistance == std::numeric_limits<double>::max() )
{
return;
}

mMovedFeatures.clear();
mMovedFeatures << cf.id(); //todo: take the closest feature, not the first one...

mRubberBand = createRubberBand();
mRubberBand->setToGeometry( cf.geometry(), vlayer );
}
else
{
return;
mMovedFeatures = vlayer->selectedFeaturesIds();

mRubberBand = createRubberBand();
for ( int i = 0; i < vlayer->selectedFeatureCount(); i++ )
{
mRubberBand->addGeometry( vlayer->selectedFeatures()[i].geometry(), vlayer );
}
}

mStartPointMapCoords = toMapCoordinates( e->pos() );
mMovedFeature = cf.id(); //todo: take the closest feature, not the first one...
mRubberBand = createRubberBand();
mRubberBand->setToGeometry( cf.geometry(), vlayer );
mRubberBand->setColor( Qt::red );
mRubberBand->setWidth( 2 );
mRubberBand->show();

delete pointGeometry;
}

void QgsMapToolMoveFeature::canvasReleaseEvent( QMouseEvent * e )
Expand All @@ -138,7 +155,10 @@ void QgsMapToolMoveFeature::canvasReleaseEvent( QMouseEvent * e )
double dx = stopPointLayerCoords.x() - startPointLayerCoords.x();
double dy = stopPointLayerCoords.y() - startPointLayerCoords.y();
vlayer->beginEditCommand( tr( "Feature moved" ) );
vlayer->translateFeature( mMovedFeature, dx, dy );
foreach( int id, mMovedFeatures )
{
vlayer->translateFeature( id, dx, dy );
}
delete mRubberBand;
mRubberBand = 0;
mCanvas->refresh();
Expand Down
3 changes: 2 additions & 1 deletion src/app/qgsmaptoolmovefeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define QGSMAPTOOLMOVEFEATURE_H

#include "qgsmaptooledit.h"
#include "qgsvectorlayer.h"

/**Map tool for translating feature position by mouse drag*/
class QgsMapToolMoveFeature: public QgsMapToolEdit
Expand All @@ -44,7 +45,7 @@ class QgsMapToolMoveFeature: public QgsMapToolEdit
QgsRubberBand* mRubberBand;

/**Id of moved feature*/
int mMovedFeature;
QgsFeatureIds mMovedFeatures;
};

#endif
Loading

0 comments on commit e03e5a1

Please sign in to comment.