QgsGrassFeatureIterator::QgsGrassFeatureIterator( QgsGrassProvider* p, const QgsFeatureRequest& request ) : QgsAbstractFeatureIterator( request ), P( p ) { // make sure that only one iterator is active if ( P->mActiveIterator ) { QgsMessageLog::logMessage( QObject::tr( "Already active iterator on this provider was closed." ), QObject::tr( "GRASS" ) ); P->mActiveIterator->close(); } P->mActiveIterator = this; // check if outdated and update if necessary P->ensureUpdated(); // Init structures mPoints = Vect_new_line_struct(); mCats = Vect_new_cats_struct(); mList = Vect_new_list(); // Create selection array allocateSelection( P->mMap ); resetSelection( 1 ); if ( request.filterType() == QgsFeatureRequest::FilterRect ) { setSelectionRect( request.filterRect(), request.flags() & QgsFeatureRequest::ExactIntersect ); } else { // TODO: implement fast lookup by feature id //no filter - use all features resetSelection( 1 ); } }
QgsGrassFeatureIterator::QgsGrassFeatureIterator( QgsGrassFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsGrassFeatureSource>( source, ownSource, request ) { sMutex.lock(); // Init structures mPoints = Vect_new_line_struct(); mCats = Vect_new_cats_struct(); mList = Vect_new_list(); // Create selection array allocateSelection( mSource->mMap ); resetSelection( 1 ); if ( request.filterType() == QgsFeatureRequest::FilterRect ) { setSelectionRect( request.filterRect(), request.flags() & QgsFeatureRequest::ExactIntersect ); } else { // TODO: implement fast lookup by feature id //no filter - use all features resetSelection( 1 ); } }
void QgsDualView::init( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, const QgsAttributeEditorContext &context, bool loadFeatures ) { if ( !layer ) return; mLayer = layer; mEditorContext = context; connect( mTableView, &QgsAttributeTableView::willShowContextMenu, this, &QgsDualView::viewWillShowContextMenu ); mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu ); connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &QgsDualView::showViewHeaderMenu ); connect( mTableView, &QgsAttributeTableView::columnResized, this, &QgsDualView::tableColumnResized ); connect( mFeatureList, &QgsFeatureListView::willShowContextMenu, this, &QgsDualView::widgetWillShowContextMenu ); initLayerCache( !( request.flags() & QgsFeatureRequest::NoGeometry ) || !request.filterRect().isNull() ); initModels( mapCanvas, request, loadFeatures ); mConditionalFormatWidget->setLayer( mLayer ); mTableView->setModel( mFilterModel ); mFeatureList->setModel( mFeatureListModel ); delete mAttributeForm; mAttributeForm = new QgsAttributeForm( mLayer, mTempAttributeFormFeature, mEditorContext ); mTempAttributeFormFeature = QgsFeature(); if ( !context.parentContext() ) { mAttributeEditorScrollArea = new QgsScrollArea(); mAttributeEditorScrollArea->setWidgetResizable( true ); mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea ); mAttributeEditorScrollArea->setWidget( mAttributeForm ); } else { mAttributeEditor->layout()->addWidget( mAttributeForm ); } connect( mAttributeForm, &QgsAttributeForm::widgetValueChanged, this, &QgsDualView::featureFormAttributeChanged ); connect( mAttributeForm, &QgsAttributeForm::modeChanged, this, &QgsDualView::formModeChanged ); connect( mMasterModel, &QgsAttributeTableModel::modelChanged, mAttributeForm, &QgsAttributeForm::refreshFeature ); connect( mAttributeForm, &QgsAttributeForm::filterExpressionSet, this, &QgsDualView::filterExpressionSet ); connect( mFilterModel, &QgsAttributeTableFilterModel::sortColumnChanged, this, &QgsDualView::onSortColumnChanged ); if ( mFeatureListPreviewButton->defaultAction() ) mFeatureList->setDisplayExpression( mDisplayExpression ); else columnBoxInit(); // This slows down load of the attribute table heaps and uses loads of memory. //mTableView->resizeColumnsToContents(); mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) ); }
QgsGrassFeatureIterator::QgsGrassFeatureIterator( QgsGrassFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsGrassFeatureSource>( source, ownSource, request ) , mCanceled( false ) , mNextCidx( 0 ) , mNextLid( 1 ) { QgsDebugMsg( "entered" ); // WARNING: the iterater cannot use mutex lock for its whole life, because QgsVectorLayerFeatureIterator is opening // multiple iterators if features are edited -> lock only critical sections // Create selection int size = 1 + qMax( Vect_get_num_lines( mSource->map() ), Vect_get_num_areas( mSource->map() ) ); QgsDebugMsg( QString( "mSelection.resize(%1)" ).arg( size ) ); mSelection.resize( size ); if ( !request.filterRect().isNull() ) { setSelectionRect( request.filterRect(), request.flags() & QgsFeatureRequest::ExactIntersect ); } else { //no filter - use all features mSelection.fill( true ); } connect( mSource->mLayer->map(), SIGNAL( cancelIterators() ), this, SLOT( cancel() ), Qt::DirectConnection ); Qt::ConnectionType connectionType = Qt::DirectConnection; if ( mSource->mLayer->map()->thread() != thread() ) { // Using BlockingQueuedConnection may be dangerous, if the iterator was later moved to maps thread, it would cause dead lock on emit closeIterators() QgsDebugMsg( "map and iterator are on different threads -> connect closeIterators() with BlockingQueuedConnection" ); connectionType = Qt::BlockingQueuedConnection; } connect( mSource->mLayer->map(), SIGNAL( closeIterators() ), this, SLOT( doClose() ), connectionType ); }
void QgsMssqlFeatureIterator::BuildStatement( const QgsFeatureRequest& request ) { // build sql statement mStatement = QString( "select " ); int fieldCount = 0; mFidCol = -1; mGeometryCol = -1; if ( !request.subsetOfAttributes().empty() ) { // subset of attributes has been specified for ( QgsAttributeList::const_iterator it = request.subsetOfAttributes().begin(); it != request.subsetOfAttributes().end(); ++it ) { if ( fieldCount != 0 ) mStatement += ","; mStatement += "[" + mSource->mFields[*it].name() + "]"; if ( !mSource->mFidColName.isEmpty() && mSource->mFidColName == mSource->mFields[*it].name() ) mFidCol = fieldCount; ++fieldCount; mAttributesToFetch.append( *it ); } } else { // get all attributes for ( int i = 0; i < mSource->mFields.count(); i++ ) { if ( fieldCount != 0 ) mStatement += ","; mStatement += "[" + mSource->mFields[i].name() + "]"; if ( !mSource->mFidColName.isEmpty() && mSource->mFidColName == mSource->mFields[i].name() ) mFidCol = fieldCount; ++fieldCount; mAttributesToFetch.append( i ); } } // get fid col if not yet required if ( mFidCol == -1 && !mSource->mFidColName.isEmpty() ) { if ( fieldCount != 0 ) mStatement += ","; mStatement += "[" + mSource->mFidColName + "]"; mFidCol = fieldCount; ++fieldCount; } // get geometry col if ( !( request.flags() & QgsFeatureRequest::NoGeometry ) && !mSource->mGeometryColName.isEmpty() ) { if ( fieldCount != 0 ) mStatement += ","; mStatement += "[" + mSource->mGeometryColName + "]"; mGeometryCol = fieldCount; ++fieldCount; } mStatement += " from "; if ( !mSource->mSchemaName.isEmpty() ) mStatement += "[" + mSource->mSchemaName + "]."; mStatement += "[" + mSource->mTableName + "]"; bool filterAdded = false; // set spatial filter if ( request.filterType() & QgsFeatureRequest::FilterRect ) { // polygons should be CCW for SqlGeography QString r; QTextStream foo( &r ); foo.setRealNumberPrecision( 8 ); foo.setRealNumberNotation( QTextStream::FixedNotation ); foo << request.filterRect().xMinimum() << " " << request.filterRect().yMinimum() << ", " << request.filterRect().xMaximum() << " " << request.filterRect().yMinimum() << ", " << request.filterRect().xMaximum() << " " << request.filterRect().yMaximum() << ", " << request.filterRect().xMinimum() << " " << request.filterRect().yMaximum() << ", " << request.filterRect().xMinimum() << " " << request.filterRect().yMinimum(); mStatement += QString( " where [%1].STIntersects([%2]::STGeomFromText('POLYGON((%3))',%4)) = 1" ).arg( mSource->mGeometryColName, mSource->mGeometryColType, r, QString::number( mSource->mSRId ) ); filterAdded = true; } // set fid filter if (( request.filterType() & QgsFeatureRequest::FilterFid ) && !mSource->mFidColName.isEmpty() ) { // set attribute filter if ( !filterAdded ) mStatement += QString( " where [%1] = %2" ).arg( mSource->mFidColName, QString::number( request.filterFid() ) ); else mStatement += QString( " and [%1] = %2" ).arg( mSource->mFidColName, QString::number( request.filterFid() ) ); filterAdded = true; } if ( !mSource->mSqlWhereClause.isEmpty() ) { if ( !filterAdded ) mStatement += " where (" + mSource->mSqlWhereClause + ")"; else mStatement += " and (" + mSource->mSqlWhereClause + ")"; } if ( fieldCount == 0 ) { QgsDebugMsg( "QgsMssqlProvider::select no fields have been requested" ); mStatement.clear(); } }
void QgsDualView::setFilterMode( QgsAttributeTableFilterModel::FilterMode filterMode ) { // cleanup any existing connections switch ( mFilterModel->filterMode() ) { case QgsAttributeTableFilterModel::ShowVisible: disconnect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged ); break; case QgsAttributeTableFilterModel::ShowAll: case QgsAttributeTableFilterModel::ShowEdited: case QgsAttributeTableFilterModel::ShowFilteredList: break; case QgsAttributeTableFilterModel::ShowSelected: disconnect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures ); break; } QgsFeatureRequest r = mMasterModel->request(); bool needsGeometry = filterMode == QgsAttributeTableFilterModel::ShowVisible; bool requiresTableReload = ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) // previous request was subset || ( needsGeometry && r.flags() & QgsFeatureRequest::NoGeometry ) // no geometry for last request || ( mMasterModel->rowCount() == 0 ); // no features if ( !needsGeometry ) r.setFlags( r.flags() | QgsFeatureRequest::NoGeometry ); else r.setFlags( r.flags() & ~( QgsFeatureRequest::NoGeometry ) ); r.setFilterFids( QgsFeatureIds() ); r.setFilterRect( QgsRectangle() ); r.disableFilter(); // setup new connections and filter request parameters switch ( filterMode ) { case QgsAttributeTableFilterModel::ShowVisible: connect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged ); if ( mFilterModel->mapCanvas() ) { QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() ); r.setFilterRect( rect ); } break; case QgsAttributeTableFilterModel::ShowAll: case QgsAttributeTableFilterModel::ShowEdited: case QgsAttributeTableFilterModel::ShowFilteredList: break; case QgsAttributeTableFilterModel::ShowSelected: connect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures ); r.setFilterFids( masterModel()->layer()->selectedFeatureIds() ); break; } if ( requiresTableReload ) { mMasterModel->setRequest( r ); whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry ); mMasterModel->loadLayer(); } //update filter model mFilterModel->setFilterMode( filterMode ); emit filterChanged(); }
void QgsMssqlFeatureIterator::BuildStatement( const QgsFeatureRequest& request ) { // build sql statement mStatement = QString( "SELECT " ); mStatement += QString( "[%1]" ).arg( mSource->mFidColName ); mFidCol = mSource->mFields.indexFromName( mSource->mFidColName ); mAttributesToFetch.append( mFidCol ); bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; foreach ( int i, subsetOfAttributes ? mRequest.subsetOfAttributes() : mSource->mFields.allAttributesList() ) { QString fieldname = mSource->mFields[i].name(); if ( mSource->mFidColName == fieldname ) continue; mStatement += QString( ",[%1]" ).arg( fieldname ); mAttributesToFetch.append( i ); } // get geometry col if ( !( request.flags() & QgsFeatureRequest::NoGeometry ) && mSource->isSpatial() ) { mStatement += QString( ",[%1]" ).arg( mSource->mGeometryColName ); } mStatement += QString( "FROM [%1].[%2]" ).arg( mSource->mSchemaName, mSource->mTableName ); bool filterAdded = false; // set spatial filter if ( request.filterType() == QgsFeatureRequest::FilterRect && mSource->isSpatial() && !request.filterRect().isEmpty() ) { // polygons should be CCW for SqlGeography QString r; QTextStream foo( &r ); foo.setRealNumberPrecision( 8 ); foo.setRealNumberNotation( QTextStream::FixedNotation ); foo << qgsDoubleToString( request.filterRect().xMinimum() ) << " " << qgsDoubleToString( request.filterRect().yMinimum() ) << ", " << qgsDoubleToString( request.filterRect().xMaximum() ) << " " << qgsDoubleToString( request.filterRect().yMinimum() ) << ", " << qgsDoubleToString( request.filterRect().xMaximum() ) << " " << qgsDoubleToString( request.filterRect().yMaximum() ) << ", " << qgsDoubleToString( request.filterRect().xMinimum() ) << " " << qgsDoubleToString( request.filterRect().yMaximum() ) << ", " << qgsDoubleToString( request.filterRect().xMinimum() ) << " " << qgsDoubleToString( request.filterRect().yMinimum() ); mStatement += QString( " where [%1].STIntersects([%2]::STGeomFromText('POLYGON((%3))',%4)) = 1" ).arg( mSource->mGeometryColName, mSource->mGeometryColType, r, QString::number( mSource->mSRId ) ); filterAdded = true; } // set fid filter if ( request.filterType() == QgsFeatureRequest::FilterFid && !mSource->mFidColName.isEmpty() ) { QString fidfilter = QString( " [%1] = %2" ).arg( mSource->mFidColName, QString::number( request.filterFid() ) ); // set attribute filter if ( !filterAdded ) mStatement += " WHERE "; else mStatement += " AND "; mStatement += fidfilter; filterAdded = true; } if ( !mSource->mSqlWhereClause.isEmpty() ) { if ( !filterAdded ) mStatement += " WHERE (" + mSource->mSqlWhereClause + ")"; else mStatement += " AND (" + mSource->mSqlWhereClause + ")"; } QgsDebugMsg( mStatement ); #if 0 if ( fieldCount == 0 ) { QgsDebugMsg( "QgsMssqlProvider::select no fields have been requested" ); mStatement.clear(); } #endif }
QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request ) : QgsAbstractFeatureIteratorFromSource<QgsVirtualLayerFeatureSource>( source, ownSource, request ) { // NOTE: this is really bad and should be removed. // it's only here to guard mSource->mSqlite - because if the provider is removed // then mSqlite will be meaningless. // this needs to be totally reworked so that mSqlite no longer depends on the provider // and can be fully encapsulated in the source if ( !mSource->mProvider ) { close(); return; } if ( mRequest.destinationCrs().isValid() && mRequest.destinationCrs() != mSource->mCrs ) { mTransform = QgsCoordinateTransform( mSource->mCrs, mRequest.destinationCrs(), mRequest.transformContext() ); } try { mFilterRect = filterRectToSourceCrs( mTransform ); } catch ( QgsCsException & ) { // can't reproject mFilterRect close(); return; } try { QString tableName = mSource->mTableName; QStringList wheres; QString offset; QString subset = mSource->mSubset; if ( !subset.isEmpty() ) { wheres << subset; } if ( !mSource->mDefinition.uid().isNull() ) { // filters are only available when a column with unique id exists if ( mSource->mDefinition.hasDefinedGeometry() && !mFilterRect.isNull() ) { bool do_exact = request.flags() & QgsFeatureRequest::ExactIntersect; QString mbr = QStringLiteral( "%1,%2,%3,%4" ).arg( mFilterRect.xMinimum() ).arg( mFilterRect.yMinimum() ).arg( mFilterRect.xMaximum() ).arg( mFilterRect.yMaximum() ); wheres << quotedColumn( mSource->mDefinition.geometryField() ) + " is not null"; wheres << QStringLiteral( "%1Intersects(%2,BuildMbr(%3))" ) .arg( do_exact ? "" : "Mbr", quotedColumn( mSource->mDefinition.geometryField() ), mbr ); } else if ( request.filterType() == QgsFeatureRequest::FilterFid ) { wheres << QStringLiteral( "%1=%2" ) .arg( quotedColumn( mSource->mDefinition.uid() ) ) .arg( request.filterFid() ); } else if ( request.filterType() == QgsFeatureRequest::FilterFids ) { QString values = quotedColumn( mSource->mDefinition.uid() ) + " IN ("; bool first = true; const auto constFilterFids = request.filterFids(); for ( QgsFeatureId v : constFilterFids ) { if ( !first ) { values += QLatin1String( "," ); } first = false; values += QString::number( v ); } values += QLatin1String( ")" ); wheres << values; } } else { if ( request.filterType() == QgsFeatureRequest::FilterFid ) { if ( request.filterFid() >= 0 ) offset = QStringLiteral( " LIMIT 1 OFFSET %1" ).arg( request.filterFid() ); else // never return a feature if the id is negative offset = QStringLiteral( " LIMIT 0" ); } else if ( !mFilterRect.isNull() && mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // if an exact intersection is requested, prepare the geometry to intersect QgsGeometry rectGeom = QgsGeometry::fromRect( mFilterRect ); mRectEngine.reset( QgsGeometry::createGeometryEngine( rectGeom.constGet() ) ); mRectEngine->prepareGeometry(); } } if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes ) { // copy only selected fields const auto subsetOfAttributes = request.subsetOfAttributes(); for ( int idx : subsetOfAttributes ) { mAttributes << idx; } // ensure that all attributes required for expression filter are being fetched if ( request.filterType() == QgsFeatureRequest::FilterExpression ) { const auto constReferencedColumns = request.filterExpression()->referencedColumns(); for ( const QString &field : constReferencedColumns ) { int attrIdx = mSource->mFields.lookupField( field ); if ( !mAttributes.contains( attrIdx ) ) mAttributes << attrIdx; } } // also need attributes required by order by if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() ) { const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields ); for ( int attrIdx : usedAttributeIndices ) { if ( !mAttributes.contains( attrIdx ) ) mAttributes << attrIdx; } } } else { mAttributes = mSource->mFields.allAttributesList(); } QString columns; { // the first column is always the uid (or 0) if ( !mSource->mDefinition.uid().isNull() ) { columns = quotedColumn( mSource->mDefinition.uid() ); } else { if ( request.filterType() == QgsFeatureRequest::FilterFid ) { columns = QString::number( request.filterFid() ); } else { columns = QStringLiteral( "0" ); } } const auto constMAttributes = mAttributes; for ( int i : constMAttributes ) { columns += QLatin1String( "," ); QString cname = mSource->mFields.at( i ).name().toLower(); columns += quotedColumn( cname ); } } // the last column is the geometry, if any if ( ( !( request.flags() & QgsFeatureRequest::NoGeometry ) || ( request.filterType() == QgsFeatureRequest::FilterExpression && request.filterExpression()->needsGeometry() ) ) && !mSource->mDefinition.geometryField().isNull() && mSource->mDefinition.geometryField() != QLatin1String( "*no*" ) ) { columns += "," + quotedColumn( mSource->mDefinition.geometryField() ); } mSqlQuery = "SELECT " + columns + " FROM " + tableName; if ( !wheres.isEmpty() ) { mSqlQuery += " WHERE " + wheres.join( QStringLiteral( " AND " ) ); } if ( !offset.isEmpty() ) { mSqlQuery += offset; } mQuery.reset( new Sqlite::Query( mSource->mSqlite, mSqlQuery ) ); mFid = 0; } catch ( std::runtime_error &e ) { QgsMessageLog::logMessage( e.what(), QObject::tr( "VLayer" ) ); close(); } }