QgsLayerRestorer::QgsLayerRestorer( const QList<QgsMapLayer *> &layers ) { for ( QgsMapLayer *layer : layers ) { QgsLayerSettings settings; settings.name = layer->name(); QString style = layer->styleManager()->currentStyle(); settings.mNamedStyle = layer->styleManager()->currentStyle(); // set a custom property allowing to keep in memory if a SLD file has // been loaded for rendering layer->setCustomProperty( "readSLD", false ); QString errMsg; QDomDocument sldDoc; layer->exportSldStyle( sldDoc, errMsg ); ( void )settings.mSldStyle.setContent( sldDoc.toString(), true ); // for namespace processing switch ( layer->type() ) { case QgsMapLayer::VectorLayer: { QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer ); if ( vLayer ) { settings.mOpacity = vLayer->opacity(); settings.mSelectedFeatureIds = vLayer->selectedFeatureIds(); settings.mFilter = vLayer->subsetString(); } break; } case QgsMapLayer::LayerType::RasterLayer: { QgsRasterLayer *rLayer = qobject_cast<QgsRasterLayer *>( layer ); if ( rLayer ) { settings.mOpacity = rLayer->renderer()->opacity(); } break; } case QgsMapLayer::MeshLayer: case QgsMapLayer::PluginLayer: break; } mLayerSettings[layer] = settings; } }
void QgsMapToolSelectUtils::selectSingleFeature( QgsMapCanvas *canvas, const QgsGeometry &selectGeometry, Qt::KeyboardModifiers modifiers ) { QgsVectorLayer *vlayer = QgsMapToolSelectUtils::getCurrentVectorLayer( canvas ); if ( !vlayer ) return; QApplication::setOverrideCursor( Qt::WaitCursor ); QgsFeatureIds selectedFeatures = getMatchingFeatures( canvas, selectGeometry, false, true ); if ( selectedFeatures.isEmpty() ) { if ( !( modifiers & Qt::ShiftModifier || modifiers & Qt::ControlModifier ) ) { // if no modifiers then clicking outside features clears the selection // but if there's a shift or ctrl modifier, then it's likely the user was trying // to modify an existing selection by adding or subtracting features and just // missed the feature vlayer->removeSelection(); } QApplication::restoreOverrideCursor(); return; } QgsVectorLayer::SelectBehavior behavior = QgsVectorLayer::SetSelection; //either shift or control modifier switches to "toggle" selection mode if ( modifiers & Qt::ShiftModifier || modifiers & Qt::ControlModifier ) { QgsFeatureId selectId = *selectedFeatures.constBegin(); QgsFeatureIds layerSelectedFeatures = vlayer->selectedFeatureIds(); if ( layerSelectedFeatures.contains( selectId ) ) behavior = QgsVectorLayer::RemoveFromSelection; else behavior = QgsVectorLayer::AddToSelection; } vlayer->selectByIds( selectedFeatures, behavior ); QApplication::restoreOverrideCursor(); }
void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e ) { if ( !mCanvas ) { return; } QgsVectorLayer *vlayer = currentVectorLayer(); if ( !vlayer ) { deleteRotationWidget(); deleteRubberband(); notifyNotVectorLayer(); return; } if ( e->button() == Qt::RightButton ) { cancel(); return; } // place anchor point on CTRL + click if ( e->modifiers() & Qt::ControlModifier ) { if ( !mAnchorPoint ) { return; } mAnchorPoint->setCenter( toMapCoordinates( e->pos() ) ); mStartPointMapCoords = toMapCoordinates( e->pos() ); mStPoint = e->pos(); return; } deleteRotationWidget(); // Initialize rotation if not yet active if ( !mRotationActive ) { mRotation = 0; mRotationOffset = 0; deleteRubberband(); mInitialPos = e->pos(); if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } QgsPointXY layerCoords = toLayerCoordinates( vlayer, e->pos() ); double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() ); QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius, layerCoords.x() + searchRadius, layerCoords.y() + searchRadius ); if ( vlayer->selectedFeatureCount() == 0 ) { QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ).setNoAttributes() ); //find the closest feature QgsGeometry pointGeometry = QgsGeometry::fromPointXY( layerCoords ); if ( pointGeometry.isNull() ) { return; } double minDistance = std::numeric_limits<double>::max(); QgsFeature cf; QgsFeature f; while ( fit.nextFeature( f ) ) { if ( f.hasGeometry() ) { double currentDistance = pointGeometry.distance( f.geometry() ); if ( currentDistance < minDistance ) { minDistance = currentDistance; cf = f; } } } if ( minDistance == std::numeric_limits<double>::max() ) { emit messageEmitted( tr( "Could not find a nearby feature in the current layer." ) ); return; } QgsRectangle bound = cf.geometry().boundingBox(); mStartPointMapCoords = toMapCoordinates( vlayer, bound.center() ); if ( !mAnchorPoint ) { mAnchorPoint = qgis::make_unique<QgsVertexMarker>( mCanvas ); } mAnchorPoint->setIconType( QgsVertexMarker::ICON_CROSS ); mAnchorPoint->setCenter( mStartPointMapCoords ); mStPoint = toCanvasCoordinates( mStartPointMapCoords ); mRotatedFeatures.clear(); mRotatedFeatures << cf.id(); //todo: take the closest feature, not the first one... mRubberBand = createRubberBand( vlayer->geometryType() ); mRubberBand->setToGeometry( cf.geometry(), vlayer ); } else { mRotatedFeatures = vlayer->selectedFeatureIds(); mRubberBand = createRubberBand( vlayer->geometryType() ); QgsFeature feat; QgsFeatureIterator it = vlayer->getSelectedFeatures(); while ( it.nextFeature( feat ) ) { mRubberBand->addGeometry( feat.geometry(), vlayer ); } } mRubberBand->show(); double XDistance = mInitialPos.x() - mAnchorPoint->x(); double YDistance = mInitialPos.y() - mAnchorPoint->y(); mRotationOffset = std::atan2( YDistance, XDistance ) * ( 180 / M_PI ); createRotationWidget(); if ( e->modifiers() & Qt::ShiftModifier ) { if ( mRotationWidget ) { mRotationWidget->setMagnet( 45 ); } } mRotationActive = true; return; } applyRotation( mRotation ); }
void QgsMapToolMoveFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) { QgsVectorLayer *vlayer = currentVectorLayer(); if ( !vlayer || !vlayer->isEditable() ) { delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); cadDockWidget()->clear(); notifyNotEditableLayer(); return; } if ( !mRubberBand ) { //find first geometry under mouse cursor and store iterator to it QgsPointXY layerCoords = toLayerCoordinates( vlayer, e->mapPoint() ); double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() ); QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius, layerCoords.x() + searchRadius, layerCoords.y() + searchRadius ); if ( vlayer->selectedFeatureCount() == 0 ) { QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ).setNoAttributes() ); //find the closest feature QgsGeometry pointGeometry = QgsGeometry::fromPointXY( layerCoords ); if ( pointGeometry.isNull() ) { cadDockWidget()->clear(); return; } double minDistance = std::numeric_limits<double>::max(); QgsFeature cf; QgsFeature f; while ( fit.nextFeature( f ) ) { if ( f.hasGeometry() ) { double currentDistance = pointGeometry.distance( f.geometry() ); if ( currentDistance < minDistance ) { minDistance = currentDistance; cf = f; } } } if ( minDistance == std::numeric_limits<double>::max() ) { cadDockWidget()->clear(); return; } mMovedFeatures.clear(); mMovedFeatures << cf.id(); //todo: take the closest feature, not the first one... mRubberBand = createRubberBand( vlayer->geometryType() ); mRubberBand->setToGeometry( cf.geometry(), vlayer ); } else { mMovedFeatures = vlayer->selectedFeatureIds(); mRubberBand = createRubberBand( vlayer->geometryType() ); QgsFeature feat; QgsFeatureIterator it = vlayer->getSelectedFeatures( QgsFeatureRequest().setNoAttributes() ); bool allFeaturesInView = true; QgsRectangle viewRect = mCanvas->mapSettings().mapToLayerCoordinates( vlayer, mCanvas->extent() ); while ( it.nextFeature( feat ) ) { mRubberBand->addGeometry( feat.geometry(), vlayer ); if ( allFeaturesInView && !viewRect.intersects( feat.geometry().boundingBox() ) ) allFeaturesInView = false; } if ( !allFeaturesInView ) { // for extra safety to make sure we are not modifying geometries by accident int res = QMessageBox::warning( mCanvas, tr( "Move features" ), tr( "Some of the selected features are outside of the current map view. Would you still like to continue?" ), QMessageBox::Yes | QMessageBox::No ); if ( res != QMessageBox::Yes ) { mMovedFeatures.clear(); delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); return; } } } mStartPointMapCoords = e->mapPoint(); mRubberBand->show(); } else { // copy and move mode if ( e->button() != Qt::LeftButton ) { cadDockWidget()->clear(); delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); return; } QgsPointXY startPointLayerCoords = toLayerCoordinates( ( QgsMapLayer * )vlayer, mStartPointMapCoords ); QgsPointXY stopPointLayerCoords = toLayerCoordinates( ( QgsMapLayer * )vlayer, e->mapPoint() ); double dx = stopPointLayerCoords.x() - startPointLayerCoords.x(); double dy = stopPointLayerCoords.y() - startPointLayerCoords.y(); vlayer->beginEditCommand( mMode == Move ? tr( "Feature moved" ) : tr( "Feature copied and moved" ) ); switch ( mMode ) { case Move: Q_FOREACH ( QgsFeatureId id, mMovedFeatures ) { vlayer->translateFeature( id, dx, dy ); } delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); cadDockWidget()->clear(); break; case CopyMove: QgsFeatureRequest request; request.setFilterFids( mMovedFeatures ); QString *errorMsg = new QString(); if ( !QgisApp::instance()->vectorLayerTools()->copyMoveFeatures( vlayer, request, dx, dy, errorMsg ) ) { emit messageEmitted( *errorMsg, Qgis::Critical ); delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); } break; } vlayer->endEditCommand(); vlayer->triggerRepaint(); }