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++ ); } }
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++ ); } }
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; }
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 ); }
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 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 ); }