QgsFeatureList QgsClipboard::stringToFeatureList( const QString &string, const QgsFields &fields ) const { //first try using OGR to read string QgsFeatureList features = QgsOgrUtils::stringToFeatureList( string, fields, QTextCodec::codecForName( "System" ) ); if ( !features.isEmpty() ) return features; // otherwise try to read in as WKT QStringList values = string.split( '\n' ); if ( values.isEmpty() || string.isEmpty() ) return features; Q_FOREACH ( const QString &row, values ) { // Assume that it's just WKT for now. QgsGeometry geometry = QgsGeometry::fromWkt( row ); if ( geometry.isNull() ) continue; QgsFeature feature; if ( !fields.isEmpty() ) feature.setFields( fields, true ); feature.setGeometry( geometry ); features.append( feature ); }
QgsFeatureList QgsClipboard::copyOf( const QgsFields &fields ) { QgsDebugMsg( "returning clipboard." ); if ( !mUseSystemClipboard ) return mFeatureClipboard; QClipboard *cb = QApplication::clipboard(); #ifndef Q_OS_WIN QString text = cb->text( QClipboard::Selection ); #else QString text = cb->text( QClipboard::Clipboard ); #endif QStringList values = text.split( "\n" ); if ( values.isEmpty() || text.isEmpty() ) return mFeatureClipboard; QgsFeatureList features; foreach ( QString row, values ) { // Assume that it's just WKT for now. QgsGeometry* geometry = QgsGeometry::fromWkt( row ); if ( !geometry ) continue; QgsFeature* feature = new QgsFeature(); if ( !fields.isEmpty() ) feature->setFields( &fields, true ); feature->setGeometry( geometry ); features.append( QgsFeature( *feature ) ); }
QgsGeometry* QgsMapToolOffsetCurve::createOriginGeometry( QgsVectorLayer* vl, const QgsPointLocator::Match& match, QgsFeature& snappedFeature ) { if ( !vl ) { return 0; } mMultiPartGeometry = false; //assign feature part by vertex number (snap to vertex) or by before vertex number (snap to segment) int partVertexNr = match.vertexIndex(); if ( vl == currentVectorLayer() && !mForceCopy ) { //don't consider selected geometries, only the snap result return convertToSingleLine( snappedFeature.geometryAndOwnership(), partVertexNr, mMultiPartGeometry ); } else //snapped to a background layer { //if source layer is polygon / multipolygon, create a linestring from the snapped ring if ( vl->geometryType() == QGis::Polygon ) { //make linestring from polygon ring and return this geometry return linestringFromPolygon( snappedFeature.geometry(), partVertexNr ); } //for background layers, try to merge selected entries together if snapped feature is contained in selection const QgsFeatureIds& selection = vl->selectedFeaturesIds(); if ( selection.size() < 1 || !selection.contains( match.featureId() ) ) { return convertToSingleLine( snappedFeature.geometryAndOwnership(), partVertexNr, mMultiPartGeometry ); } else { //merge together if several features QgsFeatureList selectedFeatures = vl->selectedFeatures(); QgsFeatureList::iterator selIt = selectedFeatures.begin(); QgsGeometry* geom = selIt->geometryAndOwnership(); ++selIt; for ( ; selIt != selectedFeatures.end(); ++selIt ) { QgsGeometry* combined = geom->combine( selIt->geometry() ); delete geom; geom = combined; } //if multitype, return only the snapped to geometry if ( geom->isMultipart() ) { delete geom; return convertToSingleLine( snappedFeature.geometryAndOwnership(), match.vertexIndex(), mMultiPartGeometry ); } return geom; } } }
bool QgsVectorLayerExporter::addFeatures( QgsFeatureList &features, Flags flags ) { QgsFeatureList::iterator fIt = features.begin(); bool result = true; for ( ; fIt != features.end(); ++fIt ) { result = result && addFeature( *fIt, flags ); } return result; }
bool QgsSpatialIndex::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags ) { QgsFeatureList::iterator fIt = features.begin(); bool result = true; for ( ; fIt != features.end(); ++fIt ) { result = result && addFeature( *fIt, flags ); } return result; }
QgsFeatureList QgsClipboard::transformedCopyOf( QgsCoordinateReferenceSystem destCRS ) { QgsFeatureList featureList = copyOf(); QgsCoordinateTransform ct( crs(), destCRS ); QgsDebugMsg( "transforming clipboard." ); for ( QgsFeatureList::iterator iter = featureList.begin(); iter != featureList.end(); ++iter ) { iter->geometry()->transform( ct ); } return featureList; }
bool QgsVectorLayerEditBuffer::addFeatures( QgsFeatureList& features ) { if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures ) ) return false; for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter ) { addFeature( *iter ); } L->updateExtents(); return true; }
bool QgsVectorLayerEditPassthrough::addFeature( QgsFeature& f ) { QgsFeatureList fl; fl << f; if ( L->dataProvider()->addFeatures( fl ) ) { f = fl.first(); emit featureAdded( f.id() ); mModified = true; return true; } return false; }
void OptMapToolDeleteLink::deleteSelected( QgsVectorLayer *layer ) { if ( !( layer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteFeatures ) ) { QMessageBox::information( 0, tr( "Provider does not support deletion" ), tr( "Data provider does not support deleting features" ) ); return; } if ( !layer->isEditable() ) { QMessageBox::information( 0, tr( "Layer not editable" ), tr( "The current layer is not editable. Choose 'Start editing' in the digitizing toolbar." ) ); return; } //display a warning int numberOfDeletedFeatures = layer->selectedFeaturesIds().size(); if ( QMessageBox::warning( 0, tr( "Delete features" ), tr( "Delete %n feature(s)?", "number of features to delete", numberOfDeletedFeatures ), QMessageBox::Ok, QMessageBox::Cancel ) == QMessageBox::Cancel ) { return; } //change the endpoint connected information and deleted endpoints if necessary QgsFeatureList features = layer->selectedFeatures(); OptFeature selectedFeature; if ( features.count() > 0) selectedFeature = features[0]; if ( !selectedFeature.isValid() ) return; //selectedFeature. //OptFeature feature; //lineLayer->getFeatureAtId_(lineID, feature); //lineLayer->changeAttribute(feature, OPT::LineFields_LENGTH, QVariant(lineLength)); // //delete the selected line layer->beginEditCommand( tr( "Features deleted" ) ); if ( !layer->deleteSelectedFeatures() ) { QMessageBox::information( 0, tr( "Problem deleting features" ), tr( "A problem occured during deletion of features" ) ); } layer->endEditCommand(); }
void QgsFeaturePool::addFeature( QgsFeature &feature ) { QgsFeatureList features; features.append( feature ); mLayerMutex.lock(); mLayer->dataProvider()->addFeatures( features ); feature.setId( features.front().id() ); if ( mSelectedOnly ) { QgsFeatureIds selectedFeatureIds = mLayer->selectedFeatureIds(); selectedFeatureIds.insert( feature.id() ); mLayer->selectByIds( selectedFeatureIds ); } mLayerMutex.unlock(); mIndexMutex.lock(); mIndex.insertFeature( feature ); mIndexMutex.unlock(); }
bool QgsGPXProvider::addFeatures( QgsFeatureList & flist ) { // add all the features for ( QgsFeatureList::iterator iter = flist.begin(); iter != flist.end(); ++iter ) { if ( !addFeature( *iter ) ) return false; } // write back to file QFile file( mFileName ); if ( !file.open( QIODevice::WriteOnly ) ) return false; QTextStream ostr( &file ); data->writeXML( ostr ); return true; }
void QgsOfflineEditing::applyFeaturesAdded( QgsVectorLayer* offlineLayer, QgsVectorLayer* remoteLayer, sqlite3* db, int layerId ) { QString sql = QString( "SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId ); QList<int> newFeatureIds = sqlQueryInts( db, sql ); // get new features from offline layer QgsFeatureList features; for ( int i = 0; i < newFeatureIds.size(); i++ ) { QgsFeature feature; if ( offlineLayer->getFeatures( QgsFeatureRequest().setFilterFid( newFeatureIds.at( i ) ) ).nextFeature( feature ) ) { features << feature; } } // copy features to remote layer emit progressModeSet( QgsOfflineEditing::AddFeatures, features.size() ); int i = 1; int newAttrsCount = remoteLayer->pendingFields().count(); for ( QgsFeatureList::iterator it = features.begin(); it != features.end(); ++it ) { QgsFeature f = *it; // NOTE: Spatialite provider ignores position of geometry column // restore gap in QgsAttributeMap if geometry column is not last (WORKAROUND) QMap<int, int> attrLookup = attributeLookup( offlineLayer, remoteLayer ); QgsAttributes newAttrs( newAttrsCount ); QgsAttributes attrs = f.attributes(); for ( int it = 0; it < attrs.count(); ++it ) { newAttrs[ attrLookup[ it ] ] = attrs[ it ]; } f.setAttributes( newAttrs ); remoteLayer->addFeature( f, false ); emit progressUpdated( i++ ); } }
bool QgsMemoryProvider::addFeatures( QgsFeatureList & flist ) { // TODO: sanity checks of fields and geometries for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it ) { mFeatures[mNextFeatureId] = *it; QgsFeature& newfeat = mFeatures[mNextFeatureId]; newfeat.setFeatureId( mNextFeatureId ); // update spatial index if ( mSpatialIndex ) mSpatialIndex->insertFeature( newfeat ); mNextFeatureId++; } updateExtent(); return TRUE; }
void QgsOfflineEditing::applyFeaturesAdded( QgsVectorLayer* offlineLayer, QgsVectorLayer* remoteLayer, sqlite3* db, int layerId ) { QString sql = QString( "SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId ); QList<int> newFeatureIds = sqlQueryInts( db, sql ); // get new features from offline layer QgsFeatureList features; for ( int i = 0; i < newFeatureIds.size(); i++ ) { QgsFeature feature; if ( offlineLayer->featureAtId( newFeatureIds.at( i ), feature, true, true ) ) { features << feature; } } // copy features to remote layer mProgressDialog->setupProgressBar( tr( "%v / %m features added" ), features.size() ); int i = 1; for ( QgsFeatureList::iterator it = features.begin(); it != features.end(); ++it ) { QgsFeature f = *it; // NOTE: Spatialite provider ignores position of geometry column // restore gap in QgsAttributeMap if geometry column is not last (WORKAROUND) QMap<int, int> attrLookup = attributeLookup( offlineLayer, remoteLayer ); QgsAttributeMap newAttrMap; QgsAttributeMap attrMap = f.attributeMap(); for ( QgsAttributeMap::const_iterator it = attrMap.begin(); it != attrMap.end(); ++it ) { newAttrMap.insert( attrLookup[ it.key()], it.value() ); } f.setAttributeMap( newAttrMap ); remoteLayer->addFeature( f, false ); mProgressDialog->setProgressValue( i++ ); } }
void QgsAttributeTableDialog::doSearch( QString searchString ) { // parse search string and build parsed tree QgsSearchString search; if ( !search.setString( searchString ) ) { QMessageBox::critical( this, tr( "Search string parsing error" ), search.parserErrorMsg() ); return; } QgsSearchTreeNode* searchTree = search.tree(); if ( searchTree == NULL ) { QMessageBox::information( this, tr( "Search results" ), tr( "You've supplied an empty search string." ) ); return; } // TODO: fetch only necessary columns // QStringList columns = searchTree->referencedColumns(); bool fetchGeom = searchTree->needsGeometry(); QApplication::setOverrideCursor( Qt::WaitCursor ); mSelectedFeatures.clear(); if ( cbxSearchSelectedOnly->isChecked() ) { QgsFeatureList selectedFeatures = mLayer->selectedFeatures(); for ( QgsFeatureList::Iterator it = selectedFeatures.begin(); it != selectedFeatures.end(); ++it ) { if ( searchTree->checkAgainst( mLayer->pendingFields(), *it ) ) mSelectedFeatures << it->id(); // check if there were errors during evaluating if ( searchTree->hasError() ) break; } } else { mLayer->select( mLayer->pendingAllAttributesList(), QgsRectangle(), fetchGeom ); QgsFeature f; while ( mLayer->nextFeature( f ) ) { if ( searchTree->checkAgainst( mLayer->pendingFields(), f ) ) mSelectedFeatures << f.id(); // check if there were errors during evaluating if ( searchTree->hasError() ) break; } } QApplication::restoreOverrideCursor(); if ( searchTree->hasError() ) { QMessageBox::critical( this, tr( "Error during search" ), searchTree->errorMsg() ); return; } mLayer->setSelectedFeatures( mSelectedFeatures ); QString str; QWidget *w = mDock ? qobject_cast<QWidget*>( mDock ) : qobject_cast<QWidget*>( this ); if ( mSelectedFeatures.size() ) { w->setWindowTitle( tr( "Attribute table - %1 (%n matching features)", "matching features", mSelectedFeatures.size() ).arg( mLayer->name() ) ); } else { w->setWindowTitle( tr( "Attribute table - %1 (No matching features)" ).arg( mLayer->name() ) ); } }
bool QgsWFSProvider::addFeatures( QgsFeatureList &flist ) { //create <Transaction> xml QDomDocument transactionDoc; QDomElement transactionElem = createTransactionElement( transactionDoc ); transactionDoc.appendChild( transactionElem ); //find out typename from uri and strip namespace prefix QString tname = mShared->mURI.typeName(); if ( tname.isNull() ) { return false; } removeNamespacePrefix( tname ); //Add the features QgsFeatureList::iterator featureIt = flist.begin(); for ( ; featureIt != flist.end(); ++featureIt ) { //Insert element QDomElement insertElem = transactionDoc.createElementNS( QgsWFSConstants::WFS_NAMESPACE, "Insert" ); transactionElem.appendChild( insertElem ); QDomElement featureElem = transactionDoc.createElementNS( mApplicationNamespace, tname ); QgsAttributes featureAttributes = featureIt->attributes(); int nAttrs = featureAttributes.size(); for ( int i = 0; i < nAttrs; ++i ) { const QVariant& value = featureAttributes.at( i ); if ( value.isValid() && !value.isNull() ) { QDomElement fieldElem = transactionDoc.createElementNS( mApplicationNamespace, mShared->mFields.at( i ).name() ); QDomText fieldText = transactionDoc.createTextNode( value.toString() ); fieldElem.appendChild( fieldText ); featureElem.appendChild( fieldElem ); } } //add geometry column (as gml) const QgsGeometry* geometry = featureIt->constGeometry(); if ( geometry != nullptr ) { QDomElement geomElem = transactionDoc.createElementNS( mApplicationNamespace, mShared->mGeometryAttribute ); QgsGeometry the_geom( *geometry ); // convert to multi if the layer geom type is multi and the geom is not if ( QGis::isMultiType( this->geometryType( ) ) && ! the_geom.isMultipart( ) ) { the_geom.convertToMultiType(); } QDomElement gmlElem = QgsOgcUtils::geometryToGML( &the_geom, transactionDoc ); if ( !gmlElem.isNull() ) { gmlElem.setAttribute( "srsName", crs().authid() ); geomElem.appendChild( gmlElem ); featureElem.appendChild( geomElem ); } } insertElem.appendChild( featureElem ); } QDomDocument serverResponse; bool success = sendTransactionDocument( transactionDoc, serverResponse ); if ( !success ) { return false; } if ( transactionSuccess( serverResponse ) ) { //transaction successful. Add the features to the cache QStringList idList = insertedFeatureIds( serverResponse ); QStringList::const_iterator idIt = idList.constBegin(); featureIt = flist.begin(); QVector<QgsWFSFeatureGmlIdPair> serializedFeatureList; for ( ; idIt != idList.constEnd() && featureIt != flist.end(); ++idIt, ++featureIt ) { serializedFeatureList.push_back( QgsWFSFeatureGmlIdPair( *featureIt, *idIt ) ); } mShared->serializeFeatures( serializedFeatureList ); // And now set the feature id from the one got from the database QMap< QString, QgsFeatureId > map; for ( int idx = 0; idx < serializedFeatureList.size(); idx++ ) map[ serializedFeatureList[idx].second ] = serializedFeatureList[idx].first.id(); idIt = idList.constBegin(); featureIt = flist.begin(); for ( ; idIt != idList.constEnd() && featureIt != flist.end(); ++idIt, ++featureIt ) { if ( map.find( *idIt ) != map.end() ) featureIt->setFeatureId( map[*idIt] ); } return true; } else { handleException( serverResponse ); return false; } }
void QgsAttributeTableDialog::doSearch( QString searchString ) { // parse search string and build parsed tree QgsExpression search( searchString ); if ( search.hasParserError() ) { QMessageBox::critical( this, tr( "Parsing error" ), search.parserErrorString() ); return; } if ( ! search.prepare( mLayer->pendingFields() ) ) { QMessageBox::critical( this, tr( "Evaluation error" ), search.evalErrorString() ); } // TODO: fetch only necessary columns //QStringList columns = search.referencedColumns(); bool fetchGeom = search.needsGeometry(); QApplication::setOverrideCursor( Qt::WaitCursor ); mSelectedFeatures.clear(); if ( cbxSearchSelectedOnly->isChecked() ) { QgsFeatureList selectedFeatures = mLayer->selectedFeatures(); for ( QgsFeatureList::Iterator it = selectedFeatures.begin(); it != selectedFeatures.end(); ++it ) { QgsFeature& feat = *it; if ( search.evaluate( &feat ).toInt() != 0 ) mSelectedFeatures << feat.id(); // check if there were errors during evaluating if ( search.hasEvalError() ) break; } } else { mLayer->select( mLayer->pendingAllAttributesList(), QgsRectangle(), fetchGeom ); QgsFeature f; while ( mLayer->nextFeature( f ) ) { if ( search.evaluate( &f ).toInt() != 0 ) mSelectedFeatures << f.id(); // check if there were errors during evaluating if ( search.hasEvalError() ) break; } } QApplication::restoreOverrideCursor(); if ( search.hasEvalError() ) { QMessageBox::critical( this, tr( "Error during search" ), search.evalErrorString() ); return; } mLayer->setSelectedFeatures( mSelectedFeatures ); QString str; QWidget *w = mDock ? qobject_cast<QWidget*>( mDock ) : qobject_cast<QWidget*>( this ); if ( mSelectedFeatures.size() ) { w->setWindowTitle( tr( "Attribute table - %1 (%n matching features)", "matching features", mSelectedFeatures.size() ).arg( mLayer->name() ) ); } else { w->setWindowTitle( tr( "Attribute table - %1 (No matching features)" ).arg( mLayer->name() ) ); } mView->setFocus(); }
QDomDocument createTransactionDocument( QgsServerInterface* serverIface, const QString& version, const QgsServerRequest& request ) { Q_UNUSED( version ); QDomDocument doc; QgsWfsProjectParser* configParser = getConfigParser( serverIface ); #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsAccessControl* accessControl = serverIface->accessControls(); #endif const QString requestBody = request.getParameter( QStringLiteral( "REQUEST_BODY" ) ); QString errorMsg; if ( !doc.setContent( requestBody, true, &errorMsg ) ) { throw QgsRequestNotWellFormedException( errorMsg ); } QDomElement docElem = doc.documentElement(); QDomNodeList docChildNodes = docElem.childNodes(); // Re-organize the transaction document QDomDocument mDoc; QDomElement mDocElem = mDoc.createElement( QStringLiteral( "myTransactionDocument" ) ); mDocElem.setAttribute( QStringLiteral( "xmlns" ), QGS_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:wfs" ), WFS_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:qgs" ), QGS_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) ); mDoc.appendChild( mDocElem ); QDomElement actionElem; QString actionName; QDomElement typeNameElem; QString typeName; for ( int i = docChildNodes.count(); 0 < i; --i ) { actionElem = docChildNodes.at( i - 1 ).toElement(); actionName = actionElem.localName(); if ( actionName == QLatin1String( "Insert" ) ) { QDomElement featureElem = actionElem.firstChild().toElement(); typeName = featureElem.localName(); } else if ( actionName == QLatin1String( "Update" ) ) { typeName = actionElem.attribute( QStringLiteral( "typeName" ) ); } else if ( actionName == QLatin1String( "Delete" ) ) { typeName = actionElem.attribute( QStringLiteral( "typeName" ) ); } if ( typeName.contains( QLatin1String( ":" ) ) ) typeName = typeName.section( QStringLiteral( ":" ), 1, 1 ); QDomNodeList typeNameList = mDocElem.elementsByTagName( typeName ); if ( typeNameList.count() == 0 ) { typeNameElem = mDoc.createElement( typeName ); mDocElem.appendChild( typeNameElem ); } else typeNameElem = typeNameList.at( 0 ).toElement(); typeNameElem.appendChild( actionElem ); } // It's time to make the transaction // Create the response document QDomDocument resp; //wfs:WFS_TransactionRespone element QDomElement respElem = resp.createElement( QStringLiteral( "WFS_TransactionResponse" )/*wfs:WFS_TransactionResponse*/ ); respElem.setAttribute( QStringLiteral( "xmlns" ), WFS_NAMESPACE ); respElem.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) ); respElem.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WFS_NAMESPACE + " http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" ); respElem.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE ); respElem.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) ); resp.appendChild( respElem ); // Store the created feature id for WFS QStringList insertResults; // Get the WFS layers id QStringList wfsLayersId = configParser->wfsLayers();; QList<QgsMapLayer*> layerList; QgsMapLayer* currentLayer = nullptr; // Loop through the layer transaction elements docChildNodes = mDocElem.childNodes(); for ( int i = 0; i < docChildNodes.count(); ++i ) { // Get the vector layer typeNameElem = docChildNodes.at( i ).toElement(); typeName = typeNameElem.tagName(); layerList = configParser->mapLayerFromTypeName( typeName ); // Could be empty! if ( layerList.count() > 0 ) { currentLayer = layerList.at( 0 ); } else { throw QgsRequestNotWellFormedException( QStringLiteral( "Wrong TypeName: %1" ).arg( typeName ) ); } QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( currentLayer ); // it's a vectorlayer and defined by the administrator as a WFS layer if ( layer && wfsLayersId.contains( layer->id() ) ) { #ifdef HAVE_SERVER_PYTHON_PLUGINS if ( actionName == QLatin1String( "Insert" ) ) { if ( !accessControl->layerInsertPermission( layer ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature insert permission denied" ) ); } } else if ( actionName == QLatin1String( "Update" ) ) { if ( !accessControl->layerUpdatePermission( layer ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature update permission denied" ) ); } } else if ( actionName == QLatin1String( "Delete" ) ) { if ( !accessControl->layerDeletePermission( layer ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature delete permission denied" ) ); } } #endif // Get the provider and it's capabilities QgsVectorDataProvider* provider = layer->dataProvider(); if ( !provider ) { continue; } int cap = provider->capabilities(); // Start the update transaction layer->startEditing(); if (( cap & QgsVectorDataProvider::ChangeAttributeValues ) && ( cap & QgsVectorDataProvider::ChangeGeometries ) ) { // Loop through the update elements for this layer QDomNodeList upNodeList = typeNameElem.elementsByTagNameNS( WFS_NAMESPACE, QStringLiteral( "Update" ) ); for ( int j = 0; j < upNodeList.count(); ++j ) { if ( !configParser->wfstUpdateLayers().contains( layer->id() ) ) { //no wfs permissions to do updates QString errorMsg = "No permissions to do WFS updates on layer '" + layer->name() + "'"; QgsMessageLog::logMessage( errorMsg, QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); addTransactionResult( resp, respElem, QStringLiteral( "FAILED" ), QStringLiteral( "Update" ), errorMsg ); return resp; } actionElem = upNodeList.at( j ).toElement(); // Get the Feature Ids for this filter on the layer QDomElement filterElem = actionElem.elementsByTagName( QStringLiteral( "Filter" ) ).at( 0 ).toElement(); QgsFeatureIds fids = getFeatureIdsFromFilter( filterElem, layer ); // Loop through the property elements // Store properties and the geometry element QDomNodeList propertyNodeList = actionElem.elementsByTagName( QStringLiteral( "Property" ) ); QMap<QString, QString> propertyMap; QDomElement propertyElem; QDomElement nameElem; QDomElement valueElem; QDomElement geometryElem; for ( int l = 0; l < propertyNodeList.count(); ++l ) { propertyElem = propertyNodeList.at( l ).toElement(); nameElem = propertyElem.elementsByTagName( QStringLiteral( "Name" ) ).at( 0 ).toElement(); valueElem = propertyElem.elementsByTagName( QStringLiteral( "Value" ) ).at( 0 ).toElement(); if ( nameElem.text() != QLatin1String( "geometry" ) ) { propertyMap.insert( nameElem.text(), valueElem.text() ); } else { geometryElem = valueElem; } } // Update the features QgsFields fields = provider->fields(); QMap<QString, int> fieldMap = provider->fieldNameMap(); QMap<QString, int>::const_iterator fieldMapIt; QString fieldName; bool conversionSuccess; QgsFeatureIds::const_iterator fidIt = fids.constBegin(); for ( ; fidIt != fids.constEnd(); ++fidIt ) { #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest( *fidIt ) ); QgsFeature feature; while ( fit.nextFeature( feature ) ) { if ( !accessControl->allowToEdit( layer, feature ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature modify permission denied" ) ); } } #endif QMap< QString, QString >::const_iterator it = propertyMap.constBegin(); for ( ; it != propertyMap.constEnd(); ++it ) { fieldName = it.key(); fieldMapIt = fieldMap.find( fieldName ); if ( fieldMapIt == fieldMap.constEnd() ) { continue; } QgsField field = fields.at( fieldMapIt.value() ); if ( field.type() == 2 ) layer->changeAttributeValue( *fidIt, fieldMapIt.value(), it.value().toInt( &conversionSuccess ) ); else if ( field.type() == 6 ) layer->changeAttributeValue( *fidIt, fieldMapIt.value(), it.value().toDouble( &conversionSuccess ) ); else layer->changeAttributeValue( *fidIt, fieldMapIt.value(), it.value() ); } if ( !geometryElem.isNull() ) { QgsGeometry g = QgsOgcUtils::geometryFromGML( geometryElem ); if ( !layer->changeGeometry( *fidIt, g ) ) { throw QgsRequestNotWellFormedException( QStringLiteral( "Error in change geometry" ) ); } } #ifdef HAVE_SERVER_PYTHON_PLUGINS fit = layer->getFeatures( QgsFeatureRequest( *fidIt ) ); while ( fit.nextFeature( feature ) ) { if ( !accessControl->allowToEdit( layer, feature ) ) { layer->rollBack(); throw QgsSecurityAccessException( QStringLiteral( "Feature modify permission denied" ) ); } } #endif } } } // Commit the changes of the update elements if ( !layer->commitChanges() ) { addTransactionResult( resp, respElem, QStringLiteral( "PARTIAL" ), QStringLiteral( "Update" ), layer->commitErrors().join( QStringLiteral( "\n " ) ) ); return resp; } // Start the delete transaction layer->startEditing(); if (( cap & QgsVectorDataProvider::DeleteFeatures ) ) { // Loop through the delete elements QDomNodeList delNodeList = typeNameElem.elementsByTagNameNS( WFS_NAMESPACE, QStringLiteral( "Delete" ) ); for ( int j = 0; j < delNodeList.count(); ++j ) { if ( !configParser->wfstDeleteLayers().contains( layer->id() ) ) { //no wfs permissions to do updates QString errorMsg = "No permissions to do WFS deletes on layer '" + layer->name() + "'"; QgsMessageLog::logMessage( errorMsg, QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); addTransactionResult( resp, respElem, QStringLiteral( "FAILED" ), QStringLiteral( "Delete" ), errorMsg ); return resp; } actionElem = delNodeList.at( j ).toElement(); QDomElement filterElem = actionElem.firstChild().toElement(); // Get Feature Ids for the Filter element QgsFeatureIds fids = getFeatureIdsFromFilter( filterElem, layer ); #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsFeatureIds::const_iterator fidIt = fids.constBegin(); for ( ; fidIt != fids.constEnd(); ++fidIt ) { QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest( *fidIt ) ); QgsFeature feature; while ( fit.nextFeature( feature ) ) { if ( !accessControl->allowToEdit( layer, feature ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature modify permission denied" ) ); } } } #endif layer->selectByIds( fids ); layer->deleteSelectedFeatures(); } } // Commit the changes of the delete elements if ( !layer->commitChanges() ) { addTransactionResult( resp, respElem, QStringLiteral( "PARTIAL" ), QStringLiteral( "Delete" ), layer->commitErrors().join( QStringLiteral( "\n " ) ) ); return resp; } // Store the inserted features QgsFeatureList inFeatList; if ( cap & QgsVectorDataProvider::AddFeatures ) { // Get Layer Field Information QgsFields fields = provider->fields(); QMap<QString, int> fieldMap = provider->fieldNameMap(); QMap<QString, int>::const_iterator fieldMapIt; // Loop through the insert elements QDomNodeList inNodeList = typeNameElem.elementsByTagNameNS( WFS_NAMESPACE, QStringLiteral( "Insert" ) ); for ( int j = 0; j < inNodeList.count(); ++j ) { if ( !configParser->wfstInsertLayers().contains( layer->id() ) ) { //no wfs permissions to do updates QString errorMsg = "No permissions to do WFS inserts on layer '" + layer->name() + "'"; QgsMessageLog::logMessage( errorMsg, QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); addTransactionResult( resp, respElem, QStringLiteral( "FAILED" ), QStringLiteral( "Insert" ), errorMsg ); return resp; } actionElem = inNodeList.at( j ).toElement(); // Loop through the feature element QDomNodeList featNodes = actionElem.childNodes(); for ( int l = 0; l < featNodes.count(); l++ ) { // Add the feature to the layer // and store it to put it's Feature Id in the response inFeatList << QgsFeature( fields ); // Create feature for this layer QDomElement featureElem = featNodes.at( l ).toElement(); QDomNode currentAttributeChild = featureElem.firstChild(); while ( !currentAttributeChild.isNull() ) { QDomElement currentAttributeElement = currentAttributeChild.toElement(); QString attrName = currentAttributeElement.localName(); if ( attrName != QLatin1String( "boundedBy" ) ) { if ( attrName != QLatin1String( "geometry" ) ) //a normal attribute { fieldMapIt = fieldMap.find( attrName ); if ( fieldMapIt == fieldMap.constEnd() ) { continue; } QgsField field = fields.at( fieldMapIt.value() ); QString attrValue = currentAttributeElement.text(); int attrType = field.type(); QgsMessageLog::logMessage( QStringLiteral( "attr: name=%1 idx=%2 value=%3" ).arg( attrName ).arg( fieldMapIt.value() ).arg( attrValue ) ); if ( attrType == QVariant::Int ) inFeatList.last().setAttribute( fieldMapIt.value(), attrValue.toInt() ); else if ( attrType == QVariant::Double ) inFeatList.last().setAttribute( fieldMapIt.value(), attrValue.toDouble() ); else inFeatList.last().setAttribute( fieldMapIt.value(), attrValue ); } else //a geometry attribute { QgsGeometry g = QgsOgcUtils::geometryFromGML( currentAttributeElement ); inFeatList.last().setGeometry( g ); } } currentAttributeChild = currentAttributeChild.nextSibling(); } } } } #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsFeatureList::iterator featureIt = inFeatList.begin(); while ( featureIt != inFeatList.end() ) { if ( !accessControl->allowToEdit( layer, *featureIt ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature modify permission denied" ) ); } featureIt++; } #endif // add the features if ( !provider->addFeatures( inFeatList ) ) { addTransactionResult( resp, respElem, QStringLiteral( "Partial" ), QStringLiteral( "Insert" ), layer->commitErrors().join( QStringLiteral( "\n " ) ) ); if ( provider->hasErrors() ) { provider->clearErrors(); } return resp; } // Get the Feature Ids of the inserted feature for ( int j = 0; j < inFeatList.size(); j++ ) { insertResults << typeName + "." + QString::number( inFeatList[j].id() ); } } } // Put the Feature Ids of the inserted feature if ( !insertResults.isEmpty() ) { Q_FOREACH ( const QString &fidStr, insertResults ) { QDomElement irElem = doc.createElement( QStringLiteral( "InsertResult" ) ); QDomElement fiElem = doc.createElement( QStringLiteral( "ogc:FeatureId" ) ); fiElem.setAttribute( QStringLiteral( "fid" ), fidStr ); irElem.appendChild( fiElem ); respElem.appendChild( irElem ); }
void QgsOfflineEditing::committedFeaturesAdded( const QString& qgisLayerId, const QgsFeatureList& addedFeatures ) { sqlite3* db = openLoggingDb(); if ( db == NULL ) { return; } // insert log int layerId = getOrCreateLayerId( db, qgisLayerId ); // get new feature ids from db QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( qgisLayerId ); QgsDataSourceURI uri = QgsDataSourceURI( layer->source() ); // only store feature ids QString sql = QString( "SELECT ROWID FROM '%1' ORDER BY ROWID DESC LIMIT %2" ).arg( uri.table() ).arg( addedFeatures.size() ); QList<int> newFeatureIds = sqlQueryInts( db, sql ); for ( int i = newFeatureIds.size() - 1; i >= 0; i-- ) { QString sql = QString( "INSERT INTO 'log_added_features' VALUES ( %1, %2 )" ) .arg( layerId ) .arg( newFeatureIds.at( i ) ); sqlExec( db, sql ); } sqlite3_close( db ); }
void QgsGeometryCheckerSetupTab::runChecks() { // Get selected layer QList<QgsVectorLayer *> layers = getSelectedLayers(); if ( layers.isEmpty() ) return; if ( ui.radioButtonOutputNew->isChecked() ) { for ( QgsVectorLayer *layer : layers ) { if ( layer->dataProvider()->dataSourceUri().startsWith( ui.lineEditOutputDirectory->text() ) ) { QMessageBox::critical( this, tr( "Invalid Output Directory" ), tr( "The chosen output directory contains one or more input layers." ) ); return; } } } QgsVectorLayer *lineLayerCheckLayer = ui.comboLineLayerIntersection->isEnabled() ? dynamic_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( ui.comboLineLayerIntersection->currentData().toString() ) ) : nullptr; QgsVectorLayer *followBoundaryCheckLayer = ui.comboBoxFollowBoundaries->isEnabled() ? dynamic_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( ui.comboBoxFollowBoundaries->currentData().toString() ) ) : nullptr; if ( layers.contains( lineLayerCheckLayer ) || layers.contains( followBoundaryCheckLayer ) ) { QMessageBox::critical( this, tr( "Error" ), tr( "The test layer set contains a layer selected for a topology check." ) ); return; } for ( QgsVectorLayer *layer : layers ) { if ( layer->isEditable() ) { QMessageBox::critical( this, tr( "Editable Input Layer" ), tr( "Input layer are not allowed to be in editing mode." ) ); return; } } bool selectedOnly = ui.checkBoxInputSelectedOnly->isChecked(); // Set window busy setCursor( Qt::WaitCursor ); mRunButton->setEnabled( false ); ui.labelStatus->setText( tr( "<b>Preparing output...</b>" ) ); ui.labelStatus->show(); QApplication::processEvents( QEventLoop::ExcludeUserInputEvents ); QList<QgsVectorLayer *> processLayers; if ( ui.radioButtonOutputNew->isChecked() ) { // Get output directory and file extension QDir outputDir = QDir( ui.lineEditOutputDirectory->text() ); QString outputDriverName = ui.comboBoxOutputFormat->currentText(); QgsVectorFileWriter::MetaData metadata; if ( !QgsVectorFileWriter::driverMetadata( outputDriverName, metadata ) ) { QMessageBox::critical( this, tr( "Unknown Output Format" ), tr( "The specified output format cannot be recognized." ) ); mRunButton->setEnabled( true ); ui.labelStatus->hide(); unsetCursor(); return; } QString outputExtension = metadata.ext; // List over input layers, check which existing project layers need to be removed and create output layers QString filenamePrefix = ui.lineEditFilenamePrefix->text(); QSettings().setValue( "/geometry_checker/previous_values/filename_prefix", filenamePrefix ); QStringList toRemove; QStringList createErrors; for ( QgsVectorLayer *layer : layers ) { QString outputPath = outputDir.absoluteFilePath( filenamePrefix + layer->name() + "." + outputExtension ); // Remove existing layer with same uri from project for ( QgsVectorLayer *projectLayer : QgsProject::instance()->layers<QgsVectorLayer *>() ) { if ( projectLayer->dataProvider()->dataSourceUri().startsWith( outputPath ) ) { toRemove.append( projectLayer->id() ); } } // Create output layer QString errMsg; QgsVectorFileWriter::WriterError err = QgsVectorFileWriter::writeAsVectorFormat( layer, outputPath, layer->dataProvider()->encoding(), layer->crs(), outputDriverName, selectedOnly, &errMsg ); if ( err != QgsVectorFileWriter::NoError ) { createErrors.append( errMsg ); continue; } QgsVectorLayer *newlayer = new QgsVectorLayer( outputPath, QFileInfo( outputPath ).completeBaseName(), QStringLiteral( "ogr" ) ); if ( selectedOnly ) { QgsFeature feature; // Get features to select (only selected features were written up to this point) QgsFeatureIds selectedFeatures = newlayer->allFeatureIds(); // Write non-selected feature ids QgsFeatureList features; QgsFeatureIterator it = layer->getFeatures(); while ( it.nextFeature( feature ) ) { if ( !layer->selectedFeatureIds().contains( feature.id() ) ) { features.append( feature ); } } newlayer->dataProvider()->addFeatures( features ); // Set selected features newlayer->selectByIds( selectedFeatures ); } processLayers.append( newlayer ); } // Remove layers from project if ( !toRemove.isEmpty() ) { QgsProject::instance()->removeMapLayers( toRemove ); } // Error if an output layer could not be created if ( !createErrors.isEmpty() ) { QMessageBox::critical( this, tr( "Layer Creation Failed" ), tr( "Failed to create one or moure output layers:\n%1" ).arg( createErrors.join( "\n" ) ) ); mRunButton->setEnabled( true ); ui.labelStatus->hide(); unsetCursor(); return; } } else { processLayers = layers; } // Check if output layers are editable QList<QgsVectorLayer *> nonEditableLayers; for ( QgsVectorLayer *layer : processLayers ) { if ( ( layer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeGeometries ) == 0 ) { nonEditableLayers.append( layer ); } } if ( !nonEditableLayers.isEmpty() ) { QStringList nonEditableLayerNames; for ( QgsVectorLayer *layer : nonEditableLayers ) { nonEditableLayerNames.append( layer->name() ); } if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Non-editable Output Layers" ), tr( "The following output layers are ina format that does not support editing features:\n%1\n\nThe geometry check can be performed, but it will not be possible to fix any errors. Do you want to continue?" ).arg( nonEditableLayerNames.join( "\n" ) ), QMessageBox::Yes, QMessageBox::No ) ) { if ( ui.radioButtonOutputNew->isChecked() ) { for ( QgsVectorLayer *layer : processLayers ) { QString layerPath = layer->dataProvider()->dataSourceUri(); delete layer; if ( ui.comboBoxOutputFormat->currentText() == QLatin1String( "ESRI Shapefile" ) ) { QgsVectorFileWriter::deleteShapeFile( layerPath ); } else { QFile( layerPath ).remove(); } } mRunButton->setEnabled( true ); ui.labelStatus->hide(); unsetCursor(); } return; } } // Setup checker ui.labelStatus->setText( tr( "<b>Building spatial index...</b>" ) ); QApplication::processEvents( QEventLoop::ExcludeUserInputEvents ); QMap<QString, QgsFeaturePool *> featurePools; for ( QgsVectorLayer *layer : processLayers ) { double layerToMapUntis = mIface->mapCanvas()->mapSettings().layerToMapUnits( layer ); QgsCoordinateTransform layerToMapTransform = QgsCoordinateTransformCache::instance()->transform( layer->crs().authid(), mIface->mapCanvas()->mapSettings().destinationCrs().authid() ); featurePools.insert( layer->id(), new QgsFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly ) ); } // LineLayerIntersection check is enabled, make sure there is also a feature pool for that layer if ( ui.checkLineLayerIntersection->isChecked() && !featurePools.keys().contains( ui.comboLineLayerIntersection->currentData().toString() ) ) { QgsVectorLayer *layer = dynamic_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( ui.comboLineLayerIntersection->currentData().toString() ) ); Q_ASSERT( layer ); double layerToMapUntis = mIface->mapCanvas()->mapSettings().layerToMapUnits( layer ); QgsCoordinateTransform layerToMapTransform = QgsCoordinateTransformCache::instance()->transform( layer->crs().authid(), mIface->mapCanvas()->mapSettings().destinationCrs().authid() ); featurePools.insert( layer->id(), new QgsFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly ) ); } QgsGeometryCheckerContext *context = new QgsGeometryCheckerContext( ui.spinBoxTolerance->value(), mIface->mapCanvas()->mapSettings().destinationCrs().authid(), featurePools ); QList<QgsGeometryCheck *> checks; for ( const QgsGeometryCheckFactory *factory : QgsGeometryCheckFactoryRegistry::getCheckFactories() ) { QgsGeometryCheck *check = factory->createInstance( context, ui ); if ( check ) { checks.append( check ); } } QgsGeometryChecker *checker = new QgsGeometryChecker( checks, context ); emit checkerStarted( checker ); if ( ui.radioButtonOutputNew->isChecked() ) { QList<QgsMapLayer *> addLayers; for ( QgsVectorLayer *layer : processLayers ) { addLayers.append( layer ); } QgsProject::instance()->addMapLayers( addLayers ); } // Run ui.buttonBox->addButton( mAbortButton, QDialogButtonBox::ActionRole ); mRunButton->hide(); ui.progressBar->setRange( 0, 0 ); ui.labelStatus->hide(); ui.progressBar->show(); ui.widgetInputs->setEnabled( false ); QEventLoop evLoop; QFutureWatcher<void> futureWatcher; connect( checker, &QgsGeometryChecker::progressValue, ui.progressBar, &QProgressBar::setValue ); connect( &futureWatcher, &QFutureWatcherBase::finished, &evLoop, &QEventLoop::quit ); connect( mAbortButton, &QAbstractButton::clicked, &futureWatcher, &QFutureWatcherBase::cancel ); connect( mAbortButton, &QAbstractButton::clicked, this, &QgsGeometryCheckerSetupTab::showCancelFeedback ); int maxSteps = 0; futureWatcher.setFuture( checker->execute( &maxSteps ) ); ui.progressBar->setRange( 0, maxSteps ); evLoop.exec(); // Restore window unsetCursor(); mAbortButton->setEnabled( true ); ui.buttonBox->removeButton( mAbortButton ); mRunButton->setEnabled( true ); mRunButton->show(); ui.progressBar->hide(); ui.labelStatus->hide(); ui.widgetInputs->setEnabled( true ); // Show result emit checkerFinished( !futureWatcher.isCanceled() ); }
void QgsClipboard::replaceWithCopyOf( const QgsFieldMap& fields, QgsFeatureList& features ) { // Replace the QGis clipboard. mFeatureClipboard = features; QgsDebugMsg( "replaced QGis clipboard." ); // Replace the system clipboard. QStringList textLines; QStringList textFields; // first do the field names textFields += "wkt_geom"; for ( QgsFieldMap::const_iterator fit = fields.begin(); fit != fields.end(); ++fit ) { textFields += fit->name(); } textLines += textFields.join( "\t" ); textFields.clear(); // then the field contents for ( QgsFeatureList::iterator it = features.begin(); it != features.end(); ++it ) { QgsAttributeMap attributes = it->attributeMap(); // TODO: Set up Paste Transformations to specify the order in which fields are added. if ( it->geometry() ) textFields += it->geometry()->exportToWkt(); else { QSettings settings; textFields += settings.value( "qgis/nullValue", "NULL" ).toString(); } // QgsDebugMsg("about to traverse fields."); // for ( QgsAttributeMap::iterator it2 = attributes.begin(); it2 != attributes.end(); ++it2 ) { // QgsDebugMsg(QString("inspecting field '%1'.").arg(it2->toString())); textFields += it2->toString(); } textLines += textFields.join( "\t" ); textFields.clear(); } QString textCopy = textLines.join( "\n" ); QClipboard *cb = QApplication::clipboard(); // Copy text into the clipboard // With qgis running under Linux, but with a Windows based X // server (Xwin32), ::Selection was necessary to get the data into // the Windows clipboard (which seems contrary to the Qt // docs). With a Linux X server, ::Clipboard was required. // The simple solution was to put the text into both clipboards. // The ::Selection setText() below one may need placing inside so // #ifdef so that it doesn't get compiled under Windows. cb->setText( textCopy, QClipboard::Selection ); cb->setText( textCopy, QClipboard::Clipboard ); QgsDebugMsg( QString( "replaced system clipboard with: %1." ).arg( textCopy ) ); }
void QgsGeometrySnapperDialog::run() { /** Get layers **/ QgsVectorLayer* layer = getInputLayer(); QgsVectorLayer* referenceLayer = getReferenceLayer(); if ( layer == 0 || referenceLayer == 0 ) { return; } if ( ui.radioButtonOutputNew->isChecked() && ( layer->dataProvider()->dataSourceUri().startsWith( ui.lineEditOutput->text() ) || referenceLayer->dataProvider()->dataSourceUri().startsWith( ui.lineEditOutput->text() ) ) ) { QMessageBox::critical( this, tr( "Invalid Output Layer" ), tr( "The chosen output layer is the same as an input layer." ) ); return; } bool selectedOnly = ui.checkBoxInputSelectedOnly->isChecked(); /** Duplicate if necessary **/ if ( ui.radioButtonOutputNew->isChecked() ) { QString filename = ui.lineEditOutput->text(); // Remove existing layer with same uri QStringList toRemove; foreach ( QgsMapLayer* maplayer, QgsMapLayerRegistry::instance()->mapLayers() ) { if ( dynamic_cast<QgsVectorLayer*>( maplayer ) && static_cast<QgsVectorLayer*>( maplayer )->dataProvider()->dataSourceUri().startsWith( filename ) ) { toRemove.append( maplayer->id() ); } } if ( !toRemove.isEmpty() ) { QgsMapLayerRegistry::instance()->removeMapLayers( toRemove ); } QString errMsg; QgsVectorFileWriter::WriterError err = QgsVectorFileWriter::writeAsVectorFormat( layer, filename, layer->dataProvider()->encoding(), &layer->crs(), mOutputDriverName, selectedOnly, &errMsg ); if ( err != QgsVectorFileWriter::NoError ) { QMessageBox::critical( this, tr( "Layer Creation Failed" ), tr( "Failed to create the output layer: %1" ).arg( errMsg ) ); return; } QgsVectorLayer* newlayer = new QgsVectorLayer( filename, QFileInfo( filename ).completeBaseName(), "ogr" ); if ( selectedOnly ) { QgsFeature feature; // Get features to select (only selected features were written up to this point) QgsFeatureIds selectedFeatures = newlayer->allFeatureIds(); // Write non-selected feature ids QgsFeatureList features; QgsFeatureIterator it = layer->getFeatures(); while ( it.nextFeature( feature ) ) { if ( !layer->selectedFeaturesIds().contains( feature.id() ) ) { features.append( feature ); } } newlayer->dataProvider()->addFeatures( features ); // Set selected features newlayer->setSelectedFeatures( selectedFeatures ); } layer = newlayer; }
int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing ) { if ( !L->hasGeometryType() ) return 4; QgsFeatureList newFeatures; //store all the newly created features double xMin, yMin, xMax, yMax; QgsRectangle bBox; //bounding box of the split line int returnCode = 0; int splitFunctionReturn; //return code of QgsGeometry::splitGeometry int numberOfSplittedFeatures = 0; QgsFeatureList featureList; const QgsFeatureIds selectedIds = L->selectedFeaturesIds(); if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection { featureList = L->selectedFeatures(); } else //else consider all the feature that intersect the bounding box of the split line { if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 ) { bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); } else { return 1; } if ( bBox.isEmpty() ) { //if the bbox is a line, try to make a square out of it if ( bBox.width() == 0.0 && bBox.height() > 0 ) { bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 ); bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 ); } else if ( bBox.height() == 0.0 && bBox.width() > 0 ) { bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 ); bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 ); } else { return 2; } } QgsFeatureIterator fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; while ( fit.nextFeature( f ) ) featureList << QgsFeature( f ); } QgsFeatureList::iterator select_it = featureList.begin(); for ( ; select_it != featureList.end(); ++select_it ) { if ( !select_it->geometry() ) { continue; } QList<QgsGeometry*> newGeometries; QList<QgsPoint> topologyTestPoints; QgsGeometry* newGeometry = 0; splitFunctionReturn = select_it->geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); if ( splitFunctionReturn == 0 ) { //change this geometry L->editBuffer()->changeGeometry( select_it->id(), select_it->geometry() ); //insert new features for ( int i = 0; i < newGeometries.size(); ++i ) { newGeometry = newGeometries.at( i ); QgsFeature newFeature; newFeature.setGeometry( newGeometry ); //use default value where possible (primary key issue), otherwise the value from the original (split) feature QgsAttributes newAttributes = select_it->attributes(); QVariant defaultValue; for ( int j = 0; j < newAttributes.count(); ++j ) { defaultValue = L->dataProvider()->defaultValue( j ); if ( !defaultValue.isNull() ) { newAttributes[ j ] = defaultValue; } } newFeature.setAttributes( newAttributes ); newFeatures.append( newFeature ); } if ( topologicalEditing ) { QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin(); for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it ) { addTopologicalPoints( *topol_it ); } } ++numberOfSplittedFeatures; } else if ( splitFunctionReturn > 1 ) //1 means no split but also no error { returnCode = splitFunctionReturn; } } if ( numberOfSplittedFeatures == 0 && selectedIds.size() > 0 ) { //There is a selection but no feature has been split. //Maybe user forgot that only the selected features are split returnCode = 4; } //now add the new features to this vectorlayer L->editBuffer()->addFeatures( newFeatures ); return returnCode; }
bool QgsMapToolFeatureAction::doAction( QgsVectorLayer *layer, int x, int y ) { if ( !layer ) return false; QgsPoint point = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y ); QgsFeatureList featList; // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { // create the search rectangle double searchRadius = searchRadiusMU( mCanvas ); QgsRectangle r; r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); r = toLayerCoordinates( layer, r ); QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; while ( fit.nextFeature( f ) ) featList << QgsFeature( f ); } catch ( QgsCsException & cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and proceed with no features found QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) ); } if ( featList.size() == 0 ) return false; Q_FOREACH ( const QgsFeature& feat, featList ) { if ( layer->actions()->defaultAction() >= 0 ) { // define custom substitutions: layer id and clicked coords QMap<QString, QVariant> substitutionMap; substitutionMap.insert( "$layerid", layer->id() ); point = toLayerCoordinates( layer, point ); substitutionMap.insert( "$clickx", point.x() ); substitutionMap.insert( "$clicky", point.y() ); int actionIdx = layer->actions()->defaultAction(); layer->actions()->doAction( actionIdx, feat, &substitutionMap ); } else { QgsMapLayerAction* mapLayerAction = QgsMapLayerActionRegistry::instance()->defaultActionForLayer( layer ); if ( mapLayerAction ) { mapLayerAction->triggerForFeature( layer, &feat ); } } } return true; }
bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors ) { QgsVectorDataProvider* provider = L->dataProvider(); commitErrors.clear(); int cap = provider->capabilities(); bool success = true; QgsFields oldFields = L->pendingFields(); // // delete attributes // bool attributesChanged = false; if ( !mDeletedAttributeIds.isEmpty() ) { if (( cap & QgsVectorDataProvider::DeleteAttributes ) && provider->deleteAttributes( mDeletedAttributeIds.toSet() ) ) { commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() ); emit committedAttributesDeleted( L->id(), mDeletedAttributeIds ); mDeletedAttributeIds.clear(); attributesChanged = true; } else { commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() ); success = false; } } // // add attributes // if ( !mAddedAttributes.isEmpty() ) { if (( cap & QgsVectorDataProvider::AddAttributes ) && provider->addAttributes( mAddedAttributes ) ) { commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() ); emit committedAttributesAdded( L->id(), mAddedAttributes ); mAddedAttributes.clear(); attributesChanged = true; } else { commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() ); success = false; } } // // check that addition/removal went as expected // bool attributeChangesOk = true; if ( attributesChanged ) { L->updateFields(); QgsFields newFields = L->pendingFields(); if ( oldFields.count() != newFields.count() ) { commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" ); attributeChangesOk = false; // don't try attribute updates - they'll fail. } for ( int i = 0; i < oldFields.count(); ++i ) { const QgsField& oldField = oldFields[i]; const QgsField& newField = newFields[i]; if ( attributeChangesOk && oldField != newField ) { commitErrors << tr( "ERROR: field with index %1 is not the same!" ).arg( i ); attributeChangesOk = false; // don't try attribute updates - they'll fail. } } } if ( attributeChangesOk ) { // // change attributes // if ( !mChangedAttributeValues.isEmpty() ) { if (( cap & QgsVectorDataProvider::ChangeAttributeValues ) && provider->changeAttributeValues( mChangedAttributeValues ) ) { commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() ); emit committedAttributeValuesChanges( L->id(), mChangedAttributeValues ); mChangedAttributeValues.clear(); } else { commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() ); success = false; } } // // delete features // if ( !mDeletedFeatureIds.isEmpty() ) { if (( cap & QgsVectorDataProvider::DeleteFeatures ) && provider->deleteFeatures( mDeletedFeatureIds ) ) { commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() ); // TODO[MD]: we should not need this here for ( QgsFeatureIds::const_iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); it++ ) { mChangedAttributeValues.remove( *it ); mChangedGeometries.remove( *it ); } emit committedFeaturesRemoved( L->id(), mDeletedFeatureIds ); mDeletedFeatureIds.clear(); } else { commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() ); success = false; } } // // add features // if ( !mAddedFeatures.isEmpty() ) { if ( cap & QgsVectorDataProvider::AddFeatures ) { QList<QgsFeatureId> ids = mAddedFeatures.keys(); QgsFeatureList featuresToAdd = mAddedFeatures.values(); if ( provider->addFeatures( featuresToAdd ) ) { commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() ); emit committedFeaturesAdded( L->id(), featuresToAdd ); // notify everyone that the features with temporary ids were updated with permanent ids for ( int i = 0; i < featuresToAdd.count(); ++i ) { if ( featuresToAdd[i].id() != ids[i] ) { emit featureDeleted( ids[i] ); emit featureAdded( featuresToAdd[i].id() ); } } mAddedFeatures.clear(); } else { commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() ); success = false; } } else { commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() ); success = false; } } } // // update geometries // if ( !mChangedGeometries.isEmpty() ) { if (( cap & QgsVectorDataProvider::ChangeGeometries ) && provider->changeGeometryValues( mChangedGeometries ) ) { commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() ); emit committedGeometriesChanges( L->id(), mChangedGeometries ); mChangedGeometries.clear(); } else { commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() ); success = false; } } if ( !success ) { if ( provider->hasErrors() ) { commitErrors << tr( "\n Provider errors:" ) << provider->errors(); provider->clearErrors(); } } return success; }
void QgsMapToolAddPart::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) { //check if we operate on a vector layer QgsVectorLayer *vlayer = currentVectorLayer(); if ( !vlayer ) { notifyNotVectorLayer(); return; } if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } bool isGeometryEmpty = false; QgsFeatureList selectedFeatures = vlayer->selectedFeatures(); if ( !selectedFeatures.isEmpty() && selectedFeatures.at( 0 ).geometry().isNull() ) isGeometryEmpty = true; if ( !checkSelection() ) { stopCapturing(); return; } int errorCode = 0; switch ( mode() ) { case CapturePoint: { QgsPoint layerPoint; QgsPointXY mapPoint = e->mapPoint(); if ( nextPoint( QgsPoint( mapPoint ), layerPoint ) != 0 ) { QgsDebugMsg( "nextPoint failed" ); return; } vlayer->beginEditCommand( tr( "Part added" ) ); errorCode = vlayer->addPart( QgsPointSequence() << layerPoint ); } break; case CaptureLine: case CapturePolygon: { //add point to list and to rubber band if ( e->button() == Qt::LeftButton ) { int error = addVertex( e->mapPoint(), e->mapPointMatch() ); if ( error == 1 ) { QgsDebugMsg( "current layer is not a vector layer" ); return; } else if ( error == 2 ) { //problem with coordinate transformation emit messageEmitted( tr( "Coordinate transform error. Cannot transform the point to the layers coordinate system" ), Qgis::Warning ); return; } startCapturing(); return; } else if ( e->button() != Qt::RightButton ) { deleteTempRubberBand(); return; } if ( !isCapturing() ) return; if ( mode() == CapturePolygon ) { closePolygon(); } //does compoundcurve contain circular strings? //does provider support circular strings? bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries; QgsCurve *curveToAdd = nullptr; if ( hasCurvedSegments && providerSupportsCurvedSegments ) { curveToAdd = captureCurve()->clone(); } else { curveToAdd = captureCurve()->curveToLine(); } vlayer->beginEditCommand( tr( "Part added" ) ); if ( mode() == CapturePolygon ) { //avoid intersections QgsCurvePolygon *cp = new QgsCurvePolygon(); cp->setExteriorRing( curveToAdd ); QgsGeometry *geom = new QgsGeometry( cp ); geom->avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() ); const QgsCurvePolygon *cpGeom = qgsgeometry_cast<const QgsCurvePolygon *>( geom->constGet() ); if ( !cpGeom ) { stopCapturing(); delete geom; vlayer->destroyEditCommand(); return; } errorCode = vlayer->addPart( cpGeom->exteriorRing()->clone() ); delete geom; } else { errorCode = vlayer->addPart( curveToAdd ); } stopCapturing(); } break; default: Q_ASSERT( !"invalid capture mode" ); errorCode = 6; break; } QString errorMessage; switch ( errorCode ) { case 0: { // remove previous message emit messageDiscarded(); //add points to other features to keep topology up-to-date bool topologicalEditing = QgsProject::instance()->topologicalEditing(); if ( topologicalEditing ) { addTopologicalPoints( points() ); } vlayer->endEditCommand(); vlayer->triggerRepaint(); if ( ( !isGeometryEmpty ) && QgsWkbTypes::isSingleType( vlayer->wkbType() ) ) { emit messageEmitted( tr( "Add part: Feature geom is single part and you've added more than one" ), Qgis::Warning ); } return; } case 1: errorMessage = tr( "Selected feature is not multi part." ); break; case 2: errorMessage = tr( "New part's geometry is not valid." ); break; case 3: errorMessage = tr( "New polygon ring not disjoint with existing polygons." ); break; case 4: errorMessage = tr( "No feature selected. Please select a feature with the selection tool or in the attribute table" ); break; case 5: errorMessage = tr( "Several features are selected. Please select only one feature to which an island should be added." ); break; case 6: errorMessage = tr( "Selected geometry could not be found" ); break; } emit messageEmitted( errorMessage, Qgis::Warning ); vlayer->destroyEditCommand(); }
QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { std::unique_ptr< QgsFeatureSource > featureSource( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); if ( !featureSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); std::unique_ptr< QgsFeatureSource > maskSource( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) ); if ( !maskSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "OVERLAY" ) ) ); QString dest; QgsWkbTypes::GeometryType sinkType = QgsWkbTypes::geometryType( featureSource->wkbType() ); std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, featureSource->fields(), QgsWkbTypes::multiType( featureSource->wkbType() ), featureSource->sourceCrs() ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); // first build up a list of clip geometries QVector< QgsGeometry > clipGeoms; QgsFeatureIterator it = maskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ).setDestinationCrs( featureSource->sourceCrs(), context.transformContext() ) ); QgsFeature f; while ( it.nextFeature( f ) ) { if ( f.hasGeometry() ) clipGeoms << f.geometry(); } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); if ( clipGeoms.isEmpty() ) return outputs; // are we clipping against a single feature? if so, we can show finer progress reports bool singleClipFeature = false; QgsGeometry combinedClipGeom; if ( clipGeoms.length() > 1 ) { combinedClipGeom = QgsGeometry::unaryUnion( clipGeoms ); if ( combinedClipGeom.isEmpty() ) { throw QgsProcessingException( QObject::tr( "Could not create the combined clip geometry: %1" ).arg( combinedClipGeom.lastError() ) ); } singleClipFeature = false; } else { combinedClipGeom = clipGeoms.at( 0 ); singleClipFeature = true; } // use prepared geometries for faster intersection tests std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( combinedClipGeom.constGet() ) ); engine->prepareGeometry(); QgsFeatureIds testedFeatureIds; int i = -1; Q_FOREACH ( const QgsGeometry &clipGeom, clipGeoms ) { i++; if ( feedback->isCanceled() ) { break; } QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) ); QgsFeatureList inputFeatures; QgsFeature f; while ( inputIt.nextFeature( f ) ) inputFeatures << f; if ( inputFeatures.isEmpty() ) continue; double step = 0; if ( singleClipFeature ) step = 100.0 / inputFeatures.length(); int current = 0; Q_FOREACH ( const QgsFeature &inputFeature, inputFeatures ) { if ( feedback->isCanceled() ) { break; } if ( !inputFeature.hasGeometry() ) continue; if ( testedFeatureIds.contains( inputFeature.id() ) ) { // don't retest a feature we have already checked continue; } testedFeatureIds.insert( inputFeature.id() ); if ( !engine->intersects( inputFeature.geometry().constGet() ) ) continue; QgsGeometry newGeometry; if ( !engine->contains( inputFeature.geometry().constGet() ) ) { QgsGeometry currentGeometry = inputFeature.geometry(); newGeometry = combinedClipGeom.intersection( currentGeometry ); if ( newGeometry.wkbType() == QgsWkbTypes::Unknown || QgsWkbTypes::flatType( newGeometry.wkbType() ) == QgsWkbTypes::GeometryCollection ) { QgsGeometry intCom = inputFeature.geometry().combine( newGeometry ); QgsGeometry intSym = inputFeature.geometry().symDifference( newGeometry ); newGeometry = intCom.difference( intSym ); } } else { // clip geometry totally contains feature geometry, so no need to perform intersection newGeometry = inputFeature.geometry(); } if ( !QgsOverlayUtils::sanitizeIntersectionResult( newGeometry, sinkType ) ) continue; QgsFeature outputFeature; outputFeature.setGeometry( newGeometry ); outputFeature.setAttributes( inputFeature.attributes() ); sink->addFeature( outputFeature, QgsFeatureSink::FastInsert ); if ( singleClipFeature ) feedback->setProgress( current * step ); } if ( !singleClipFeature ) { // coarse progress report for multiple clip geometries feedback->setProgress( 100.0 * static_cast< double >( i ) / clipGeoms.length() ); } }
bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int y ) { if ( !layer ) return false; QMap< QString, QString > attributes, derivedAttributes; QgsPoint point = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y ); derivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() ); // load identify radius from settings QSettings settings; double identifyValue = settings.value( "/Map/identifyRadius", QGis::DEFAULT_IDENTIFY_RADIUS ).toDouble(); QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", "WGS84" ).toString(); if ( identifyValue <= 0.0 ) identifyValue = QGis::DEFAULT_IDENTIFY_RADIUS; int featureCount = 0; QgsFeatureList featureList; // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { // create the search rectangle double searchRadius = mCanvas->extent().width() * ( identifyValue / 100.0 ); QgsRectangle r; r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); r = toLayerCoordinates( layer, r ); layer->select( layer->pendingAllAttributesList(), r, true, true ); QgsFeature f; while ( layer->nextFeature( f ) ) featureList << QgsFeature( f ); } catch ( QgsCsException & cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and proceed with no features found QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) ); } // init distance/area calculator QgsDistanceArea calc; if ( !featureList.count() == 0 ) { calc.setProjectionsEnabled( mCanvas->hasCrsTransformEnabled() ); // project? calc.setEllipsoid( ellipsoid ); calc.setSourceCrs( layer->crs().srsid() ); } QgsFeatureList::iterator f_it = featureList.begin(); for ( ; f_it != featureList.end(); ++f_it ) { featureCount++; QgsFeatureId fid = f_it->id(); QMap<QString, QString> derivedAttributes; // Calculate derived attributes and insert: // measure distance or area depending on geometry type if ( layer->geometryType() == QGis::Line ) { double dist = calc.measure( f_it->geometry() ); QGis::UnitType myDisplayUnits; convertMeasurement( calc, dist, myDisplayUnits, false ); QString str = calc.textUnit( dist, 3, myDisplayUnits, false ); // dist and myDisplayUnits are out params derivedAttributes.insert( tr( "Length" ), str ); if ( f_it->geometry()->wkbType() == QGis::WKBLineString || f_it->geometry()->wkbType() == QGis::WKBLineString25D ) { // Add the start and end points in as derived attributes str = QLocale::system().toString( f_it->geometry()->asPolyline().first().x(), 'g', 10 ); derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str ); str = QLocale::system().toString( f_it->geometry()->asPolyline().first().y(), 'g', 10 ); derivedAttributes.insert( tr( "firstY" ), str ); str = QLocale::system().toString( f_it->geometry()->asPolyline().last().x(), 'g', 10 ); derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str ); str = QLocale::system().toString( f_it->geometry()->asPolyline().last().y(), 'g', 10 ); derivedAttributes.insert( tr( "lastY" ), str ); } } else if ( layer->geometryType() == QGis::Polygon ) { double area = calc.measure( f_it->geometry() ); QGis::UnitType myDisplayUnits; convertMeasurement( calc, area, myDisplayUnits, true ); // area and myDisplayUnits are out params QString str = calc.textUnit( area, 3, myDisplayUnits, true ); derivedAttributes.insert( tr( "Area" ), str ); } else if ( layer->geometryType() == QGis::Point && ( f_it->geometry()->wkbType() == QGis::WKBPoint || f_it->geometry()->wkbType() == QGis::WKBPoint25D ) ) { // Include the x and y coordinates of the point as a derived attribute QString str; str = QLocale::system().toString( f_it->geometry()->asPoint().x(), 'g', 10 ); derivedAttributes.insert( "X", str ); str = QLocale::system().toString( f_it->geometry()->asPoint().y(), 'g', 10 ); derivedAttributes.insert( "Y", str ); } derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) ); results()->addFeature( layer, *f_it, derivedAttributes ); } QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) ); return featureCount > 0; }
bool QgsMapToolIdentify::identifyVectorLayer( QList<IdentifyResult> *results, QgsVectorLayer *layer, const QgsPoint& point ) { if ( !layer || !layer->hasGeometryType() ) return false; if ( layer->hasScaleBasedVisibility() && ( layer->minimumScale() > mCanvas->mapSettings().scale() || layer->maximumScale() <= mCanvas->mapSettings().scale() ) ) { QgsDebugMsg( "Out of scale limits" ); return false; } QApplication::setOverrideCursor( Qt::WaitCursor ); QMap< QString, QString > commonDerivedAttributes; commonDerivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() ); int featureCount = 0; QgsFeatureList featureList; // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { // create the search rectangle double searchRadius = searchRadiusMU( mCanvas ); QgsRectangle r; r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); r = toLayerCoordinates( layer, r ); QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; while ( fit.nextFeature( f ) ) featureList << QgsFeature( f ); } catch ( QgsCsException & cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and proceed with no features found QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) ); } QgsFeatureList::iterator f_it = featureList.begin(); bool filter = false; QgsRenderContext context( QgsRenderContext::fromMapSettings( mCanvas->mapSettings() ) ); context.expressionContext() << QgsExpressionContextUtils::layerScope( layer ); QgsFeatureRendererV2* renderer = layer->rendererV2(); if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent ) { // setup scale for scale dependent visibility (rule based) renderer->startRender( context, layer->fields() ); filter = renderer->capabilities() & QgsFeatureRendererV2::Filter; } for ( ; f_it != featureList.end(); ++f_it ) { QMap< QString, QString > derivedAttributes = commonDerivedAttributes; QgsFeatureId fid = f_it->id(); context.expressionContext().setFeature( *f_it ); if ( filter && !renderer->willRenderFeature( *f_it, context ) ) continue; featureCount++; derivedAttributes.unite( featureDerivedAttributes( &( *f_it ), layer, toLayerCoordinates( layer, point ) ) ); derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) ); results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), *f_it, derivedAttributes ) ); } if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent ) { renderer->stopRender( context ); } QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) ); QApplication::restoreOverrideCursor(); return featureCount > 0; }
int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing ) { if ( !L->hasGeometryType() ) return 4; QgsFeatureList newFeatures; //store all the newly created features double xMin, yMin, xMax, yMax; QgsRectangle bBox; //bounding box of the split line int returnCode = 0; int splitFunctionReturn; //return code of QgsGeometry::splitGeometry int numberOfSplittedFeatures = 0; QgsFeatureIterator features; const QgsFeatureIds selectedIds = L->selectedFeaturesIds(); if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection { features = L->selectedFeaturesIterator(); } else //else consider all the feature that intersect the bounding box of the split line { if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 ) { bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); } else { return 1; } if ( bBox.isEmpty() ) { //if the bbox is a line, try to make a square out of it if ( bBox.width() == 0.0 && bBox.height() > 0 ) { bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 ); bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 ); } else if ( bBox.height() == 0.0 && bBox.width() > 0 ) { bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 ); bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 ); } else { //If we have a single point, we still create a non-null box double bufferDistance = 0.000001; if ( L->crs().geographicFlag() ) bufferDistance = 0.00000001; bBox.setXMinimum( bBox.xMinimum() - bufferDistance ); bBox.setXMaximum( bBox.xMaximum() + bufferDistance ); bBox.setYMinimum( bBox.yMinimum() - bufferDistance ); bBox.setYMaximum( bBox.yMaximum() + bufferDistance ); } } features = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); } QgsFeature feat; while ( features.nextFeature( feat ) ) { if ( !feat.constGeometry() ) { continue; } QList<QgsGeometry*> newGeometries; QList<QgsPoint> topologyTestPoints; QgsGeometry* newGeometry = 0; splitFunctionReturn = feat.geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); if ( splitFunctionReturn == 0 ) { //change this geometry L->editBuffer()->changeGeometry( feat.id(), feat.geometry() ); //insert new features for ( int i = 0; i < newGeometries.size(); ++i ) { newGeometry = newGeometries.at( i ); QgsFeature newFeature; newFeature.setGeometry( newGeometry ); //use default value where possible for primary key (e.g. autoincrement), //and use the value from the original (split) feature if not primary key QgsAttributes newAttributes = feat.attributes(); Q_FOREACH ( int pkIdx, L->dataProvider()->pkAttributeIndexes() ) { const QVariant defaultValue = L->dataProvider()->defaultValue( pkIdx ); if ( !defaultValue.isNull() ) { newAttributes[ pkIdx ] = defaultValue; } else //try with NULL { newAttributes[ pkIdx ] = QVariant(); } } newFeature.setAttributes( newAttributes ); newFeatures.append( newFeature ); } if ( topologicalEditing ) { QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin(); for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it ) { addTopologicalPoints( *topol_it ); } } ++numberOfSplittedFeatures; } else if ( splitFunctionReturn > 1 ) //1 means no split but also no error